Merge branch 'qemu-vendor-drops' (qemu as of 2007-10-01)

Conflicts:

	kernel/Kbuild
	kernel/Makefile
	qemu/.cvsignore
	qemu/Changelog
	qemu/Makefile
	qemu/Makefile.target
	qemu/arm-semi.c
	qemu/audio/audio.c
	qemu/audio/audio_template.h
	qemu/audio/coreaudio.c
	qemu/audio/wavaudio.c
	qemu/audio/wavcapture.c
	qemu/block-bochs.c
	qemu/block-cow.c
	qemu/block-qcow.c
	qemu/block-qcow2.c
	qemu/block-raw.c
	qemu/block-vmdk.c
	qemu/block-vpc.c
	qemu/block-vvfat.c
	qemu/block.c
	qemu/block_int.h
	qemu/configure
	qemu/console.c
	qemu/cpu-all.h
	qemu/cpu-defs.h
	qemu/cpu-exec.c
	qemu/cutils.c
	qemu/darwin-user/main.c
	qemu/darwin-user/mmap.c
	qemu/darwin-user/syscall.c
	qemu/darwin-user/syscalls.h
	qemu/dyngen-exec.h
	qemu/dyngen.c
	qemu/dyngen.h
	qemu/elf.h
	qemu/exec-all.h
	qemu/exec.c
	qemu/fpu/softfloat-native.c
	qemu/fpu/softfloat.h
	qemu/gdbstub.c
	qemu/gdbstub.h
	qemu/hw/acpi.c
	qemu/hw/apb_pci.c
	qemu/hw/apic.c
	qemu/hw/arm_boot.c
	qemu/hw/arm_gic.c
	qemu/hw/arm_sysctl.c
	qemu/hw/arm_timer.c
	qemu/hw/cdrom.c
	qemu/hw/cirrus_vga.c
	qemu/hw/cs4231.c
	qemu/hw/cuda.c
	qemu/hw/esp.c
	qemu/hw/fdc.c
	qemu/hw/grackle_pci.c
	qemu/hw/gt64xxx.c
	qemu/hw/i8254.c
	qemu/hw/i8259.c
	qemu/hw/ide.c
	qemu/hw/integratorcp.c
	qemu/hw/iommu.c
	qemu/hw/isa_mmio.c
	qemu/hw/lsi53c895a.c
	qemu/hw/m48t59.c
	qemu/hw/mc146818rtc.c
	qemu/hw/mips_int.c
	qemu/hw/mips_malta.c
	qemu/hw/mips_r4k.c
	qemu/hw/mips_timer.c
	qemu/hw/ne2000.c
	qemu/hw/pc.c
	qemu/hw/pci.c
	qemu/hw/pci_host.h
	qemu/hw/pcnet.c
	qemu/hw/pflash_cfi02.c
	qemu/hw/piix_pci.c
	qemu/hw/pl011.c
	qemu/hw/pl050.c
	qemu/hw/pl080.c
	qemu/hw/ppc.c
	qemu/hw/ppc_chrp.c
	qemu/hw/ppc_prep.c
	qemu/hw/prep_pci.c
	qemu/hw/realview.c
	qemu/hw/rtl8139.c
	qemu/hw/scsi-disk.c
	qemu/hw/sh7750.c
	qemu/hw/slavio_serial.c
	qemu/hw/slavio_timer.c
	qemu/hw/smbus.h
	qemu/hw/smbus_eeprom.c
	qemu/hw/sparc32_dma.c
	qemu/hw/sun4m.c
	qemu/hw/sun4u.c
	qemu/hw/tcx.c
	qemu/hw/unin_pci.c
	qemu/hw/usb-hid.c
	qemu/hw/usb-hub.c
	qemu/hw/usb-msd.c
	qemu/hw/usb-ohci.c
	qemu/hw/usb-uhci.c
	qemu/hw/usb.h
	qemu/hw/versatile_pci.c
	qemu/hw/versatilepb.c
	qemu/hw/vga.c
	qemu/hw/vga_int.h
	qemu/hw/vga_template.h
	qemu/kqemu.c
	qemu/linux-user/arm/syscall_nr.h
	qemu/linux-user/elfload.c
	qemu/linux-user/flat.h
	qemu/linux-user/flatload.c
	qemu/linux-user/linuxload.c
	qemu/linux-user/m68k-sim.c
	qemu/linux-user/m68k/syscall_nr.h
	qemu/linux-user/m68k/termbits.h
	qemu/linux-user/main.c
	qemu/linux-user/mmap.c
	qemu/linux-user/qemu.h
	qemu/linux-user/signal.c
	qemu/linux-user/syscall.c
	qemu/linux-user/syscall_defs.h
	qemu/monitor.c
	qemu/osdep.c
	qemu/osdep.h
	qemu/pc-bios/README
	qemu/pc-bios/bios.bin
	qemu/pc-bios/bios.diff
	qemu/pc-bios/openbios-sparc32
	qemu/pc-bios/vgabios-cirrus.bin
	qemu/pc-bios/vgabios.bin
	qemu/ppc.ld
	qemu/qemu-doc.texi
	qemu/qemu-img.c
	qemu/sdl.c
	qemu/slirp/tcp_subr.c
	qemu/slirp/udp.c
	qemu/target-arm/cpu.h
	qemu/target-arm/helper.c
	qemu/target-arm/translate.c
	qemu/target-i386/cpu.h
	qemu/target-i386/exec.h
	qemu/target-i386/helper.c
	qemu/target-i386/helper2.c
	qemu/target-i386/translate.c
	qemu/target-m68k/cpu.h
	qemu/target-m68k/exec.h
	qemu/target-m68k/helper.c
	qemu/target-m68k/op-hacks.h
	qemu/target-m68k/op.c
	qemu/target-m68k/qregs.def
	qemu/target-m68k/translate.c
	qemu/target-mips/TODO
	qemu/target-mips/cpu.h
	qemu/target-mips/exec.h
	qemu/target-mips/fop_template.c
	qemu/target-mips/helper.c
	qemu/target-mips/mips-defs.h
	qemu/target-mips/op.c
	qemu/target-mips/op_helper.c
	qemu/target-mips/op_helper_mem.c
	qemu/target-mips/op_mem.c
	qemu/target-mips/op_template.c
	qemu/target-mips/translate.c
	qemu/target-ppc/cpu.h
	qemu/target-ppc/helper.c
	qemu/target-ppc/op.c
	qemu/target-ppc/translate.c
	qemu/target-ppc/translate_init.c
	qemu/target-sh4/cpu.h
	qemu/target-sh4/helper.c
	qemu/target-sh4/op.c
	qemu/target-sh4/translate.c
	qemu/target-sparc/cpu.h
	qemu/target-sparc/exec.h
	qemu/target-sparc/helper.c
	qemu/target-sparc/op.c
	qemu/target-sparc/op_helper.c
	qemu/target-sparc/translate.c
	qemu/tests/Makefile
	qemu/usb-linux.c
	qemu/vl.c
	qemu/vl.h
	qemu/vnc.c
	qemu/vnchextile.h
	user/Makefile
diff --git a/.cvsignore b/.cvsignore
index 7be41c4..ffbf37d 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -8,7 +8,11 @@
 i386-user
 ppc-softmmu
 ppc64-softmmu
-ppc-user
+ppcemb-softmmu
+ppc-darwin-user
+ppc-linux-user
+ppc64-linux-user
+ppcemb-linux-user
 qemu-doc.html
 qemu-tech.html
 qemu-doc.info
@@ -21,15 +25,26 @@
 qemu-img
 sparc-softmmu
 x86_64-softmmu
-sparc64-user
+x86_64-linux-user
+sparc64-linux-user
 sparc64-softmmu
 mips-softmmu
 mipsel-softmmu
-mips-user
-mipsel-user
+mips-linux-user
+mipsel-linux-user
+mips64-softmmu
+mips64el-softmmu
+mipsn32-linux-user
+mipsn32el-linux-user
+mips64-linux-user
+mips64el-linux-user
+m68k-linux-user
+m68k-softmmu
 .gdbinit
 sh4-user
 sh4-softmmu
+alpha-linux-user
+alpha-softmmu
 *.aux
 *.cp
 *.dvi
diff --git a/Changelog b/Changelog
index ea9ea74..f61a580 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,18 @@
+  - TFTP booting from host directory (Anthony Liguori, Erwan Velu)
+  - Tap device emulation for Solaris (Sittichai Palanisong)
+  - Monitor multiplexing to several I/O channels (Jason Wessel)
+  - ds1225y nvram support (Herve Poussineau)
+  - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
+  - Several Sparc fixes (Aurelien Jarno, Blue Swirl)
+  - MIPS 64-bit FPU support (Thiemo Seufer)
+  - Xscale PDA emulation (Andrzei Zaborowski)
+  - ColdFire system emulation (Paul Brook)
+  - Improved SH4 support (Magnus Damm)
+  - MIPS64 support (Aurelien Jarno, Thiemo Seufer)
+  - Preliminary Alpha guest support (J. Mayer)
+  - Read-only support for Parallels disk images (Alex Beregszaszi)
+  - SVM (x86 virtualization) support (Alexander Graf)
+
 version 0.9.0:
 
   - Support for relative paths in backing files for disk images
@@ -23,7 +38,7 @@
   - switch to OpenBios for SPARC targets (Blue Swirl)
   - VNC server fixes
   - MIPS FPU support (Marius Groeger)
-  - Solaris/SPARC host support (Ben Taylor)
+  - Solaris/SPARC host support (Juergen Keil)
   - PPC breakpoints and single stepping (Jason Wessel)
   - USB updates (Paul Brook)
   - UDP/TCP/telnet character devices (Jason Wessel)
@@ -42,7 +57,7 @@
   - PC speaker support (Joachim Henke)
   - IDE LBA48 support (Jens Axboe)
   - SSE3 support
-  - Solaris port (Ben Taylor)
+  - Solaris port (Juergen Keil)
   - Preliminary SH4 target (Samuel Tardieu)
   - VNC server (Anthony Liguori)
   - slirp fixes (Ed Swierk et al.)
@@ -72,7 +87,7 @@
     (Johannes Schindelin)
 
 version 0.7.2:
-  
+
   - x86_64 fixes (Win2000 and Linux 2.6 boot in 32 bit)
   - merge self modifying code handling in dirty ram page mecanism.
   - MIPS fixes (Ralf Baechle)
@@ -121,7 +136,7 @@
   - Mac OS X port (Pierre d'Herbemont)
   - Virtual console support
   - Better monitor line edition
-  - New block device layer 
+  - New block device layer
   - New 'qcow' growable disk image support with AES encryption and
     transparent decompression
   - VMware 3 and 4 read-only disk image support (untested)
@@ -187,7 +202,7 @@
   - FDC fixes for Win98
 
 version 0.5.4:
-  
+
   - qemu-fast fixes
   - BIOS area protection fix (aka EMM386.EXE fix) (Mike Nordell)
   - keyboard/mouse fix (Mike Nordell)
@@ -214,7 +229,7 @@
   - added accurate CR0.MP/ME/TS emulation
   - fixed DMA memory write access (Win95 boot floppy fix)
   - graphical x86 linux loader
-  - command line monitor 
+  - command line monitor
   - generic removable device support
   - support of CD-ROM change
   - multiple network interface support
@@ -252,7 +267,7 @@
   - eflags optimisation fix for string operations
 
 version 0.5.1:
-  
+
   - float access fixes when using soft mmu
   - PC emulation support on PowerPC
   - A20 support
@@ -267,7 +282,7 @@
   - Major SPARC target fixes (dynamically linked programs begin to work)
 
 version 0.5.0:
-  
+
   - full hardware level VGA emulation
   - graphical display with SDL
   - added PS/2 mouse and keyboard emulation
@@ -305,7 +320,7 @@
  - SMP kernels can at least be booted
 
 version 0.4.1:
-  
+
  - more accurate timer support in vl.
  - more reliable NE2000 probe in vl.
  - added 2.5.66 kernel in vl-test.
@@ -391,7 +406,7 @@
  - added bound, cmpxchg8b, cpuid instructions
  - added 16 bit addressing support/override for string operations
  - poll() fix
- 
+
 version 0.1.2:
 
  - compile fixes
diff --git a/Makefile b/Makefile
index 573c42e..053c88c 100644
--- a/Makefile
+++ b/Makefile
@@ -8,13 +8,11 @@
 BASE_CFLAGS=
 BASE_LDFLAGS=
 
-BASE_CFLAGS += $(OS_CFLAGS)
-ifeq ($(ARCH),sparc)
-BASE_CFLAGS += -mcpu=ultrasparc
-endif
+BASE_CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS)
+BASE_LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS)
+
 CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
 LIBS=
-TOOLS=qemu-img$(EXESUF)
 ifdef CONFIG_STATIC
 BASE_LDFLAGS += -static
 endif
@@ -24,13 +22,7 @@
 DOCS=
 endif
 
-ifndef CONFIG_DARWIN
-ifndef CONFIG_WIN32
-ifndef CONFIG_SOLARIS
-LIBS+=-lrt
-endif
-endif
-endif
+LIBS+=$(AIOLIBS)
 
 all: $(TOOLS) $(DOCS) recurse-all
 
@@ -39,7 +31,7 @@
 
 recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
 
-qemu-img$(EXESUF): qemu-img.c cutils.c block.c block-raw.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c block-qcow2.c
+qemu-img$(EXESUF): qemu-img.c cutils.c block.c block-raw.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c block-qcow2.c block-parallels.c
 	$(CC) -DQEMU_TOOL $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $(LDFLAGS) $(BASE_LDFLAGS) -o $@ $^ -lz $(LIBS)
 
 dyngen$(EXESUF): dyngen.c
@@ -47,8 +39,8 @@
 
 clean:
 # avoid old build problems by removing potentially incorrect old files
-	rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h 
-	rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
+	rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
+	rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS cscope.* *.pod *~ */*~
 	$(MAKE) -C tests clean
 	for d in $(TARGET_DIRS); do \
 	$(MAKE) -C $$d $@ || exit 1 ; \
@@ -78,7 +70,7 @@
 	$(INSTALL) -m 755 $(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
@@ -96,7 +88,7 @@
 test speed test2: all
 	$(MAKE) -C tests $@
 
-TAGS: 
+TAGS:
 	etags *.[ch] tests/*.[ch]
 
 cscope:
@@ -140,21 +132,35 @@
 
 # generate a binary distribution
 tarbin:
-	( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
+	( cd / ; tar zcvf ~/qemu-$(VERSION)-$(ARCH).tar.gz \
 	$(bindir)/qemu \
 	$(bindir)/qemu-system-ppc \
+	$(bindir)/qemu-system-ppc64 \
+	$(bindir)/qemu-system-ppcemb \
 	$(bindir)/qemu-system-sparc \
 	$(bindir)/qemu-system-x86_64 \
 	$(bindir)/qemu-system-mips \
 	$(bindir)/qemu-system-mipsel \
+	$(bindir)/qemu-system-mips64 \
+	$(bindir)/qemu-system-mips64el \
 	$(bindir)/qemu-system-arm \
+	$(bindir)/qemu-system-m68k \
+	$(bindir)/qemu-system-sh4 \
 	$(bindir)/qemu-i386 \
         $(bindir)/qemu-arm \
         $(bindir)/qemu-armeb \
         $(bindir)/qemu-sparc \
         $(bindir)/qemu-ppc \
+        $(bindir)/qemu-ppc64 \
         $(bindir)/qemu-mips \
         $(bindir)/qemu-mipsel \
+        $(bindir)/qemu-mipsn32 \
+        $(bindir)/qemu-mipsn32el \
+        $(bindir)/qemu-mips64 \
+        $(bindir)/qemu-mips64el \
+        $(bindir)/qemu-alpha \
+        $(bindir)/qemu-m68k \
+        $(bindir)/qemu-sh4 \
         $(bindir)/qemu-img \
 	$(datadir)/bios.bin \
 	$(datadir)/vgabios.bin \
@@ -162,7 +168,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 \
diff --git a/Makefile.target b/Makefile.target
index aeee2af..d60595e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -8,9 +8,18 @@
 ifeq ($(TARGET_ARCH), x86_64)
 TARGET_BASE_ARCH:=i386
 endif
+ifeq ($(TARGET_ARCH), mipsn32)
+TARGET_BASE_ARCH:=mips
+endif
+ifeq ($(TARGET_ARCH), mips64)
+TARGET_BASE_ARCH:=mips
+endif
 ifeq ($(TARGET_ARCH), ppc64)
 TARGET_BASE_ARCH:=ppc
 endif
+ifeq ($(TARGET_ARCH), ppcemb)
+TARGET_BASE_ARCH:=ppc
+endif
 ifeq ($(TARGET_ARCH), sparc64)
 TARGET_BASE_ARCH:=sparc
 endif
@@ -48,6 +57,16 @@
     TARGET_ARCH2=mipsel
   endif
 endif
+ifeq ($(TARGET_ARCH),mipsn32)
+  ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
+    TARGET_ARCH2=mipsn32el
+  endif
+endif
+ifeq ($(TARGET_ARCH),mips64)
+  ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
+    TARGET_ARCH2=mips64el
+  endif
+endif
 QEMU_USER=qemu-$(TARGET_ARCH2)
 # system emulator name
 ifdef CONFIG_SOFTMMU
@@ -74,16 +93,27 @@
 endif
 
 # We require -O2 to avoid the stack setup prologue in EXIT_TB
-OP_CFLAGS = -Wall -O2 -g -fno-strict-aliasing
+OP_CFLAGS := -Wall -O2 -g -fno-strict-aliasing
+
+# cc-option
+# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
+
+cc-option = $(shell if $(CC) $(OP_CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
+              > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+
+OP_CFLAGS+=$(call cc-option, -fno-reorder-blocks, "")
+OP_CFLAGS+=$(call cc-option, -fno-gcse, "")
+OP_CFLAGS+=$(call cc-option, -fno-tree-ch, "")
+OP_CFLAGS+=$(call cc-option, -fno-optimize-sibling-calls, "")
+OP_CFLAGS+=$(call cc-option, -fno-crossjumping, "")
+OP_CFLAGS+=$(call cc-option, -fno-align-labels, "")
+OP_CFLAGS+=$(call cc-option, -fno-align-jumps, "")
+OP_CFLAGS+=$(call cc-option, -fno-align-functions, $(call cc-option, -malign-functions=0, ""))
+OP_CFLAGS+=$(call cc-option, -fno-section-anchors, "")
 
 ifeq ($(ARCH),i386)
 HELPER_CFLAGS+=-fomit-frame-pointer
 OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer
-ifeq ($(HAVE_GCC3_OPTIONS),yes)
-OP_CFLAGS+= -falign-functions=0 -fno-gcse
-else
-OP_CFLAGS+= -malign-functions=0
-endif
 ifdef TARGET_GPROF
 USE_I386_LD=y
 endif
@@ -118,25 +148,25 @@
 endif
 
 ifeq ($(ARCH),sparc)
-ifeq ($(CONFIG_SOLARIS),yes)
-BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
-BASE_LDFLAGS+=-m32
-OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
-else
-BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
-BASE_LDFLAGS+=-m32
-OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
-HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
-# -static is used to avoid g1/g3 usage by the dynamic linker
-BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
-endif
+  BASE_CFLAGS+=-ffixed-g2 -ffixed-g3
+  OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
+  ifeq ($(CONFIG_SOLARIS),yes)
+    OP_CFLAGS+=-fno-omit-frame-pointer
+  else
+    BASE_CFLAGS+=-ffixed-g1 -ffixed-g6
+    HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
+    # -static is used to avoid g1/g3 usage by the dynamic linker
+    BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
+  endif
 endif
 
 ifeq ($(ARCH),sparc64)
-BASE_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
-BASE_LDFLAGS+=-m64
-BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
-OP_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 -fno-delayed-branch -ffixed-i0
+  BASE_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
+  OP_CFLAGS+=-mcpu=ultrasparc -m64 -fno-delayed-branch -ffixed-i0
+  ifneq ($(CONFIG_SOLARIS),yes)
+    BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+    OP_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
+  endif
 endif
 
 ifeq ($(ARCH),alpha)
@@ -164,12 +194,21 @@
 endif
 
 ifeq ($(ARCH),mips)
+OP_CFLAGS+=-mabi=32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0
+ifeq ($(WORDS_BIGENDIAN),yes)
 BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+else
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
+endif
 endif
 
-ifeq ($(HAVE_GCC3_OPTIONS),yes)
-# very important to generate a return at the end of every operation
-OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
+ifeq ($(ARCH),mips64)
+OP_CFLAGS+=-mabi=n32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0
+ifeq ($(WORDS_BIGENDIAN),yes)
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+else
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
+endif
 endif
 
 ifeq ($(CONFIG_DARWIN),yes)
@@ -181,7 +220,10 @@
 BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
 endif
 
-OP_CFLAGS+=$(OS_CFLAGS)
+BASE_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS)
+BASE_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS)
+OP_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS)
+OP_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS)
 
 #########################################################
 
@@ -195,6 +237,12 @@
 endif
 ifdef CONFIG_SOLARIS
 LIBS+=-lsocket -lnsl -lresolv
+ifdef NEEDS_LIBSUNMATH
+LIBS+=-lsunmath
+LDFLAGS+=-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib
+OP_CFLAGS+=-I/opt/SUNWspro/prod/include/cc
+BASE_CFLAGS+=-I/opt/SUNWspro/prod/include/cc
+endif
 endif
 
 # profiling code
@@ -206,6 +254,7 @@
 ifdef CONFIG_LINUX_USER
 OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
       elfload.o linuxload.o
+LIBS+= $(AIOLIBS)
 ifdef TARGET_HAS_BFLT
 OBJS+= flatload.o
 endif
@@ -232,7 +281,7 @@
 
 # cpu emulator library
 LIBOBJS=exec.o kqemu.o qemu-kvm.o translate-op.o translate-all.o cpu-exec.o\
-        translate.o op.o qemu-kvm-helper.o
+        translate.o op.o host-utils.o qemu-kvm-helper.o
 ifdef CONFIG_SOFTFLOAT
 LIBOBJS+=fpu/softfloat.o
 else
@@ -255,7 +304,7 @@
 LIBOBJS+= op_helper.o helper.o
 endif
 
-ifeq ($(TARGET_ARCH), mips)
+ifeq ($(TARGET_BASE_ARCH), mips)
 LIBOBJS+= op_helper.o helper.o
 endif
 
@@ -272,11 +321,15 @@
 endif
 
 ifeq ($(TARGET_BASE_ARCH), m68k)
-LIBOBJS+= helper.o
+LIBOBJS+= op_helper.o helper.o
+endif
+
+ifeq ($(TARGET_BASE_ARCH), alpha)
+LIBOBJS+= op_helper.o helper.o alpha_palcode.o
 endif
 
 # NOTE: the disassembler code is only needed for debugging
-LIBOBJS+=disas.o 
+LIBOBJS+=disas.o
 ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
 USE_I386_DIS=y
 endif
@@ -292,7 +345,7 @@
 ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
 LIBOBJS+=ppc-dis.o
 endif
-ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
+ifeq ($(findstring mips, $(TARGET_BASE_ARCH) $(ARCH)),mips)
 LIBOBJS+=mips-dis.o
 endif
 ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
@@ -307,6 +360,9 @@
 ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
 LIBOBJS+=sh4-dis.o
 endif
+ifeq ($(findstring s390, $(TARGET_ARCH) $(ARCH)),s390)
+LIBOBJS+=s390-dis.o
+endif
 
 ifdef CONFIG_GDBSTUB
 OBJS+=gdbstub.o
@@ -326,13 +382,14 @@
 VL_OBJS=vl.o osdep.o readline.o monitor.o pci.o console.o loader.o isa_mmio.o
 VL_OBJS+=cutils.o migration.o
 VL_OBJS+=block.o block-raw.o
-VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o
+VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o block-parallels.o
+VL_OBJS+=irq.o
 ifdef CONFIG_WIN32
 VL_OBJS+=tap-win32.o
 endif
 
 SOUND_HW = sb16.o es1370.o
-AUDIODRV = audio.o noaudio.o wavaudio.o
+AUDIODRV = audio.o noaudio.o wavaudio.o mixeng.o
 ifdef CONFIG_SDL
 AUDIODRV += sdlaudio.o
 endif
@@ -365,14 +422,28 @@
 DEPLIBS += ../user/libkvm.a
 endif
 
+ifdef CONFIG_VNC_TLS
+CPPFLAGS += $(CONFIG_VNC_TLS_CFLAGS)
+LIBS += $(CONFIG_VNC_TLS_LIBS)
+endif
+
+VL_OBJS += i2c.o smbus.o
+
 # SCSI layer
 VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
 
 # USB layer
 VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
+VL_OBJS+= usb-wacom.o
+
+# EEPROM emulation
+VL_OBJS += eeprom93xx.o
 
 # PCI network cards
-VL_OBJS+= ne2000.o rtl8139.o pcnet.o
+VL_OBJS += eepro100.o
+VL_OBJS += ne2000.o
+VL_OBJS += pcnet.o
+VL_OBJS += rtl8139.o
 
 # PCI Hypercall
 VL_OBJS+= hypercall.o
@@ -381,51 +452,63 @@
 # Hardware support
 VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
 VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
-VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o acpi.o piix_pci.o
-VL_OBJS+= usb-uhci.o smbus_eeprom.o
-CPPFLAGS += -DHAS_AUDIO
+VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
+VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o vmport.o vmware_vga.o
+CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 endif
 ifeq ($(TARGET_BASE_ARCH), ppc)
 VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
-VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
-VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
-VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
-CPPFLAGS += -DHAS_AUDIO
+VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o pflash_cfi02.o
+VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o
+VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o ppc405_uc.o ppc405_boards.o
+CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
 endif
-ifeq ($(TARGET_ARCH), mips)
-VL_OBJS+= mips_r4k.o mips_malta.o mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o
-VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o
-VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV)
-DEFINES += -DHAS_AUDIO
+ifeq ($(TARGET_BASE_ARCH), mips)
+VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o
+VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o
+VL_OBJS+= jazz_led.o
+VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
+VL_OBJS+= piix_pci.o smbus_eeprom.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV)
+CPPFLAGS += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), sparc)
 ifeq ($(TARGET_ARCH), sparc64)
 VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
 VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
-VL_OBJS+= cirrus_vga.o parallel.o
+VL_OBJS+= cirrus_vga.o parallel.o ptimer.o
 else
 VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o
 VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o
-VL_OBJS+= cs4231.o
+VL_OBJS+= cs4231.o ptimer.o
 endif
 endif
 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 pl190.o
-VL_OBJS+= versatile_pci.o
+VL_OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.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
+VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o
+VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o
+VL_OBJS+= omap.o omap_lcdc.o omap1_clk.o omap_mmc.o palm.o ecc.o
+CPPFLAGS += -DHAS_AUDIO
 endif
 ifeq ($(TARGET_BASE_ARCH), sh4)
-VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
+VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
+VL_OBJS+= sh_timer.o ptimer.o sh_serial.o
+endif
+ifeq ($(TARGET_BASE_ARCH), m68k)
+VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
+VL_OBJS+= m68k-semi.o
 endif
 ifdef CONFIG_GDBSTUB
-VL_OBJS+=gdbstub.o 
+VL_OBJS+=gdbstub.o
 endif
 ifdef CONFIG_SDL
 VL_OBJS+=sdl.o x_keymap.o
 endif
-VL_OBJS+=vnc.o
+VL_OBJS+=vnc.o d3des.o
 ifdef CONFIG_COCOA
 VL_OBJS+=cocoa.o
 COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
@@ -441,18 +524,19 @@
 VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
 endif
 
-VL_LDFLAGS=$(LDFLAGS_BASE)
+VL_LDFLAGS=$(VL_OS_LDFLAGS)
+VL_LIBS=$(AIOLIBS)
 # specific flags are needed for non soft mmu emulator
 ifdef CONFIG_STATIC
 VL_LDFLAGS+=-static
 endif
 ifndef CONFIG_SOFTMMU
-VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld 
+VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
 endif
 ifndef CONFIG_DARWIN
 ifndef CONFIG_WIN32
 ifndef CONFIG_SOLARIS
-VL_LIBS=-lutil -lrt
+VL_LIBS+=-lutil
 endif
 endif
 endif
@@ -466,8 +550,10 @@
 endif
 
 ifeq ($(ARCH),sparc64)
-VL_LDFLAGS+=-m64
-VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
+  VL_LDFLAGS+=-m64
+  ifneq ($(CONFIG_SOLARIS),yes)
+    VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+  endif
 endif
 
 ifdef CONFIG_WIN32
@@ -475,7 +561,7 @@
 endif
 
 $(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(DEPLIBS)
-	$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
+	$(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
 
 cocoa.o: cocoa.m
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
@@ -483,7 +569,7 @@
 sdl.o: sdl.c keymaps.c sdl_keysym.h
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(SDL_CFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
-vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
+vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h d3des.c d3des.h
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
 sdlaudio.o: sdlaudio.c
@@ -495,7 +581,7 @@
 vldepend: $(VL_OBJS:.o=.c)
 	$(CC) -MM $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) $^ 1>.depend
 
-# libqemu 
+# libqemu
 
 libqemu.a: $(LIBOBJS)
 	rm -f $@
@@ -543,6 +629,10 @@
 signal.o: signal.c
 	$(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
 
+vga.o: pixel_ops.h
+
+tcx.o: pixel_ops.h
+
 ifeq ($(TARGET_BASE_ARCH), i386)
 op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h
 endif
@@ -553,19 +643,23 @@
 endif
 
 ifeq ($(TARGET_BASE_ARCH), sparc)
-op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h
-magic_load.o: elf_op.h
+helper.o: cpu.h exec-all.h
+op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h exec.h cpu.h
+op_helper.o: exec.h softmmu_template.h cpu.h
+translate.o: cpu.h exec-all.h disas.h
 endif
 
 ifeq ($(TARGET_BASE_ARCH), ppc)
-op.o: op.c op_template.h op_mem.h
-op_helper.o: op_helper_mem.h
+op.o: op.c op_template.h op_mem.h op_helper.h
+op_helper.o: op_helper.c mfrom_table.c op_helper_mem.h op_helper.h
 translate.o: translate.c translate_init.c
 endif
 
-ifeq ($(TARGET_ARCH), mips)
-op.o: op.c op_template.c fop_template.c op_mem.c
-op_helper.o: op_helper_mem.c
+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 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
 
 loader.o: loader.c elf_ops.h
@@ -580,6 +674,11 @@
 tc58128.o: tc58128.c
 endif
 
+ifeq ($(TARGET_BASE_ARCH), alpha)
+op.o: op.c op_template.h op_mem.h
+op_helper.o: op_helper_mem.h
+endif
+
 $(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
 
 %.o: %.c
@@ -591,7 +690,7 @@
 clean:
 	rm -f *.o  *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
 
-install: all 
+install: all
 ifneq ($(PROGS),)
 	$(INSTALL) -m 755 $(PROGS) "$(DESTDIR)$(bindir)"
 endif
diff --git a/TODO b/TODO
index 516ea87..178a071 100644
--- a/TODO
+++ b/TODO
@@ -16,7 +16,7 @@
 - do not resize vga if invalid size.
 - avoid looping if only exceptions
 - TLB code protection support for PPC
-- see openMosix Doc 
+- see openMosix Doc
 - disable SMC handling for ARM/SPARC/PPC (not finished)
 - see undefined flags for BTx insn
 - user/kernel PUSHL/POPL in helper.c
diff --git a/a.out.h b/a.out.h
index 1f978c1..2d35ebf 100644
--- a/a.out.h
+++ b/a.out.h
@@ -25,9 +25,9 @@
 struct external_filehdr {
   short f_magic;	/* magic number			*/
   short f_nscns;	/* number of sections		*/
-  unsigned long f_timdat;	/* time & date stamp		*/
-  unsigned long f_symptr;	/* file pointer to symtab	*/
-  unsigned long f_nsyms;	/* number of symtab entries	*/
+  host_ulong f_timdat;	/* time & date stamp		*/
+  host_ulong f_symptr;	/* file pointer to symtab	*/
+  host_ulong f_nsyms;	/* number of symtab entries	*/
   short f_opthdr;	/* sizeof(optional hdr)		*/
   short f_flags;	/* flags			*/
 };
@@ -72,12 +72,12 @@
 {
   unsigned short magic;		/* type of file				*/
   unsigned short vstamp;	/* version stamp			*/
-  unsigned long	tsize;		/* text size in bytes, padded to FW bdry*/
-  unsigned long	dsize;		/* initialized data "  "		*/
-  unsigned long	bsize;		/* uninitialized data "   "		*/
-  unsigned long	entry;		/* entry pt.				*/
-  unsigned long text_start;	/* base of text used for this file */
-  unsigned long data_start;	/* base of data used for this file=
+  host_ulong	tsize;		/* text size in bytes, padded to FW bdry*/
+  host_ulong	dsize;		/* initialized data "  "		*/
+  host_ulong	bsize;		/* uninitialized data "   "		*/
+  host_ulong	entry;		/* entry pt.				*/
+  host_ulong text_start;	/* base of text used for this file */
+  host_ulong data_start;	/* base of data used for this file=
  */
 }
 AOUTHDR;
@@ -103,16 +103,16 @@
 
 struct external_scnhdr {
   char		s_name[8];	/* section name			*/
-  unsigned long	s_paddr;	/* physical address, offset
+  host_ulong	s_paddr;	/* physical address, offset
 				   of last addr in scn */
-  unsigned long	s_vaddr;	/* virtual address		*/
-  unsigned long	s_size;		/* section size			*/
-  unsigned long	s_scnptr;	/* file ptr to raw data for section */
-  unsigned long	s_relptr;	/* file ptr to relocation	*/
-  unsigned long	s_lnnoptr;	/* file ptr to line numbers	*/
+  host_ulong	s_vaddr;	/* virtual address		*/
+  host_ulong	s_size;		/* section size			*/
+  host_ulong	s_scnptr;	/* file ptr to raw data for section */
+  host_ulong	s_relptr;	/* file ptr to relocation	*/
+  host_ulong	s_lnnoptr;	/* file ptr to line numbers	*/
   unsigned short s_nreloc;	/* number of relocation entries	*/
   unsigned short s_nlnno;	/* number of line number entries*/
-  unsigned long	s_flags;	/* flags			*/
+  host_ulong	s_flags;	/* flags			*/
 };
 
 #define	SCNHDR	struct external_scnhdr
@@ -136,8 +136,8 @@
  */
 struct external_lineno {
   union {
-    unsigned long l_symndx; /* function name symbol index, iff l_lnno 0 */
-    unsigned long l_paddr;	/* (physical) address of line number	*/
+    host_ulong l_symndx; /* function name symbol index, iff l_lnno 0 */
+    host_ulong l_paddr;	/* (physical) address of line number	*/
   } l_addr;
   unsigned short l_lnno;	/* line number		*/
 };
@@ -156,11 +156,11 @@
   union {
     char e_name[E_SYMNMLEN];
     struct {
-      unsigned long e_zeroes;
-      unsigned long e_offset;
+      host_ulong e_zeroes;
+      host_ulong e_offset;
     } e;
   } e;
-  unsigned long e_value;
+  host_ulong e_value;
   unsigned short e_scnum;
   unsigned short e_type;
   char e_sclass[1];
@@ -174,18 +174,18 @@
 
 union external_auxent {
   struct {
-    unsigned long x_tagndx;	/* str, un, or enum tag indx */
+    host_ulong x_tagndx;	/* str, un, or enum tag indx */
     union {
       struct {
 	unsigned short  x_lnno; /* declaration line number */
 	unsigned short  x_size; /* str/union/array size */
       } x_lnsz;
-      unsigned long x_fsize;	/* size of function */
+      host_ulong x_fsize;	/* size of function */
     } x_misc;
     union {
       struct {			/* if ISFCN, tag, or .bb */
-	unsigned long x_lnnoptr;/* ptr to fcn line # */
-	unsigned long x_endndx;	/* entry ndx past block end */
+	host_ulong x_lnnoptr;/* ptr to fcn line # */
+	host_ulong x_endndx;	/* entry ndx past block end */
       } x_fcn;
       struct {			/* if ISARY, up to 4 dimen. */
 	char x_dimen[E_DIMNUM][2];
@@ -197,22 +197,22 @@
   union {
     char x_fname[E_FILNMLEN];
     struct {
-      unsigned long x_zeroes;
-      unsigned long x_offset;
+      host_ulong x_zeroes;
+      host_ulong x_offset;
     } x_n;
   } x_file;
 
   struct {
-    unsigned long x_scnlen;	/* section length */
+    host_ulong x_scnlen;	/* section length */
     unsigned short x_nreloc;	/* # relocation entries */
     unsigned short x_nlinno;	/* # line numbers */
-    unsigned long x_checksum;	/* section COMDAT checksum */
+    host_ulong x_checksum;	/* section COMDAT checksum */
     unsigned short x_associated;/* COMDAT associated section index */
     char x_comdat[1];		/* COMDAT selection number */
   } x_scn;
 
   struct {
-    unsigned long x_tvfill;	/* tv fill value */
+    host_ulong x_tvfill;	/* tv fill value */
     unsigned short x_tvlen;	/* length of .tv */
     char x_tvran[2][2];		/* tv range */
   } x_tv;	/* info about .tv section (in auxent of symbol .tv)) */
@@ -344,7 +344,7 @@
   unsigned short e_oemid;	/* OEM identifier (for e_oeminfo), 0x0 */
   unsigned short e_oeminfo;	/* OEM information; e_oemid specific, 0x0 */
   char e_res2[10][2];		/* Reserved words, all 0x0 */
-  unsigned long e_lfanew;	/* File address of new exe header, 0x80 */
+  host_ulong e_lfanew;	/* File address of new exe header, 0x80 */
   char dos_message[16][4];	/* other stuff, always follow DOS header */
   unsigned int nt_signature;	/* required NT signature, 0x4550 */
 
@@ -352,9 +352,9 @@
 
   unsigned short f_magic;	/* magic number			*/
   unsigned short f_nscns;	/* number of sections		*/
-  unsigned long f_timdat;	/* time & date stamp		*/
-  unsigned long f_symptr;	/* file pointer to symtab	*/
-  unsigned long f_nsyms;	/* number of symtab entries	*/
+  host_ulong f_timdat;	/* time & date stamp		*/
+  host_ulong f_symptr;	/* file pointer to symtab	*/
+  host_ulong f_nsyms;	/* number of symtab entries	*/
   unsigned short f_opthdr;	/* sizeof(optional hdr)		*/
   unsigned short f_flags;	/* flags			*/
 };
@@ -370,17 +370,17 @@
 {
   unsigned short magic;		/* type of file				*/
   unsigned short vstamp;	/* version stamp			*/
-  unsigned long	tsize;		/* text size in bytes, padded to FW bdry*/
-  unsigned long	dsize;		/* initialized data "  "		*/
-  unsigned long	bsize;		/* uninitialized data "   "		*/
-  unsigned long	entry;		/* entry pt.				*/
-  unsigned long text_start;	/* base of text used for this file */
-  unsigned long data_start;	/* base of all data used for this file */
+  host_ulong	tsize;		/* text size in bytes, padded to FW bdry*/
+  host_ulong	dsize;		/* initialized data "  "		*/
+  host_ulong	bsize;		/* uninitialized data "   "		*/
+  host_ulong	entry;		/* entry pt.				*/
+  host_ulong text_start;	/* base of text used for this file */
+  host_ulong data_start;	/* base of all data used for this file */
 
   /* NT extra fields; see internal.h for descriptions */
-  unsigned long  ImageBase;
-  unsigned long  SectionAlignment;
-  unsigned long  FileAlignment;
+  host_ulong  ImageBase;
+  host_ulong  SectionAlignment;
+  host_ulong  FileAlignment;
   unsigned short  MajorOperatingSystemVersion;
   unsigned short  MinorOperatingSystemVersion;
   unsigned short  MajorImageVersion;
@@ -388,17 +388,17 @@
   unsigned short  MajorSubsystemVersion;
   unsigned short  MinorSubsystemVersion;
   char  Reserved1[4];
-  unsigned long  SizeOfImage;
-  unsigned long  SizeOfHeaders;
-  unsigned long  CheckSum;
+  host_ulong  SizeOfImage;
+  host_ulong  SizeOfHeaders;
+  host_ulong  CheckSum;
   unsigned short Subsystem;
   unsigned short DllCharacteristics;
-  unsigned long  SizeOfStackReserve;
-  unsigned long  SizeOfStackCommit;
-  unsigned long  SizeOfHeapReserve;
-  unsigned long  SizeOfHeapCommit;
-  unsigned long  LoaderFlags;
-  unsigned long  NumberOfRvaAndSizes;
+  host_ulong  SizeOfStackReserve;
+  host_ulong  SizeOfStackCommit;
+  host_ulong  SizeOfHeapReserve;
+  host_ulong  SizeOfHeapCommit;
+  host_ulong  LoaderFlags;
+  host_ulong  NumberOfRvaAndSizes;
   /* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
   char  DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
 
diff --git a/aes.c b/aes.c
index cd4484f..40ed109 100644
--- a/aes.c
+++ b/aes.c
@@ -1,5 +1,5 @@
 /**
- * 
+ *
  * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project.
  */
 /*
@@ -1267,7 +1267,7 @@
 
 void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
 		     const unsigned long length, const AES_KEY *key,
-		     unsigned char *ivec, const int enc) 
+		     unsigned char *ivec, const int enc)
 {
 
 	unsigned long n;
@@ -1294,7 +1294,7 @@
 			AES_encrypt(tmp, tmp, key);
 			memcpy(out, tmp, AES_BLOCK_SIZE);
 			memcpy(ivec, tmp, AES_BLOCK_SIZE);
-		}			
+		}
 	} else {
 		while (len >= AES_BLOCK_SIZE) {
 			memcpy(tmp, in, AES_BLOCK_SIZE);
@@ -1312,6 +1312,6 @@
 			for(n=0; n < len; ++n)
 				out[n] = tmp[n] ^ ivec[n];
 			memcpy(ivec, tmp, AES_BLOCK_SIZE);
-		}			
+		}
 	}
 }
diff --git a/alpha-dis.c b/alpha-dis.c
index 81a55e9..c6af1aa 100644
--- a/alpha-dis.c
+++ b/alpha-dis.c
@@ -374,7 +374,7 @@
 
   /* The signed "23-bit" aligned displacement of Branch format insns */
 #define BDISP		(MDISP + 1)
-  { 21, 0, BFD_RELOC_23_PCREL_S2, 
+  { 21, 0, BFD_RELOC_23_PCREL_S2,
     AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp },
 
   /* The 26-bit PALcode function */
diff --git a/arm-dis.c b/arm-dis.c
index 1e027ef..11f580b 100644
--- a/arm-dis.c
+++ b/arm-dis.c
@@ -4,17 +4,17 @@
    Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
    Modification by James G. Smith (jsmith@cygnus.co.uk)
 
-This file is part of libopcodes. 
+This file is part of libopcodes.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 Software Foundation; either version 2 of the License, or (at your option)
-any later version. 
+any later version.
 
 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
-more details. 
+more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
@@ -34,7 +34,7 @@
 };
 
 /* format of the assembler string :
-   
+
    %%			%
    %<bitfield>d		print the bitfield in decimal
    %<bitfield>x		print the bitfield in hex
@@ -104,7 +104,7 @@
     {0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"},
     {0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"},
     {0xf450f000, 0xfc70f000, "pld\t%a"},
-    
+
     /* V5 Instructions.  */
     {0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"},
     {0xfa000000, 0xfe000000, "blx\t%B"},
@@ -116,7 +116,7 @@
     {0xfe000010, 0xff100010, "mcr2\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
     {0xfe100010, 0xff100010, "mrc2\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"},
 
-    /* V5E "El Segundo" Instructions.  */    
+    /* V5E "El Segundo" Instructions.  */
     {0x000000d0, 0x0e1000f0, "ldr%cd\t%12-15r, %s"},
     {0x000000f0, 0x0e1000f0, "str%cd\t%12-15r, %s"},
     {0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"},
@@ -303,7 +303,7 @@
     {0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"},
     {0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"},
     {0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"},
-    {0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, 
+    {0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"},
     {0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"},
     {0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"},
     {0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"},
@@ -571,7 +571,7 @@
 static char * arm_fp_const[] =
 {"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
 
-static char * arm_shift[] = 
+static char * arm_shift[] =
 {"lsl", "lsr", "asr", "ror"};
 
 /* Forward declarations.  */
@@ -621,14 +621,14 @@
      void * stream;
 {
   func (stream, "%s", arm_regnames[given & 0xf]);
-  
+
   if ((given & 0xff0) != 0)
     {
       if ((given & 0x10) == 0)
 	{
 	  int amount = (given & 0xf80) >> 7;
 	  int shift = (given & 0x60) >> 5;
-	  
+
 	  if (amount == 0)
 	    {
 	      if (shift == 3)
@@ -636,10 +636,10 @@
 		  func (stream, ", rrx");
 		  return;
 		}
-	      
+
 	      amount = 32;
 	    }
-	  
+
 	  func (stream, ", %s #%d", arm_shift[shift], amount);
 	}
       else
@@ -666,7 +666,7 @@
       if ((given & insn->mask) == insn->value)
 	{
 	  char * c;
-	  
+
 	  for (c = insn->assembler; *c; c++)
 	    {
 	      if (*c == '%')
@@ -682,14 +682,14 @@
 			  && ((given & 0x02000000) == 0))
 			{
 			  int offset = given & 0xfff;
-			  
+
 			  func (stream, "[pc");
- 
+
 			  if (given & 0x01000000)
 			    {
 			      if ((given & 0x00800000) == 0)
 				offset = - offset;
-			  
+
 			      /* Pre-indexed.  */
 			      func (stream, ", #%d]", offset);
 
@@ -710,13 +710,13 @@
 			      /* ie ignore the offset.  */
 			      offset = pc + 8;
 			    }
-			  
+
 			  func (stream, "\t; ");
 			  info->print_address_func (offset, info);
 			}
 		      else
 			{
-			  func (stream, "[%s", 
+			  func (stream, "[%s",
 				arm_regnames[(given >> 16) & 0xf]);
 			  if ((given & 0x01000000) != 0)
 			    {
@@ -736,7 +736,7 @@
 				  arm_decode_shift (given, func, stream);
 				}
 
-			      func (stream, "]%s", 
+			      func (stream, "]%s",
 				    ((given & 0x00200000) != 0) ? "!" : "");
 			    }
 			  else
@@ -748,13 +748,13 @@
 				    func (stream, "], %s#%d",
 					  (((given & 0x00800000) == 0)
 					   ? "-" : ""), offset);
-				  else 
+				  else
 				    func (stream, "]");
 				}
 			      else
 				{
 				  func (stream, "], %s",
-					(((given & 0x00800000) == 0) 
+					(((given & 0x00800000) == 0)
 					 ? "-" : ""));
 				  arm_decode_shift (given, func, stream);
 				}
@@ -767,18 +767,18 @@
 			{
                           /* PC relative with immediate offset.  */
 			  int offset = ((given & 0xf00) >> 4) | (given & 0xf);
-			  
+
 			  if ((given & 0x00800000) == 0)
 			    offset = -offset;
-			  
+
 			  func (stream, "[pc, #%d]\t; ", offset);
-			  
+
 			  (*info->print_address_func)
 			    (offset + pc + 8, info);
 			}
 		      else
 			{
-			  func (stream, "[%s", 
+			  func (stream, "[%s",
 				arm_regnames[(given >> 16) & 0xf]);
 			  if ((given & 0x01000000) != 0)
 			    {
@@ -801,7 +801,7 @@
                                         arm_regnames[given & 0xf]);
 				}
 
-			      func (stream, "]%s", 
+			      func (stream, "]%s",
 				    ((given & 0x00200000) != 0) ? "!" : "");
 			    }
 			  else
@@ -815,7 +815,7 @@
 				    func (stream, "], %s#%d",
 					  (((given & 0x00800000) == 0)
 					   ? "-" : ""), offset);
-				  else 
+				  else
 				    func (stream, "]");
 				}
 			      else
@@ -829,7 +829,7 @@
 			    }
 			}
 		      break;
-			  
+
 		    case 'b':
 		      (*info->print_address_func)
 			(BDISP (given) * 4 + pc + 8, info);
@@ -911,7 +911,7 @@
 		      {
 			bfd_vma address;
 			bfd_vma offset = 0;
-			
+
 			if (given & 0x00800000)
 			  /* Is signed, hi bits should be ones.  */
 			  offset = (-1) ^ 0x00ffffff;
@@ -920,7 +920,7 @@
 			offset += given & 0x00ffffff;
 			offset <<= 2;
 			address = offset + pc + 8;
-			
+
 			if (given & 0x01000000)
 			  /* H bit allows addressing to 2-byte boundaries.  */
 			  address += 2;
@@ -976,7 +976,7 @@
 			  func (stream, "3");
 			}
 		      break;
-			
+
 		    case 'P':
 		      switch (given & 0x00080080)
 			{
@@ -1028,7 +1028,7 @@
 			}
 		      break;
 
-		    case '0': case '1': case '2': case '3': case '4': 
+		    case '0': case '1': case '2': case '3': case '4':
 		    case '5': case '6': case '7': case '8': case '9':
 		      {
 			int bitstart = *c++ - '0';
@@ -1040,44 +1040,44 @@
 			  {
 			  case '-':
 			    c++;
-			    
+
 			    while (*c >= '0' && *c <= '9')
 			      bitend = (bitend * 10) + *c++ - '0';
-			    
+
 			    if (!bitend)
 			      abort ();
-			    
+
 			    switch (*c)
 			      {
 			      case 'r':
 				{
 				  long reg;
-				  
+
 				  reg = given >> bitstart;
 				  reg &= (2 << (bitend - bitstart)) - 1;
-				  
+
 				  func (stream, "%s", arm_regnames[reg]);
 				}
 				break;
 			      case 'd':
 				{
 				  long reg;
-				  
+
 				  reg = given >> bitstart;
 				  reg &= (2 << (bitend - bitstart)) - 1;
-				  
+
 				  func (stream, "%d", reg);
 				}
 				break;
 			      case 'x':
 				{
 				  long reg;
-				  
+
 				  reg = given >> bitstart;
 				  reg &= (2 << (bitend - bitstart)) - 1;
-				  
+
 				  func (stream, "0x%08x", reg);
-				  
+
 				  /* Some SWI instructions have special
 				     meanings.  */
 				  if ((given & 0x0fffffff) == 0x0FF00000)
@@ -1089,20 +1089,20 @@
 			      case 'X':
 				{
 				  long reg;
-				  
+
 				  reg = given >> bitstart;
 				  reg &= (2 << (bitend - bitstart)) - 1;
-				  
+
 				  func (stream, "%01x", reg & 0xf);
 				}
 				break;
 			      case 'f':
 				{
 				  long reg;
-				  
+
 				  reg = given >> bitstart;
 				  reg &= (2 << (bitend - bitstart)) - 1;
-				  
+
 				  if (reg > 7)
 				    func (stream, "#%s",
 					  arm_fp_const[reg & 7]);
@@ -1163,7 +1163,7 @@
 				    }
 				  break;
 
-				  
+
 				default:
 				  abort ();
 				}
@@ -1252,7 +1252,7 @@
           if (!*c) /* Check for empty (not NULL) assembler string.  */
             {
 	      long offset;
-	      
+
 	      info->bytes_per_chunk = 4;
 	      info->bytes_per_line  = 4;
 
@@ -1274,16 +1274,16 @@
             {
 	      info->bytes_per_chunk = 2;
 	      info->bytes_per_line  = 4;
-	  	      
+
               given &= 0xffff;
-	      
+
               for (; *c; c++)
                 {
                   if (*c == '%')
                     {
                       int domaskpc = 0;
                       int domasklr = 0;
-		      
+
                       switch (*++c)
                         {
                         case '%':
@@ -1293,11 +1293,11 @@
                         case 'S':
                           {
                             long reg;
-			    
+
                             reg = (given >> 3) & 0x7;
                             if (given & (1 << 6))
                               reg += 8;
-			    
+
                             func (stream, "%s", arm_regnames[reg]);
                           }
                           break;
@@ -1305,11 +1305,11 @@
                         case 'D':
                           {
                             long reg;
-			    
+
                             reg = given & 0x7;
                             if (given & (1 << 7))
                              reg += 8;
-			    
+
                             func (stream, "%s", arm_regnames[reg]);
                           }
                           break;
@@ -1331,9 +1331,9 @@
                           {
                             int started = 0;
                             int reg;
-			    
+
                             func (stream, "{");
-			    
+
                             /* It would be nice if we could spot
                                ranges, and generate the rS-rE format: */
                             for (reg = 0; (reg < 8); reg++)
@@ -1365,12 +1365,12 @@
                           break;
 
 
-                        case '0': case '1': case '2': case '3': case '4': 
+                        case '0': case '1': case '2': case '3': case '4':
                         case '5': case '6': case '7': case '8': case '9':
                           {
                             int bitstart = *c++ - '0';
                             int bitend = 0;
-			    
+
                             while (*c >= '0' && *c <= '9')
                               bitstart = (bitstart * 10) + *c++ - '0';
 
@@ -1379,7 +1379,7 @@
                               case '-':
                                 {
                                   long reg;
-				  
+
                                   c++;
                                   while (*c >= '0' && *c <= '9')
                                     bitend = (bitend * 10) + *c++ - '0';
@@ -1478,11 +1478,11 @@
 {
   if (option == NULL)
     return;
-      
+
   if (strneq (option, "reg-names-", 10))
     {
       int i;
-	
+
       option += 10;
 
       for (i = NUM_ARM_REGNAMES; i--;)
@@ -1491,7 +1491,7 @@
 	    regname_selected = i;
 	    break;
 	  }
-      
+
       if (i < 0)
 	fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
     }
@@ -1501,7 +1501,7 @@
     force_thumb = 0;
   else
     fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
-  
+
   return;
 }
 
@@ -1512,7 +1512,7 @@
      char * options;
 {
   char * space;
-  
+
   if (options == NULL)
     return;
 
@@ -1550,25 +1550,25 @@
   if (info->disassembler_options)
     {
       parse_disassembler_options (info->disassembler_options);
-      
+
       /* To avoid repeated parsing of these options, we remove them here.  */
       info->disassembler_options = NULL;
     }
-  
+
   is_thumb = force_thumb;
   if (pc & 1)
     {
       is_thumb = 1;
       pc &= ~(bfd_vma) 1;
     }
-  
+
 #if 0
   if (!is_thumb && info->symbols != NULL)
     {
       if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
 	{
 	  coff_symbol_type * cs;
-	  
+
 	  cs = coffsymbol (*info->symbols);
 	  is_thumb = (   cs->native->u.syment.n_sclass == C_THUMBEXT
 		      || cs->native->u.syment.n_sclass == C_THUMBSTAT
@@ -1580,15 +1580,15 @@
 	{
 	  elf_symbol_type *  es;
 	  unsigned int       type;
-	  
+
 	  es = *(elf_symbol_type **)(info->symbols);
 	  type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
-	  
+
 	  is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
 	}
     }
 #endif
-  
+
   little = (info->endian == BFD_ENDIAN_LITTLE);
   info->bytes_per_chunk = 4;
   info->display_endian  = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
@@ -1599,17 +1599,17 @@
       if (status != 0 && is_thumb)
 	{
 	  info->bytes_per_chunk = 2;
-	  
+
 	  status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
 	  b[3] = b[2] = 0;
 	}
-      
+
       if (status != 0)
 	{
 	  info->memory_error_func (status, pc, info);
 	  return -1;
 	}
-      
+
       given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
     }
   else
@@ -1621,13 +1621,13 @@
 	  info->memory_error_func (status, pc, info);
 	  return -1;
 	}
-      
+
       if (is_thumb)
 	{
 	  if (pc & 0x2)
 	    {
 	      given = (b[2] << 8) | b[3];
-	      
+
 	      status = info->read_memory_func
 		((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
 	      if (status != 0)
@@ -1635,7 +1635,7 @@
 		  info->memory_error_func (status, pc + 4, info);
 		  return -1;
 		}
-	      
+
 	      given |= (b[0] << 24) | (b[1] << 16);
 	    }
 	  else
@@ -1644,7 +1644,7 @@
       else
 	given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
     }
-  
+
   if (info->flags & INSN_HAS_RELOC)
     /* If the instruction has a reloc associated with it, then
        the offset field in the instruction will actually be the
@@ -1668,7 +1668,7 @@
   fprintf (stream, _("\n\
 The following ARM specific disassembler options are supported for use with\n\
 the -M switch:\n"));
-  
+
   for (i = NUM_ARM_REGNAMES; i--;)
     fprintf (stream, "  reg-names-%s %*c%s\n",
 	     regnames[i].name,
diff --git a/arm-semi.c b/arm-semi.c
index 4ddbc73..ff7a343 100644
--- a/arm-semi.c
+++ b/arm-semi.c
@@ -1,6 +1,6 @@
 /*
  *  Arm "Angel" semihosting syscalls
- * 
+ *
  *  Copyright (c) 2005, 2007 CodeSourcery.
  *  Written by Paul Brook.
  *
@@ -112,69 +112,26 @@
     return code;
 }
 
-static uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
-{
-    uint32_t val;
-
-    cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
-    return tswap32(val);
-}
-static uint32_t softmmu_tget8(CPUState *env, uint32_t addr)
-{
-    uint8_t val;
-
-    cpu_memory_rw_debug(env, addr, &val, 1, 0);
-    return val;
-}
-#define tget32(p) softmmu_tget32(env, p)
-#define tget8(p) softmmu_tget8(env, p)
-
-static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
-                               int copy)
-{
-    char *p;
-    /* TODO: Make this something that isn't fixed size.  */
-    p = malloc(len);
-    if (copy)
-        cpu_memory_rw_debug(env, addr, p, len, 0);
-    return p;
-}
-#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy)
-static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
-{
-    char *p;
-    char *s;
-    uint8_t c;
-    /* TODO: Make this something that isn't fixed size.  */
-    s = p = malloc(1024);
-    do {
-        cpu_memory_rw_debug(env, addr, &c, 1, 0);
-        addr++;
-        *(p++) = c;
-    } while (c);
-    return s;
-}
-#define lock_user_string(p) softmmu_lock_user_string(env, p)
-static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
-                                target_ulong len)
-{
-    if (len)
-        cpu_memory_rw_debug(env, addr, p, len, 1);
-    free(p);
-}
-#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
+#include "softmmu-semi.h"
 #endif
 
 static target_ulong arm_semi_syscall_len;
 
+#if !defined(CONFIG_USER_ONLY)
+static target_ulong syscall_err;
+#endif
+
 static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
 {
 #ifdef CONFIG_USER_ONLY
     TaskState *ts = env->opaque;
 #endif
+
     if (ret == (target_ulong)-1) {
 #ifdef CONFIG_USER_ONLY
         ts->swi_errno = err;
+#else
+	syscall_err = err;
 #endif
         env->regs[0] = ret;
     } else {
@@ -194,6 +151,20 @@
     }
 }
 
+static void arm_semi_flen_cb(CPUState *env, target_ulong ret, target_ulong err)
+{
+    /* The size is always stored in big-endian order, extract
+       the value. We assume the size always fit in 32 bits.  */
+    uint32_t size;
+    cpu_memory_rw_debug(env, env->regs[13]-64+32, (uint8_t *)&size, 4, 0);
+    env->regs[0] = be32_to_cpu(size);
+#ifdef CONFIG_USER_ONLY
+    ((TaskState *)env->opaque)->swi_errno = err;
+#else
+    syscall_err = err;
+#endif
+}
+
 #define ARG(n) tget32(args + (n) * 4)
 #define SET_ARG(n, val) tput32(args + (n) * 4,val)
 uint32_t do_arm_semihosting(CPUState *env)
@@ -223,8 +194,8 @@
                 return STDOUT_FILENO;
         }
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), (int)ARG(2),
-                           gdb_open_modeflags[ARG(1)]);
+            gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0),
+			   (int)ARG(2)+1, gdb_open_modeflags[ARG(1)]);
             return env->regs[0];
         } else {
             ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
@@ -302,7 +273,7 @@
         }
     case SYS_SEEK:
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(arm_semi_cb, "fseek,%x,%x,0", ARG(0), ARG(1));
+            gdb_do_syscall(arm_semi_cb, "lseek,%x,%x,0", ARG(0), ARG(1));
             return env->regs[0];
         } else {
             ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
@@ -312,8 +283,9 @@
         }
     case SYS_FLEN:
         if (use_gdb_syscalls()) {
-            /* TODO: Use stat syscall.  */
-            return -1;
+            gdb_do_syscall(arm_semi_flen_cb, "fstat,%x,%x",
+			   ARG(0), env->regs[13]-64);
+            return env->regs[0];
         } else {
             struct stat buf;
             ret = set_swi_errno(ts, fstat(ARG(0), &buf));
@@ -326,7 +298,7 @@
         return -1;
     case SYS_REMOVE:
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1));
+            gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1)+1);
             ret = env->regs[0];
         } else {
             s = lock_user_string(ARG(0));
@@ -337,7 +309,7 @@
     case SYS_RENAME:
         if (use_gdb_syscalls()) {
             gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
-                           ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
+                           ARG(0), (int)ARG(1)+1, ARG(2), (int)ARG(3)+1);
             return env->regs[0];
         } else {
             char *s2;
@@ -354,7 +326,7 @@
         return set_swi_errno(ts, time(NULL));
     case SYS_SYSTEM:
         if (use_gdb_syscalls()) {
-            gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1));
+            gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1)+1);
             return env->regs[0];
         } else {
             s = lock_user_string(ARG(0));
@@ -365,7 +337,7 @@
 #ifdef CONFIG_USER_ONLY
         return ts->swi_errno;
 #else
-        return 0;
+        return syscall_err;
 #endif
     case SYS_GET_CMDLINE:
 #ifdef CONFIG_USER_ONLY
@@ -429,7 +401,7 @@
                 }
                 ts->heap_limit = limit;
             }
-              
+
             ptr = lock_user(ARG(0), 16, 0);
             ptr[0] = tswap32(ts->heap_base);
             ptr[1] = tswap32(ts->heap_limit);
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 71e5235..a573a38 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -50,13 +50,15 @@
     unsigned int period_size_out;
     unsigned int threshold;
 
-    int buffer_size_in_overriden;
-    int period_size_in_overriden;
+    int buffer_size_in_overridden;
+    int period_size_in_overridden;
 
-    int buffer_size_out_overriden;
-    int period_size_out_overriden;
+    int buffer_size_out_overridden;
+    int period_size_out_overridden;
     int verbose;
 } conf = {
+#define DEFAULT_BUFFER_SIZE 1024
+#define DEFAULT_PERIOD_SIZE 256
 #ifdef HIGH_LATENCY
     .size_in_usec_in = 1,
     .size_in_usec_out = 1,
@@ -69,16 +71,14 @@
     .buffer_size_out = 400000,
     .period_size_out = 400000 / 4,
 #else
-#define DEFAULT_BUFFER_SIZE 1024
-#define DEFAULT_PERIOD_SIZE 256
     .buffer_size_in = DEFAULT_BUFFER_SIZE * 4,
     .period_size_in = DEFAULT_PERIOD_SIZE * 4,
     .buffer_size_out = DEFAULT_BUFFER_SIZE,
     .period_size_out = DEFAULT_PERIOD_SIZE,
-    .buffer_size_in_overriden = 0,
-    .buffer_size_out_overriden = 0,
-    .period_size_in_overriden = 0,
-    .period_size_out_overriden = 0,
+    .buffer_size_in_overridden = 0,
+    .buffer_size_out_overridden = 0,
+    .period_size_in_overridden = 0,
+    .period_size_out_overridden = 0,
 #endif
     .threshold = 0,
     .verbose = 0
@@ -157,6 +157,12 @@
     case AUD_FMT_U16:
         return SND_PCM_FORMAT_U16_LE;
 
+    case AUD_FMT_S32:
+        return SND_PCM_FORMAT_S32_LE;
+
+    case AUD_FMT_U32:
+        return SND_PCM_FORMAT_U32_LE;
+
     default:
         dolog ("Internal logic error: Bad audio format %d\n", fmt);
 #ifdef DEBUG_AUDIO
@@ -199,6 +205,26 @@
         *fmt = AUD_FMT_U16;
         break;
 
+    case SND_PCM_FORMAT_S32_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_S32;
+        break;
+
+    case SND_PCM_FORMAT_U32_LE:
+        *endianness = 0;
+        *fmt = AUD_FMT_U32;
+        break;
+
+    case SND_PCM_FORMAT_S32_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_S32;
+        break;
+
+    case SND_PCM_FORMAT_U32_BE:
+        *endianness = 1;
+        *fmt = AUD_FMT_U32;
+        break;
+
     default:
         dolog ("Unrecognized audio format %d\n", alsafmt);
         return -1;
@@ -388,8 +414,8 @@
                 }
                 else {
                     if (period_size < minval) {
-                        if ((in && conf.period_size_in_overriden)
-                            || (!in && conf.period_size_out_overriden)) {
+                        if ((in && conf.period_size_in_overridden)
+                            || (!in && conf.period_size_out_overridden)) {
                             dolog ("%s period size(%d) is less "
                                    "than minmal period size(%ld)\n",
                                    typ,
@@ -424,8 +450,8 @@
             }
             else {
                 if (buffer_size < minval) {
-                    if ((in && conf.buffer_size_in_overriden)
-                        || (!in && conf.buffer_size_out_overriden)) {
+                    if ((in && conf.buffer_size_in_overridden)
+                        || (!in && conf.buffer_size_out_overridden)) {
                         dolog (
                             "%s buffer size(%d) is less "
                             "than minimal buffer size(%ld)\n",
@@ -919,16 +945,16 @@
     {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out,
      "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
     {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out,
-     "DAC period size", &conf.period_size_out_overriden, 0},
+     "DAC period size", &conf.period_size_out_overridden, 0},
     {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out,
-     "DAC buffer size", &conf.buffer_size_out_overriden, 0},
+     "DAC buffer size", &conf.buffer_size_out_overridden, 0},
 
     {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in,
      "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0},
     {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in,
-     "ADC period size", &conf.period_size_in_overriden, 0},
+     "ADC period size", &conf.period_size_in_overridden, 0},
     {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in,
-     "ADC buffer size", &conf.buffer_size_in_overriden, 0},
+     "ADC buffer size", &conf.buffer_size_in_overridden, 0},
 
     {"THRESHOLD", AUD_OPT_INT, &conf.threshold,
      "(undocumented)", NULL, 0},
diff --git a/audio/audio.c b/audio/audio.c
index 556e6fd..4248c14 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -80,7 +80,8 @@
         {
             44100,              /* freq */
             2,                  /* nchannels */
-            AUD_FMT_S16         /* fmt */
+            AUD_FMT_S16,        /* fmt */
+            AUDIO_HOST_ENDIANNESS
         }
     },
 
@@ -91,7 +92,8 @@
         {
             44100,              /* freq */
             2,                  /* nchannels */
-            AUD_FMT_S16         /* fmt */
+            AUD_FMT_S16,        /* fmt */
+            AUDIO_HOST_ENDIANNESS
         }
     },
 
@@ -166,6 +168,25 @@
 }
 #endif
 
+static inline int audio_bits_to_index (int bits)
+{
+    switch (bits) {
+    case 8:
+        return 0;
+
+    case 16:
+        return 1;
+
+    case 32:
+        return 2;
+
+    default:
+        audio_bug ("bits_to_index", 1);
+        AUD_log (NULL, "invalid bits %d\n", bits);
+        return 0;
+    }
+}
+
 void *audio_calloc (const char *funcname, int nmemb, size_t size)
 {
     int cond;
@@ -227,6 +248,12 @@
 
     case AUD_FMT_S16:
         return "S16";
+
+    case AUD_FMT_U32:
+        return "U32";
+
+    case AUD_FMT_S32:
+        return "S32";
     }
 
     dolog ("Bogus audfmt %d returning S16\n", fmt);
@@ -243,6 +270,10 @@
         *defaultp = 0;
         return AUD_FMT_U16;
     }
+    else if (!strcasecmp (s, "u32")) {
+        *defaultp = 0;
+        return AUD_FMT_U32;
+    }
     else if (!strcasecmp (s, "s8")) {
         *defaultp = 0;
         return AUD_FMT_S8;
@@ -251,6 +282,10 @@
         *defaultp = 0;
         return AUD_FMT_S16;
     }
+    else if (!strcasecmp (s, "s32")) {
+        *defaultp = 0;
+        return AUD_FMT_S32;
+    }
     else {
         dolog ("Bogus audio format `%s' using %s\n",
                s, audio_audfmt_to_string (defval));
@@ -351,7 +386,7 @@
         const char *state = "default";
         printf ("  %s_%s: ", uprefix, opt->name);
 
-        if (opt->overridenp && *opt->overridenp) {
+        if (opt->overriddenp && *opt->overriddenp) {
             state = "current";
         }
 
@@ -481,10 +516,10 @@
             break;
         }
 
-        if (!opt->overridenp) {
-            opt->overridenp = &opt->overriden;
+        if (!opt->overriddenp) {
+            opt->overriddenp = &opt->overridden;
         }
-        *opt->overridenp = !def;
+        *opt->overriddenp = !def;
         qemu_free (optname);
     }
 }
@@ -538,6 +573,8 @@
     case AUD_FMT_U8:
     case AUD_FMT_S16:
     case AUD_FMT_U16:
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
         break;
     default:
         invalid = 1;
@@ -563,6 +600,12 @@
     case AUD_FMT_U16:
         bits = 16;
         break;
+
+    case AUD_FMT_S32:
+        sign = 1;
+    case AUD_FMT_U32:
+        bits = 32;
+        break;
     }
     return info->freq == as->freq
         && info->nchannels == as->nchannels
@@ -573,7 +616,7 @@
 
 void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
 {
-    int bits = 8, sign = 0;
+    int bits = 8, sign = 0, shift = 0;
 
     switch (as->fmt) {
     case AUD_FMT_S8:
@@ -585,6 +628,14 @@
         sign = 1;
     case AUD_FMT_U16:
         bits = 16;
+        shift = 1;
+        break;
+
+    case AUD_FMT_S32:
+        sign = 1;
+    case AUD_FMT_U32:
+        bits = 32;
+        shift = 2;
         break;
     }
 
@@ -592,7 +643,7 @@
     info->bits = bits;
     info->sign = sign;
     info->nchannels = as->nchannels;
-    info->shift = (as->nchannels == 2) + (bits == 16);
+    info->shift = (as->nchannels == 2) + shift;
     info->align = (1 << info->shift) - 1;
     info->bytes_per_second = info->freq << info->shift;
     info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
@@ -608,22 +659,49 @@
         memset (buf, 0x00, len << info->shift);
     }
     else {
-        if (info->bits == 8) {
+        switch (info->bits) {
+        case 8:
             memset (buf, 0x80, len << info->shift);
-        }
-        else {
-            int i;
-            uint16_t *p = buf;
-            int shift = info->nchannels - 1;
-            short s = INT16_MAX;
+            break;
 
-            if (info->swap_endianness) {
-                s = bswap16 (s);
-            }
+        case 16:
+            {
+                int i;
+                uint16_t *p = buf;
+                int shift = info->nchannels - 1;
+                short s = INT16_MAX;
 
-            for (i = 0; i < len << shift; i++) {
-                p[i] = s;
+                if (info->swap_endianness) {
+                    s = bswap16 (s);
+                }
+
+                for (i = 0; i < len << shift; i++) {
+                    p[i] = s;
+                }
             }
+            break;
+
+        case 32:
+            {
+                int i;
+                uint32_t *p = buf;
+                int shift = info->nchannels - 1;
+                int32_t s = INT32_MAX;
+
+                if (info->swap_endianness) {
+                    s = bswap32 (s);
+                }
+
+                for (i = 0; i < len << shift; i++) {
+                    p[i] = s;
+                }
+            }
+            break;
+
+        default:
+            AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n",
+                     info->bits);
+            break;
         }
     }
 }
@@ -1811,7 +1889,7 @@
             [hw->info.nchannels == 2]
             [hw->info.sign]
             [hw->info.swap_endianness]
-            [hw->info.bits == 16];
+            [audio_bits_to_index (hw->info.bits)];
 
         LIST_INSERT_HEAD (&s->cap_head, cap, entries);
         LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
diff --git a/audio/audio.h b/audio/audio.h
index c097f39..287cc5c 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -33,7 +33,9 @@
     AUD_FMT_U8,
     AUD_FMT_S8,
     AUD_FMT_U16,
-    AUD_FMT_S16
+    AUD_FMT_S16,
+    AUD_FMT_U32,
+    AUD_FMT_S32
 } audfmt_e;
 
 #ifdef WORDS_BIGENDIAN
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 1a15d4c..cd22a30 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -44,8 +44,8 @@
     audio_option_tag_e tag;
     void *valp;
     const char *descr;
-    int *overridenp;
-    int overriden;
+    int *overriddenp;
+    int overridden;
 };
 
 struct audio_callback {
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 13e1c3e..850e101 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -164,7 +164,7 @@
         [sw->info.nchannels == 2]
         [sw->info.sign]
         [sw->info.swap_endianness]
-        [sw->info.bits == 16];
+        [audio_bits_to_index (sw->info.bits)];
 
     sw->name = qemu_strdup (name);
     err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
@@ -288,7 +288,7 @@
         [hw->info.nchannels == 2]
         [hw->info.sign]
         [hw->info.swap_endianness]
-        [hw->info.bits == 16];
+        [audio_bits_to_index (hw->info.bits)];
 
     if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
         goto err1;
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 8512f12..74d432f 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -294,7 +294,6 @@
     coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
     UInt32 propertySize;
     int err;
-    int bits = 8;
     const char *typ = "playback";
     AudioValueRange frameRange;
 
@@ -305,10 +304,6 @@
         return -1;
     }
 
-    if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
-        bits = 16;
-    }
-
     audio_pcm_init_info (&hw->info, as);
 
     /* open default output device */
diff --git a/audio/mixeng.c b/audio/mixeng.c
index 6308d41..34cc1ae 100644
--- a/audio/mixeng.c
+++ b/audio/mixeng.c
@@ -82,6 +82,7 @@
 #undef IN_T
 #undef SHIFT
 
+/* Unsigned 16 bit */
 #define IN_T uint16_t
 #define IN_MIN 0
 #define IN_MAX USHRT_MAX
@@ -101,26 +102,72 @@
 #undef IN_T
 #undef SHIFT
 
-t_sample *mixeng_conv[2][2][2][2] = {
+/* Signed 32 bit */
+#define IN_T int32_t
+#define IN_MIN INT32_MIN
+#define IN_MAX INT32_MAX
+#define SIGNED
+#define SHIFT 32
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#define ENDIAN_CONVERSION swap
+#define ENDIAN_CONVERT(v) bswap32 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#undef SIGNED
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+/* Unsigned 16 bit */
+#define IN_T uint32_t
+#define IN_MIN 0
+#define IN_MAX UINT32_MAX
+#define SHIFT 32
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#define ENDIAN_CONVERSION swap
+#define ENDIAN_CONVERT(v) bswap32 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+t_sample *mixeng_conv[2][2][2][3] = {
     {
         {
             {
                 conv_natural_uint8_t_to_mono,
-                conv_natural_uint16_t_to_mono
+                conv_natural_uint16_t_to_mono,
+                conv_natural_uint32_t_to_mono
             },
             {
                 conv_natural_uint8_t_to_mono,
-                conv_swap_uint16_t_to_mono
+                conv_swap_uint16_t_to_mono,
+                conv_swap_uint32_t_to_mono,
             }
         },
         {
             {
                 conv_natural_int8_t_to_mono,
-                conv_natural_int16_t_to_mono
+                conv_natural_int16_t_to_mono,
+                conv_natural_int32_t_to_mono
             },
             {
                 conv_natural_int8_t_to_mono,
-                conv_swap_int16_t_to_mono
+                conv_swap_int16_t_to_mono,
+                conv_swap_int32_t_to_mono
             }
         }
     },
@@ -128,46 +175,54 @@
         {
             {
                 conv_natural_uint8_t_to_stereo,
-                conv_natural_uint16_t_to_stereo
+                conv_natural_uint16_t_to_stereo,
+                conv_natural_uint32_t_to_stereo
             },
             {
                 conv_natural_uint8_t_to_stereo,
-                conv_swap_uint16_t_to_stereo
+                conv_swap_uint16_t_to_stereo,
+                conv_swap_uint32_t_to_stereo
             }
         },
         {
             {
                 conv_natural_int8_t_to_stereo,
-                conv_natural_int16_t_to_stereo
+                conv_natural_int16_t_to_stereo,
+                conv_natural_int32_t_to_stereo
             },
             {
                 conv_natural_int8_t_to_stereo,
-                conv_swap_int16_t_to_stereo
+                conv_swap_int16_t_to_stereo,
+                conv_swap_int32_t_to_stereo,
             }
         }
     }
 };
 
-f_sample *mixeng_clip[2][2][2][2] = {
+f_sample *mixeng_clip[2][2][2][3] = {
     {
         {
             {
                 clip_natural_uint8_t_from_mono,
-                clip_natural_uint16_t_from_mono
+                clip_natural_uint16_t_from_mono,
+                clip_natural_uint32_t_from_mono
             },
             {
                 clip_natural_uint8_t_from_mono,
-                clip_swap_uint16_t_from_mono
+                clip_swap_uint16_t_from_mono,
+                clip_swap_uint32_t_from_mono
             }
         },
         {
             {
                 clip_natural_int8_t_from_mono,
-                clip_natural_int16_t_from_mono
+                clip_natural_int16_t_from_mono,
+                clip_natural_int32_t_from_mono
             },
             {
                 clip_natural_int8_t_from_mono,
-                clip_swap_int16_t_from_mono
+                clip_swap_int16_t_from_mono,
+                clip_swap_int32_t_from_mono
             }
         }
     },
@@ -175,21 +230,25 @@
         {
             {
                 clip_natural_uint8_t_from_stereo,
-                clip_natural_uint16_t_from_stereo
+                clip_natural_uint16_t_from_stereo,
+                clip_natural_uint32_t_from_stereo
             },
             {
                 clip_natural_uint8_t_from_stereo,
-                clip_swap_uint16_t_from_stereo
+                clip_swap_uint16_t_from_stereo,
+                clip_swap_uint32_t_from_stereo
             }
         },
         {
             {
                 clip_natural_int8_t_from_stereo,
-                clip_natural_int16_t_from_stereo
+                clip_natural_int16_t_from_stereo,
+                clip_natural_int32_t_from_stereo
             },
             {
                 clip_natural_int8_t_from_stereo,
-                clip_swap_int16_t_from_stereo
+                clip_swap_int16_t_from_stereo,
+                clip_swap_int32_t_from_stereo
             }
         }
     }
diff --git a/audio/mixeng.h b/audio/mixeng.h
index 9e3bac1..95b68df 100644
--- a/audio/mixeng.h
+++ b/audio/mixeng.h
@@ -37,8 +37,8 @@
                          int samples, volume_t *vol);
 typedef void (f_sample) (void *dst, const st_sample_t *src, int samples);
 
-extern t_sample *mixeng_conv[2][2][2][2];
-extern f_sample *mixeng_clip[2][2][2][2];
+extern t_sample *mixeng_conv[2][2][2][3];
+extern f_sample *mixeng_clip[2][2][2][3];
 
 void *st_rate_start (int inrate, int outrate);
 void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 125e4c8..cedcea4 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -21,10 +21,15 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/ioctl.h>
+#ifdef __OpenBSD__
+#include <soundcard.h>
+#else
 #include <sys/soundcard.h>
+#endif
 #include "vl.h"
 
 #define AUDIO_CAP "oss"
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index f2a6896..11edab0 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -25,6 +25,13 @@
 #include <SDL_thread.h>
 #include "vl.h"
 
+#ifndef _WIN32
+#ifdef __sun__
+#define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+#include <signal.h>
+#endif
+
 #define AUDIO_CAP "sdl"
 #include "audio_int.h"
 
@@ -177,11 +184,22 @@
 static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
 {
     int status;
+#ifndef _WIN32
+    sigset_t new, old;
+
+    /* Make sure potential threads created by SDL don't hog signals.  */
+    sigfillset (&new);
+    pthread_sigmask (SIG_BLOCK, &new, &old);
+#endif
 
     status = SDL_OpenAudio (req, obt);
     if (status) {
         sdl_logerr ("SDL_OpenAudio failed\n");
     }
+
+#ifndef _WIN32
+    pthread_sigmask (SIG_SETMASK, &old, 0);
+#endif
     return status;
 }
 
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index 911aa2a..0a800f1 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -41,7 +41,8 @@
     {
         44100,
         2,
-        AUD_FMT_S16
+        AUD_FMT_S16,
+        AUDIO_HOST_ENDIANNESS
     },
     "qemu.wav"
 };
@@ -131,6 +132,11 @@
     case AUD_FMT_U16:
         bits16 = 1;
         break;
+
+    case AUD_FMT_S32:
+    case AUD_FMT_U32:
+        dolog ("WAVE files can not handle 32bit formats\n");
+        return -1;
     }
 
     hdr[34] = bits16 ? 0x10 : 0x08;
diff --git a/audio/wavcapture.c b/audio/wavcapture.c
index 1ebf12f..627ba83 100644
--- a/audio/wavcapture.c
+++ b/audio/wavcapture.c
@@ -37,15 +37,15 @@
     if (wav->f) {
         le_store (rlen, rifflen, 4);
         le_store (dlen, datalen, 4);
-        
+
         qemu_fseek (wav->f, 4, SEEK_SET);
         qemu_put_buffer (wav->f, rlen, 4);
-        
+
         qemu_fseek (wav->f, 32, SEEK_CUR);
         qemu_put_buffer (wav->f, dlen, 4);
         qemu_fclose (wav->f);
     }
-    
+
     qemu_free (wav->path);
 }
 
diff --git a/block-bochs.c b/block-bochs.c
index 35e2a6c..9baea9b 100644
--- a/block-bochs.c
+++ b/block-bochs.c
@@ -1,9 +1,9 @@
 /*
  * Block driver for the various disk image formats used by Bochs
  * Currently only for "growing" type in read-only mode
- * 
+ *
  * Copyright (c) 2005 Alex Beregszaszi
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -44,7 +44,7 @@
     char subtype[16]; // "Undoable" / "Volatile" / "Growing"
     uint32_t version;
     uint32_t header; // size of header
-    
+
     union {
 	struct {
 	    uint32_t catalog; // num of entries
@@ -64,7 +64,7 @@
     char subtype[16]; // "Undoable" / "Volatile" / "Growing"
     uint32_t version;
     uint32_t header; // size of header
-    
+
     union {
 	struct {
 	    uint32_t catalog; // num of entries
@@ -83,9 +83,9 @@
 
     uint32_t *catalog_bitmap;
     int catalog_size;
-    
+
     int data_offset;
-    
+
     int bitmap_blocks;
     int extent_blocks;
     int extent_size;
@@ -94,7 +94,7 @@
 static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     const struct bochs_header *bochs = (const void *)buf;
-    
+
     if (buf_size < HEADER_SIZE)
 	return 0;
 
@@ -121,9 +121,9 @@
         if (fd < 0)
             return -1;
     }
-    
+
     bs->read_only = 1; // no write support yet
-    
+
     s->fd = fd;
 
     if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) {
@@ -161,7 +161,7 @@
 
     s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
     s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
-    
+
     s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
 
     return 0;
@@ -180,7 +180,7 @@
     // seek to sector
     extent_index = offset / s->extent_size;
     extent_offset = (offset % s->extent_size) / 512;
-    
+
     if (s->catalog_bitmap[extent_index] == 0xffffffff)
     {
 //	fprintf(stderr, "page not allocated [%x - %x:%x]\n",
@@ -191,17 +191,17 @@
     bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
 	(s->extent_blocks + s->bitmap_blocks));
     block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
-    
+
 //    fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
 //	sector_num, extent_index, extent_offset,
 //	le32_to_cpu(s->catalog_bitmap[extent_index]),
 //	bitmap_offset, block_offset);
-    
+
     // read in bitmap for current extent
     lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET);
-    
+
     read(s->fd, &bitmap_entry, 1);
-    
+
     if (!((bitmap_entry >> (extent_offset % 8)) & 1))
     {
 //	fprintf(stderr, "sector (%x) in bitmap not allocated\n",
@@ -210,11 +210,11 @@
     }
 
     lseek(s->fd, block_offset, SEEK_SET);
-    
+
     return 0;
 }
 
-static int bochs_read(BlockDriverState *bs, int64_t sector_num, 
+static int bochs_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVBochsState *s = bs->opaque;
diff --git a/block-cloop.c b/block-cloop.c
index f51c32d..0c9ddb3 100644
--- a/block-cloop.c
+++ b/block-cloop.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Block driver for CLOOP images
- * 
+ *
  * Copyright (c) 2004 Johannes E. Schindelin
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -96,7 +96,7 @@
     if(inflateInit(&s->zstream) != Z_OK)
 	goto cloop_close;
     s->current_block=s->n_blocks;
-    
+
     s->sectors_per_block = s->block_size/512;
     bs->total_sectors = s->n_blocks*s->sectors_per_block;
     return 0;
@@ -107,12 +107,12 @@
     if(s->current_block != block_num) {
 	int ret;
         uint32_t bytes = s->offsets[block_num+1]-s->offsets[block_num];
-	    
+
 	lseek(s->fd, s->offsets[block_num], SEEK_SET);
         ret = read(s->fd, s->compressed_block, bytes);
-        if (ret != bytes) 
+        if (ret != bytes)
             return -1;
-	
+
 	s->zstream.next_in = s->compressed_block;
 	s->zstream.avail_in = bytes;
 	s->zstream.next_out = s->uncompressed_block;
@@ -123,13 +123,13 @@
 	ret = inflate(&s->zstream, Z_FINISH);
 	if(ret != Z_STREAM_END || s->zstream.total_out != s->block_size)
 	    return -1;
-	
+
 	s->current_block = block_num;
     }
     return 0;
 }
 
-static int cloop_read(BlockDriverState *bs, int64_t sector_num, 
+static int cloop_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVCloopState *s = bs->opaque;
diff --git a/block-cow.c b/block-cow.c
index 07c8a7b..47a91e5 100644
--- a/block-cow.c
+++ b/block-cow.c
@@ -1,8 +1,8 @@
 /*
  * Block driver for the COW format
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -56,7 +56,7 @@
 
     if (buf_size >= sizeof(struct cow_header_v2) &&
         be32_to_cpu(cow_header->magic) == COW_MAGIC &&
-        be32_to_cpu(cow_header->version) == COW_VERSION) 
+        be32_to_cpu(cow_header->version) == COW_VERSION)
         return 100;
     else
         return 0;
@@ -85,18 +85,18 @@
         be32_to_cpu(cow_header.version) != COW_VERSION) {
         goto fail;
     }
-        
+
     /* cow image found */
     size = be64_to_cpu(cow_header.size);
     bs->total_sectors = size / 512;
 
-    pstrcpy(bs->backing_file, sizeof(bs->backing_file), 
+    pstrcpy(bs->backing_file, sizeof(bs->backing_file),
             cow_header.backing_file);
-    
+
     /* mmap the bitmap */
     s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
-    s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size), 
-                              s->cow_bitmap_size, 
+    s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
+                              s->cow_bitmap_size,
                               PROT_READ | PROT_WRITE,
                               MAP_SHARED, s->fd, 0);
     if (s->cow_bitmap_addr == MAP_FAILED)
@@ -143,24 +143,24 @@
     return changed;
 }
 
-static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num, 
+static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
                             int nb_sectors, int *pnum)
 {
     BDRVCowState *s = bs->opaque;
     return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
 }
 
-static int cow_read(BlockDriverState *bs, int64_t sector_num, 
+static int cow_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVCowState *s = bs->opaque;
     int ret, n;
-    
+
     while (nb_sectors > 0) {
         if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
             lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
             ret = read(s->fd, buf, n * 512);
-            if (ret != n * 512) 
+            if (ret != n * 512)
                 return -1;
         } else {
             if (bs->backing_hd) {
@@ -179,15 +179,15 @@
     return 0;
 }
 
-static int cow_write(BlockDriverState *bs, int64_t sector_num, 
+static int cow_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
     BDRVCowState *s = bs->opaque;
     int ret, i;
-    
+
     lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
     ret = write(s->fd, buf, nb_sectors * 512);
-    if (ret != nb_sectors * 512) 
+    if (ret != nb_sectors * 512)
         return -1;
     for (i = 0; i < nb_sectors; i++)
         cow_set_bit(s->cow_bitmap, sector_num + i);
@@ -211,7 +211,7 @@
     if (flags)
         return -ENOTSUP;
 
-    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
+    cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
     if (cow_fd < 0)
         return -1;
diff --git a/block-dmg.c b/block-dmg.c
index a883a23..681f4dc 100644
--- a/block-dmg.c
+++ b/block-dmg.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Block driver for DMG images
- * 
+ *
  * Copyright (c) 2004 Johannes E. Schindelin
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -28,7 +28,7 @@
 
 typedef struct BDRVDMGState {
     int fd;
-    
+
     /* each chunk contains a certain number of sectors,
      * offsets[i] is the offset in the .dmg file,
      * lengths[i] is the length of the compressed chunk,
@@ -86,7 +86,7 @@
     bs->read_only = 1;
     s->n_chunks = 0;
     s->offsets = s->lengths = s->sectors = s->sectorcounts = 0;
-    
+
     /* read offset of info blocks */
     if(lseek(s->fd,-0x1d8,SEEK_END)<0) {
 dmg_close:
@@ -167,7 +167,7 @@
 	goto dmg_close;
 
     s->current_chunk = s->n_chunks;
-    
+
     return 0;
 }
 
@@ -227,7 +227,7 @@
 
 	    if (ret != s->lengths[chunk])
 		return -1;
-	
+
 	    s->zstream.next_in = s->compressed_chunk;
 	    s->zstream.avail_in = s->lengths[chunk];
 	    s->zstream.next_out = s->uncompressed_chunk;
@@ -253,7 +253,7 @@
     return 0;
 }
 
-static int dmg_read(BlockDriverState *bs, int64_t sector_num, 
+static int dmg_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVDMGState *s = bs->opaque;
diff --git a/block-parallels.c b/block-parallels.c
new file mode 100644
index 0000000..b0fb99c
--- /dev/null
+++ b/block-parallels.c
@@ -0,0 +1,176 @@
+/*
+ * Block driver for Parallels disk image format
+ *
+ * Copyright (c) 2007 Alex Beregszaszi
+ *
+ * This code is based on comparing different disk images created by Parallels.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+#include "block_int.h"
+
+/**************************************************************/
+
+#define HEADER_MAGIC "WithoutFreeSpace"
+#define HEADER_VERSION 2
+#define HEADER_SIZE 64
+
+// always little-endian
+struct parallels_header {
+    char magic[16]; // "WithoutFreeSpace"
+    uint32_t version;
+    uint32_t heads;
+    uint32_t cylinders;
+    uint32_t tracks;
+    uint32_t catalog_entries;
+    uint32_t nb_sectors;
+    char padding[24];
+} __attribute__((packed));
+
+typedef struct BDRVParallelsState {
+    int fd;
+
+    uint32_t *catalog_bitmap;
+    int catalog_size;
+
+    int tracks;
+} BDRVParallelsState;
+
+static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
+{
+    const struct parallels_header *ph = (const void *)buf;
+
+    if (buf_size < HEADER_SIZE)
+	return 0;
+
+    if (!memcmp(ph->magic, HEADER_MAGIC, 16) &&
+	(le32_to_cpu(ph->version) == HEADER_VERSION))
+	return 100;
+
+    return 0;
+}
+
+static int parallels_open(BlockDriverState *bs, const char *filename, int flags)
+{
+    BDRVParallelsState *s = bs->opaque;
+    int fd, i;
+    struct parallels_header ph;
+
+    fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
+    if (fd < 0) {
+        fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
+        if (fd < 0)
+            return -1;
+    }
+
+    bs->read_only = 1; // no write support yet
+
+    s->fd = fd;
+
+    if (read(fd, &ph, sizeof(ph)) != sizeof(ph))
+        goto fail;
+
+    if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
+	(le32_to_cpu(ph.version) != HEADER_VERSION)) {
+        goto fail;
+    }
+
+    bs->total_sectors = le32_to_cpu(ph.nb_sectors);
+
+    if (lseek(s->fd, 64, SEEK_SET) != 64)
+	goto fail;
+
+    s->tracks = le32_to_cpu(ph.tracks);
+
+    s->catalog_size = le32_to_cpu(ph.catalog_entries);
+    s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
+    if (!s->catalog_bitmap)
+	goto fail;
+    if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
+	s->catalog_size * 4)
+	goto fail;
+    for (i = 0; i < s->catalog_size; i++)
+	le32_to_cpus(&s->catalog_bitmap[i]);
+
+    return 0;
+fail:
+    if (s->catalog_bitmap)
+	qemu_free(s->catalog_bitmap);
+    close(fd);
+    return -1;
+}
+
+static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
+{
+    BDRVParallelsState *s = bs->opaque;
+    uint32_t index, offset, position;
+
+    index = sector_num / s->tracks;
+    offset = sector_num % s->tracks;
+
+    // not allocated
+    if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
+	return -1;
+
+    position = (s->catalog_bitmap[index] + offset) * 512;
+
+//    fprintf(stderr, "sector: %llx index=%x offset=%x pointer=%x position=%x\n",
+//	sector_num, index, offset, s->catalog_bitmap[index], position);
+
+    if (lseek(s->fd, position, SEEK_SET) != position)
+	return -1;
+
+    return 0;
+}
+
+static int parallels_read(BlockDriverState *bs, int64_t sector_num,
+                    uint8_t *buf, int nb_sectors)
+{
+    BDRVParallelsState *s = bs->opaque;
+
+    while (nb_sectors > 0) {
+	if (!seek_to_sector(bs, sector_num)) {
+	    if (read(s->fd, buf, 512) != 512)
+		return -1;
+	} else
+            memset(buf, 0, 512);
+        nb_sectors--;
+        sector_num++;
+        buf += 512;
+    }
+    return 0;
+}
+
+static void parallels_close(BlockDriverState *bs)
+{
+    BDRVParallelsState *s = bs->opaque;
+    qemu_free(s->catalog_bitmap);
+    close(s->fd);
+}
+
+BlockDriver bdrv_parallels = {
+    "parallels",
+    sizeof(BDRVParallelsState),
+    parallels_probe,
+    parallels_open,
+    parallels_read,
+    NULL,
+    parallels_close,
+};
diff --git a/block-qcow.c b/block-qcow.c
index d5333b3..9a0bca0 100644
--- a/block-qcow.c
+++ b/block-qcow.c
@@ -1,8 +1,8 @@
 /*
  * Block driver for the QCOW format
- * 
+ *
  * Copyright (c) 2004-2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -80,10 +80,10 @@
 static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     const QCowHeader *cow_header = (const void *)buf;
-    
+
     if (buf_size >= sizeof(QCowHeader) &&
         be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
-        be32_to_cpu(cow_header->version) == QCOW_VERSION) 
+        be32_to_cpu(cow_header->version) == QCOW_VERSION)
         return 100;
     else
         return 0;
@@ -108,7 +108,7 @@
     be64_to_cpus(&header.size);
     be32_to_cpus(&header.crypt_method);
     be64_to_cpus(&header.l1_table_offset);
-    
+
     if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
         goto fail;
     if (header.size <= 1 || header.cluster_bits < 9)
@@ -134,7 +134,7 @@
     s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
     if (!s->l1_table)
         goto fail;
-    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != 
+    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
         s->l1_size * sizeof(uint64_t))
         goto fail;
     for(i = 0;i < s->l1_size; i++) {
@@ -151,7 +151,7 @@
     if (!s->cluster_data)
         goto fail;
     s->cluster_cache_offset = -1;
-    
+
     /* read the backing file name */
     if (header.backing_file_offset != 0) {
         len = header.backing_file_size;
@@ -177,7 +177,7 @@
     BDRVQcowState *s = bs->opaque;
     uint8_t keybuf[16];
     int len, i;
-    
+
     memset(keybuf, 0, 16);
     len = strlen(key);
     if (len > 16)
@@ -231,7 +231,7 @@
     for(i = 0; i < nb_sectors; i++) {
         ivec.ll[0] = cpu_to_le64(sector_num);
         ivec.ll[1] = 0;
-        AES_cbc_encrypt(in_buf, out_buf, 512, key, 
+        AES_cbc_encrypt(in_buf, out_buf, 512, key,
                         ivec.b, enc);
         sector_num++;
         in_buf += 512;
@@ -248,7 +248,7 @@
  *
  * 2 to allocate a compressed cluster of size
  * 'compressed_size'. 'compressed_size' must be > 0 and <
- * cluster_size 
+ * cluster_size
  *
  * return 0 if not allocated.
  */
@@ -262,7 +262,7 @@
     uint64_t l2_offset, *l2_table, cluster_offset, tmp;
     uint32_t min_count;
     int new_l2_table;
-    
+
     l1_index = offset >> (s->l2_bits + s->cluster_bits);
     l2_offset = s->l1_table[l1_index];
     new_l2_table = 0;
@@ -276,7 +276,7 @@
         /* update the L1 entry */
         s->l1_table[l1_index] = l2_offset;
         tmp = cpu_to_be64(l2_offset);
-        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), 
+        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
                         &tmp, sizeof(tmp)) != sizeof(tmp))
             return 0;
         new_l2_table = 1;
@@ -309,7 +309,7 @@
             s->l2_size * sizeof(uint64_t))
             return 0;
     } else {
-        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != 
+        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
             s->l2_size * sizeof(uint64_t))
             return 0;
     }
@@ -318,7 +318,7 @@
  found:
     l2_index = (offset >> s->cluster_bits) & (s->l2_size - 1);
     cluster_offset = be64_to_cpu(l2_table[l2_index]);
-    if (!cluster_offset || 
+    if (!cluster_offset ||
         ((cluster_offset & QCOW_OFLAG_COMPRESSED) && allocate == 1)) {
         if (!allocate)
             return 0;
@@ -331,54 +331,54 @@
             if (decompress_cluster(s, cluster_offset) < 0)
                 return 0;
             cluster_offset = bdrv_getlength(s->hd);
-            cluster_offset = (cluster_offset + s->cluster_size - 1) & 
+            cluster_offset = (cluster_offset + s->cluster_size - 1) &
                 ~(s->cluster_size - 1);
             /* write the cluster content */
-            if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) != 
+            if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) !=
                 s->cluster_size)
                 return -1;
         } else {
             cluster_offset = bdrv_getlength(s->hd);
             if (allocate == 1) {
                 /* round to cluster size */
-                cluster_offset = (cluster_offset + s->cluster_size - 1) & 
+                cluster_offset = (cluster_offset + s->cluster_size - 1) &
                     ~(s->cluster_size - 1);
                 bdrv_truncate(s->hd, cluster_offset + s->cluster_size);
                 /* if encrypted, we must initialize the cluster
                    content which won't be written */
-                if (s->crypt_method && 
+                if (s->crypt_method &&
                     (n_end - n_start) < s->cluster_sectors) {
                     uint64_t start_sect;
                     start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
                     memset(s->cluster_data + 512, 0x00, 512);
                     for(i = 0; i < s->cluster_sectors; i++) {
                         if (i < n_start || i >= n_end) {
-                            encrypt_sectors(s, start_sect + i, 
-                                            s->cluster_data, 
+                            encrypt_sectors(s, start_sect + i,
+                                            s->cluster_data,
                                             s->cluster_data + 512, 1, 1,
                                             &s->aes_encrypt_key);
-                            if (bdrv_pwrite(s->hd, cluster_offset + i * 512, 
+                            if (bdrv_pwrite(s->hd, cluster_offset + i * 512,
                                             s->cluster_data, 512) != 512)
                                 return -1;
                         }
                     }
                 }
             } else {
-                cluster_offset |= QCOW_OFLAG_COMPRESSED | 
+                cluster_offset |= QCOW_OFLAG_COMPRESSED |
                     (uint64_t)compressed_size << (63 - s->cluster_bits);
             }
         }
         /* update L2 table */
         tmp = cpu_to_be64(cluster_offset);
         l2_table[l2_index] = tmp;
-        if (bdrv_pwrite(s->hd, 
+        if (bdrv_pwrite(s->hd,
                         l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
             return 0;
     }
     return cluster_offset;
 }
 
-static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum)
 {
     BDRVQcowState *s = bs->opaque;
@@ -420,7 +420,7 @@
     inflateEnd(strm);
     return 0;
 }
-                              
+
 static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
 {
     int ret, csize;
@@ -431,7 +431,7 @@
         csize = cluster_offset >> (63 - s->cluster_bits);
         csize &= (s->cluster_size - 1);
         ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize);
-        if (ret != csize) 
+        if (ret != csize)
             return -1;
         if (decompress_buffer(s->cluster_cache, s->cluster_size,
                               s->cluster_data, csize) < 0) {
@@ -444,13 +444,13 @@
 
 #if 0
 
-static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_read(BlockDriverState *bs, int64_t sector_num,
                      uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
     int ret, index_in_cluster, n;
     uint64_t cluster_offset;
-    
+
     while (nb_sectors > 0) {
         cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
         index_in_cluster = sector_num & (s->cluster_sectors - 1);
@@ -472,10 +472,10 @@
             memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
         } else {
             ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
-            if (ret != n * 512) 
+            if (ret != n * 512)
                 return -1;
             if (s->crypt_method) {
-                encrypt_sectors(s, sector_num, buf, buf, n, 0, 
+                encrypt_sectors(s, sector_num, buf, buf, n, 0,
                                 &s->aes_decrypt_key);
             }
         }
@@ -487,32 +487,32 @@
 }
 #endif
 
-static int qcow_write(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
     int ret, index_in_cluster, n;
     uint64_t cluster_offset;
-    
+
     while (nb_sectors > 0) {
         index_in_cluster = sector_num & (s->cluster_sectors - 1);
         n = s->cluster_sectors - index_in_cluster;
         if (n > nb_sectors)
             n = nb_sectors;
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, 
-                                            index_in_cluster, 
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
+                                            index_in_cluster,
                                             index_in_cluster + n);
         if (!cluster_offset)
             return -1;
         if (s->crypt_method) {
             encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
                             &s->aes_encrypt_key);
-            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
+            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
                               s->cluster_data, n * 512);
         } else {
             ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
         }
-        if (ret != n * 512) 
+        if (ret != n * 512)
             return -1;
         nb_sectors -= n;
         sector_num += n;
@@ -529,7 +529,7 @@
     int nb_sectors;
     int n;
     uint64_t cluster_offset;
-    uint8_t *cluster_data; 
+    uint8_t *cluster_data;
     BlockDriverAIOCB *hd_aiocb;
 } QCowAIOCB;
 
@@ -556,8 +556,8 @@
         /* nothing to do */
     } else {
         if (s->crypt_method) {
-            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, 
-                            acb->n, 0, 
+            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
+                            acb->n, 0,
                             &s->aes_decrypt_key);
         }
     }
@@ -572,9 +572,9 @@
         qemu_aio_release(acb);
         return;
     }
-    
+
     /* prepare next AIO request */
-    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 
+    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
                                              0, 0, 0, 0);
     index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
     acb->n = s->cluster_sectors - index_in_cluster;
@@ -597,7 +597,7 @@
         /* add AIO support for compressed blocks ? */
         if (decompress_cluster(s, acb->cluster_offset) < 0)
             goto fail;
-        memcpy(acb->buf, 
+        memcpy(acb->buf,
                s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
         goto redo;
     } else {
@@ -606,7 +606,7 @@
             goto fail;
         }
         acb->hd_aiocb = bdrv_aio_read(s->hd,
-                            (acb->cluster_offset >> 9) + index_in_cluster, 
+                            (acb->cluster_offset >> 9) + index_in_cluster,
                             acb->buf, acb->n, qcow_aio_read_cb, acb);
         if (acb->hd_aiocb == NULL)
             goto fail;
@@ -627,7 +627,7 @@
     acb->buf = buf;
     acb->nb_sectors = nb_sectors;
     acb->n = 0;
-    acb->cluster_offset = 0;    
+    acb->cluster_offset = 0;
 
     qcow_aio_read_cb(acb, 0);
     return &acb->common;
@@ -661,13 +661,13 @@
         qemu_aio_release(acb);
         return;
     }
-    
+
     index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
     acb->n = s->cluster_sectors - index_in_cluster;
     if (acb->n > acb->nb_sectors)
         acb->n = acb->nb_sectors;
-    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, 
-                                        index_in_cluster, 
+    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
+                                        index_in_cluster,
                                         index_in_cluster + acb->n);
     if (!cluster_offset || (cluster_offset & 511) != 0) {
         ret = -EIO;
@@ -681,15 +681,15 @@
                 goto fail;
             }
         }
-        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, 
+        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
                         acb->n, 1, &s->aes_encrypt_key);
         src_buf = acb->cluster_data;
     } else {
         src_buf = acb->buf;
     }
     acb->hd_aiocb = bdrv_aio_write(s->hd,
-                                   (cluster_offset >> 9) + index_in_cluster, 
-                                   src_buf, acb->n, 
+                                   (cluster_offset >> 9) + index_in_cluster,
+                                   src_buf, acb->n,
                                    qcow_aio_write_cb, acb);
     if (acb->hd_aiocb == NULL)
         goto fail;
@@ -701,7 +701,7 @@
 {
     BDRVQcowState *s = bs->opaque;
     QCowAIOCB *acb;
-    
+
     s->cluster_cache_offset = -1; /* disable compressed cache */
 
     acb = qemu_aio_get(bs, cb, opaque);
@@ -712,7 +712,7 @@
     acb->buf = (uint8_t *)buf;
     acb->nb_sectors = nb_sectors;
     acb->n = 0;
-    
+
     qcow_aio_write_cb(acb, 0);
     return &acb->common;
 }
@@ -769,12 +769,12 @@
     l1_size = ((total_size * 512) + (1LL << shift) - 1) >> shift;
 
     header.l1_table_offset = cpu_to_be64(header_size);
-    if (flags) {
+    if (flags & BLOCK_FLAG_ENCRYPT) {
         header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
     } else {
         header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
     }
-    
+
     /* write all the data */
     write(fd, &header, sizeof(header));
     if (backing_file) {
@@ -811,7 +811,7 @@
 
 /* XXX: put compressed sectors first, then all the cluster aligned
    tables to avoid losing bytes in alignment */
-static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
                                  const uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
@@ -830,7 +830,7 @@
     /* best compression, small window, no zlib header */
     memset(&strm, 0, sizeof(strm));
     ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
-                       Z_DEFLATED, -12, 
+                       Z_DEFLATED, -12,
                        9, Z_DEFAULT_STRATEGY);
     if (ret != 0) {
         qemu_free(out_buf);
@@ -856,7 +856,7 @@
         /* could not compress: write normal cluster */
         qcow_write(bs, sector_num, buf, s->cluster_sectors);
     } else {
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, 
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
                                             out_len, 0, 0);
         cluster_offset &= s->cluster_offset_mask;
         if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
@@ -864,7 +864,7 @@
             return -1;
         }
     }
-    
+
     qemu_free(out_buf);
     return 0;
 }
diff --git a/block-qcow2.c b/block-qcow2.c
index 0f7a069..b74fe34 100644
--- a/block-qcow2.c
+++ b/block-qcow2.c
@@ -1,8 +1,8 @@
 /*
  * Block driver for the QCOW version 2 format
- * 
+ *
  * Copyright (c) 2004-2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -34,10 +34,10 @@
   - Memory management by reference counts.
   - Clusters which have a reference count of one have the bit
     QCOW_OFLAG_COPIED to optimize write performance.
-  - Size of compressed clusters is stored in sectors to reduce bit usage 
+  - Size of compressed clusters is stored in sectors to reduce bit usage
     in the cluster offsets.
   - Support for storing additional data (such as the VM state) in the
-    snapshots.  
+    snapshots.
   - If a backing store is used, the cluster size is not constrained
     (could be backported to QCOW).
   - L2 tables have always a size of one cluster.
@@ -45,7 +45,7 @@
 
 //#define DEBUG_ALLOC
 //#define DEBUG_ALLOC2
- 
+
 #define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
 #define QCOW_VERSION 2
 
@@ -152,22 +152,22 @@
 } BDRVQcowState;
 
 static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset);
-static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_read(BlockDriverState *bs, int64_t sector_num,
                      uint8_t *buf, int nb_sectors);
 static int qcow_read_snapshots(BlockDriverState *bs);
 static void qcow_free_snapshots(BlockDriverState *bs);
 static int refcount_init(BlockDriverState *bs);
 static void refcount_close(BlockDriverState *bs);
 static int get_refcount(BlockDriverState *bs, int64_t cluster_index);
-static int update_cluster_refcount(BlockDriverState *bs, 
+static int update_cluster_refcount(BlockDriverState *bs,
                                    int64_t cluster_index,
                                    int addend);
-static void update_refcount(BlockDriverState *bs, 
-                            int64_t offset, int64_t length, 
+static void update_refcount(BlockDriverState *bs,
+                            int64_t offset, int64_t length,
                             int addend);
 static int64_t alloc_clusters(BlockDriverState *bs, int64_t size);
 static int64_t alloc_bytes(BlockDriverState *bs, int size);
-static void free_clusters(BlockDriverState *bs, 
+static void free_clusters(BlockDriverState *bs,
                           int64_t offset, int64_t size);
 #ifdef DEBUG_ALLOC
 static void check_refcounts(BlockDriverState *bs);
@@ -176,10 +176,10 @@
 static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename)
 {
     const QCowHeader *cow_header = (const void *)buf;
-    
+
     if (buf_size >= sizeof(QCowHeader) &&
         be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
-        be32_to_cpu(cow_header->version) == QCOW_VERSION) 
+        be32_to_cpu(cow_header->version) == QCOW_VERSION)
         return 100;
     else
         return 0;
@@ -209,11 +209,11 @@
     be32_to_cpus(&header.refcount_table_clusters);
     be64_to_cpus(&header.snapshots_offset);
     be32_to_cpus(&header.nb_snapshots);
-    
+
     if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION)
         goto fail;
-    if (header.size <= 1 || 
-        header.cluster_bits < 9 || 
+    if (header.size <= 1 ||
+        header.cluster_bits < 9 ||
         header.cluster_bits > 16)
         goto fail;
     if (header.crypt_method > QCOW_CRYPT_AES)
@@ -231,7 +231,7 @@
     s->csize_mask = (1 << (s->cluster_bits - 8)) - 1;
     s->cluster_offset_mask = (1LL << s->csize_shift) - 1;
     s->refcount_table_offset = header.refcount_table_offset;
-    s->refcount_table_size = 
+    s->refcount_table_size =
         header.refcount_table_clusters << (s->cluster_bits - 3);
 
     s->snapshots_offset = header.snapshots_offset;
@@ -249,7 +249,7 @@
     s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t));
     if (!s->l1_table)
         goto fail;
-    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != 
+    if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) !=
         s->l1_size * sizeof(uint64_t))
         goto fail;
     for(i = 0;i < s->l1_size; i++) {
@@ -267,7 +267,7 @@
     if (!s->cluster_data)
         goto fail;
     s->cluster_cache_offset = -1;
-    
+
     if (refcount_init(bs) < 0)
         goto fail;
 
@@ -304,7 +304,7 @@
     BDRVQcowState *s = bs->opaque;
     uint8_t keybuf[16];
     int len, i;
-    
+
     memset(keybuf, 0, 16);
     len = strlen(key);
     if (len > 16)
@@ -358,7 +358,7 @@
     for(i = 0; i < nb_sectors; i++) {
         ivec.ll[0] = cpu_to_le64(sector_num);
         ivec.ll[1] = 0;
-        AES_cbc_encrypt(in_buf, out_buf, 512, key, 
+        AES_cbc_encrypt(in_buf, out_buf, 512, key,
                         ivec.b, enc);
         sector_num++;
         in_buf += 512;
@@ -379,12 +379,12 @@
     if (ret < 0)
         return ret;
     if (s->crypt_method) {
-        encrypt_sectors(s, start_sect + n_start, 
-                        s->cluster_data, 
+        encrypt_sectors(s, start_sect + n_start,
+                        s->cluster_data,
                         s->cluster_data, n, 1,
                         &s->aes_encrypt_key);
     }
-    ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start, 
+    ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start,
                      s->cluster_data, n);
     if (ret < 0)
         return ret;
@@ -451,7 +451,7 @@
 
     /* write new table (align to cluster) */
     new_l1_table_offset = alloc_clusters(bs, new_l1_size2);
-    
+
     for(i = 0; i < s->l1_size; i++)
         new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
     ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2);
@@ -459,7 +459,7 @@
         goto fail;
     for(i = 0; i < s->l1_size; i++)
         new_l1_table[i] = be64_to_cpu(new_l1_table[i]);
-    
+
     /* set new table */
     data64 = cpu_to_be64(new_l1_table_offset);
     if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_table_offset),
@@ -489,7 +489,7 @@
  *
  * 2 to allocate a compressed cluster of size
  * 'compressed_size'. 'compressed_size' must be > 0 and <
- * cluster_size 
+ * cluster_size
  *
  * return 0 if not allocated.
  */
@@ -501,7 +501,7 @@
     BDRVQcowState *s = bs->opaque;
     int min_index, i, j, l1_index, l2_index, ret;
     uint64_t l2_offset, *l2_table, cluster_offset, tmp, old_l2_offset;
-    
+
     l1_index = offset >> (s->l2_bits + s->cluster_bits);
     if (l1_index >= s->l1_size) {
         /* outside l1 table is allowed: we grow the table if needed */
@@ -521,7 +521,7 @@
         /* update the L1 entry */
         s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED;
         tmp = cpu_to_be64(l2_offset | QCOW_OFLAG_COPIED);
-        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), 
+        if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp),
                         &tmp, sizeof(tmp)) != sizeof(tmp))
             return 0;
         min_index = l2_cache_new_entry(bs);
@@ -530,12 +530,12 @@
         if (old_l2_offset == 0) {
             memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
         } else {
-            if (bdrv_pread(s->hd, old_l2_offset, 
+            if (bdrv_pread(s->hd, old_l2_offset,
                            l2_table, s->l2_size * sizeof(uint64_t)) !=
                 s->l2_size * sizeof(uint64_t))
                 return 0;
         }
-        if (bdrv_pwrite(s->hd, l2_offset, 
+        if (bdrv_pwrite(s->hd, l2_offset,
                         l2_table, s->l2_size * sizeof(uint64_t)) !=
             s->l2_size * sizeof(uint64_t))
             return 0;
@@ -563,7 +563,7 @@
         /* not found: load a new entry in the least used one */
         min_index = l2_cache_new_entry(bs);
         l2_table = s->l2_cache + (min_index << s->l2_bits);
-        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != 
+        if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) !=
             s->l2_size * sizeof(uint64_t))
             return 0;
     }
@@ -581,7 +581,7 @@
         /* free the cluster */
         if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
             int nb_csectors;
-            nb_csectors = ((cluster_offset >> s->csize_shift) & 
+            nb_csectors = ((cluster_offset >> s->csize_shift) &
                            s->csize_mask) + 1;
             free_clusters(bs, (cluster_offset & s->cluster_offset_mask) & ~511,
                           nb_csectors * 512);
@@ -600,7 +600,7 @@
            written */
         if ((n_end - n_start) < s->cluster_sectors) {
             uint64_t start_sect;
-            
+
             start_sect = (offset & ~(s->cluster_size - 1)) >> 9;
             ret = copy_sectors(bs, start_sect,
                                cluster_offset, 0, n_start);
@@ -615,22 +615,22 @@
     } else {
         int nb_csectors;
         cluster_offset = alloc_bytes(bs, compressed_size);
-        nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) - 
+        nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
             (cluster_offset >> 9);
-        cluster_offset |= QCOW_OFLAG_COMPRESSED | 
+        cluster_offset |= QCOW_OFLAG_COMPRESSED |
             ((uint64_t)nb_csectors << s->csize_shift);
         /* compressed clusters never have the copied flag */
         tmp = cpu_to_be64(cluster_offset);
     }
     /* update L2 table */
     l2_table[l2_index] = tmp;
-    if (bdrv_pwrite(s->hd, 
+    if (bdrv_pwrite(s->hd,
                     l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp))
         return 0;
     return cluster_offset;
 }
 
-static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_is_allocated(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum)
 {
     BDRVQcowState *s = bs->opaque;
@@ -672,7 +672,7 @@
     inflateEnd(strm);
     return 0;
 }
-                              
+
 static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset)
 {
     int ret, csize, nb_csectors, sector_offset;
@@ -697,7 +697,7 @@
 }
 
 /* handle reading after the end of the backing file */
-static int backing_read1(BlockDriverState *bs, 
+static int backing_read1(BlockDriverState *bs,
                          int64_t sector_num, uint8_t *buf, int nb_sectors)
 {
     int n1;
@@ -711,13 +711,13 @@
     return n1;
 }
 
-static int qcow_read(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_read(BlockDriverState *bs, int64_t sector_num,
                      uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
     int ret, index_in_cluster, n, n1;
     uint64_t cluster_offset;
-    
+
     while (nb_sectors > 0) {
         cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
         index_in_cluster = sector_num & (s->cluster_sectors - 1);
@@ -742,10 +742,10 @@
             memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n);
         } else {
             ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
-            if (ret != n * 512) 
+            if (ret != n * 512)
                 return -1;
             if (s->crypt_method) {
-                encrypt_sectors(s, sector_num, buf, buf, n, 0, 
+                encrypt_sectors(s, sector_num, buf, buf, n, 0,
                                 &s->aes_decrypt_key);
             }
         }
@@ -756,32 +756,32 @@
     return 0;
 }
 
-static int qcow_write(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
     int ret, index_in_cluster, n;
     uint64_t cluster_offset;
-    
+
     while (nb_sectors > 0) {
         index_in_cluster = sector_num & (s->cluster_sectors - 1);
         n = s->cluster_sectors - index_in_cluster;
         if (n > nb_sectors)
             n = nb_sectors;
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0, 
-                                            index_in_cluster, 
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
+                                            index_in_cluster,
                                             index_in_cluster + n);
         if (!cluster_offset)
             return -1;
         if (s->crypt_method) {
             encrypt_sectors(s, sector_num, s->cluster_data, buf, n, 1,
                             &s->aes_encrypt_key);
-            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, 
+            ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512,
                               s->cluster_data, n * 512);
         } else {
             ret = bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512);
         }
-        if (ret != n * 512) 
+        if (ret != n * 512)
             return -1;
         nb_sectors -= n;
         sector_num += n;
@@ -798,7 +798,7 @@
     int nb_sectors;
     int n;
     uint64_t cluster_offset;
-    uint8_t *cluster_data; 
+    uint8_t *cluster_data;
     BlockDriverAIOCB *hd_aiocb;
 } QCowAIOCB;
 
@@ -825,8 +825,8 @@
         /* nothing to do */
     } else {
         if (s->crypt_method) {
-            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf, 
-                            acb->n, 0, 
+            encrypt_sectors(s, acb->sector_num, acb->buf, acb->buf,
+                            acb->n, 0,
                             &s->aes_decrypt_key);
         }
     }
@@ -841,9 +841,9 @@
         qemu_aio_release(acb);
         return;
     }
-    
+
     /* prepare next AIO request */
-    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 
+    acb->cluster_offset = get_cluster_offset(bs, acb->sector_num << 9,
                                              0, 0, 0, 0);
     index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
     acb->n = s->cluster_sectors - index_in_cluster;
@@ -853,10 +853,10 @@
     if (!acb->cluster_offset) {
         if (bs->backing_hd) {
             /* read from the base image */
-            n1 = backing_read1(bs->backing_hd, acb->sector_num, 
+            n1 = backing_read1(bs->backing_hd, acb->sector_num,
                                acb->buf, acb->n);
             if (n1 > 0) {
-                acb->hd_aiocb = bdrv_aio_read(bs->backing_hd, acb->sector_num, 
+                acb->hd_aiocb = bdrv_aio_read(bs->backing_hd, acb->sector_num,
                                     acb->buf, acb->n, qcow_aio_read_cb, acb);
                 if (acb->hd_aiocb == NULL)
                     goto fail;
@@ -872,7 +872,7 @@
         /* add AIO support for compressed blocks ? */
         if (decompress_cluster(s, acb->cluster_offset) < 0)
             goto fail;
-        memcpy(acb->buf, 
+        memcpy(acb->buf,
                s->cluster_cache + index_in_cluster * 512, 512 * acb->n);
         goto redo;
     } else {
@@ -881,7 +881,7 @@
             goto fail;
         }
         acb->hd_aiocb = bdrv_aio_read(s->hd,
-                            (acb->cluster_offset >> 9) + index_in_cluster, 
+                            (acb->cluster_offset >> 9) + index_in_cluster,
                             acb->buf, acb->n, qcow_aio_read_cb, acb);
         if (acb->hd_aiocb == NULL)
             goto fail;
@@ -948,13 +948,13 @@
         qemu_aio_release(acb);
         return;
     }
-    
+
     index_in_cluster = acb->sector_num & (s->cluster_sectors - 1);
     acb->n = s->cluster_sectors - index_in_cluster;
     if (acb->n > acb->nb_sectors)
         acb->n = acb->nb_sectors;
-    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0, 
-                                        index_in_cluster, 
+    cluster_offset = get_cluster_offset(bs, acb->sector_num << 9, 1, 0,
+                                        index_in_cluster,
                                         index_in_cluster + acb->n);
     if (!cluster_offset || (cluster_offset & 511) != 0) {
         ret = -EIO;
@@ -968,15 +968,15 @@
                 goto fail;
             }
         }
-        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf, 
+        encrypt_sectors(s, acb->sector_num, acb->cluster_data, acb->buf,
                         acb->n, 1, &s->aes_encrypt_key);
         src_buf = acb->cluster_data;
     } else {
         src_buf = acb->buf;
     }
     acb->hd_aiocb = bdrv_aio_write(s->hd,
-                                   (cluster_offset >> 9) + index_in_cluster, 
-                                   src_buf, acb->n, 
+                                   (cluster_offset >> 9) + index_in_cluster,
+                                   src_buf, acb->n,
                                    qcow_aio_write_cb, acb);
     if (acb->hd_aiocb == NULL)
         goto fail;
@@ -988,13 +988,13 @@
 {
     BDRVQcowState *s = bs->opaque;
     QCowAIOCB *acb;
-    
+
     s->cluster_cache_offset = -1; /* disable compressed cache */
 
     acb = qcow_aio_setup(bs, sector_num, (uint8_t*)buf, nb_sectors, cb, opaque);
     if (!acb)
         return NULL;
-    
+
     qcow_aio_write_cb(acb, 0);
     return &acb->common;
 }
@@ -1038,7 +1038,7 @@
 
     start = offset & ~(s->cluster_size - 1);
     last = (offset + size - 1)  & ~(s->cluster_size - 1);
-    for(cluster_offset = start; cluster_offset <= last; 
+    for(cluster_offset = start; cluster_offset <= last;
         cluster_offset += s->cluster_size) {
         p = &s->refcount_block[cluster_offset >> s->cluster_bits];
         refcount = be16_to_cpu(*p);
@@ -1054,7 +1054,7 @@
     QCowHeader header;
     uint64_t tmp, offset;
     QCowCreateState s1, *s = &s1;
-    
+
     memset(s, 0, sizeof(*s));
 
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
@@ -1076,7 +1076,7 @@
     s->cluster_size = 1 << s->cluster_bits;
     header.cluster_bits = cpu_to_be32(s->cluster_bits);
     header_size = (header_size + 7) & ~7;
-    if (flags) {
+    if (flags & BLOCK_FLAG_ENCRYPT) {
         header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
     } else {
         header.crypt_method = cpu_to_be32(QCOW_CRYPT_NONE);
@@ -1096,7 +1096,7 @@
     s->refcount_block = qemu_mallocz(s->cluster_size);
     if (!s->refcount_block)
         goto fail;
-    
+
     s->refcount_table_offset = offset;
     header.refcount_table_offset = cpu_to_be64(offset);
     header.refcount_table_clusters = cpu_to_be32(1);
@@ -1111,7 +1111,7 @@
     create_refcount_update(s, s->l1_table_offset, l1_size * sizeof(uint64_t));
     create_refcount_update(s, s->refcount_table_offset, s->cluster_size);
     create_refcount_update(s, s->refcount_block_offset, s->cluster_size);
-    
+
     /* write all the data */
     write(fd, &header, sizeof(header));
     if (backing_file) {
@@ -1124,7 +1124,7 @@
     }
     lseek(fd, s->refcount_table_offset, SEEK_SET);
     write(fd, s->refcount_table, s->cluster_size);
-    
+
     lseek(fd, s->refcount_block_offset, SEEK_SET);
     write(fd, s->refcount_block, s->cluster_size);
 
@@ -1153,7 +1153,7 @@
     ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length);
     if (ret < 0)
         return ret;
-    
+
     l2_cache_reset(bs);
 #endif
     return 0;
@@ -1161,7 +1161,7 @@
 
 /* XXX: put compressed sectors first, then all the cluster aligned
    tables to avoid losing bytes in alignment */
-static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, 
+static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num,
                                  const uint8_t *buf, int nb_sectors)
 {
     BDRVQcowState *s = bs->opaque;
@@ -1189,7 +1189,7 @@
     /* best compression, small window, no zlib header */
     memset(&strm, 0, sizeof(strm));
     ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION,
-                       Z_DEFLATED, -12, 
+                       Z_DEFLATED, -12,
                        9, Z_DEFAULT_STRATEGY);
     if (ret != 0) {
         qemu_free(out_buf);
@@ -1215,7 +1215,7 @@
         /* could not compress: write normal cluster */
         qcow_write(bs, sector_num, buf, s->cluster_sectors);
     } else {
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, 
+        cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
                                             out_len, 0, 0);
         cluster_offset &= s->cluster_offset_mask;
         if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) {
@@ -1223,7 +1223,7 @@
             return -1;
         }
     }
-    
+
     qemu_free(out_buf);
     return 0;
 }
@@ -1238,7 +1238,7 @@
 {
     BDRVQcowState *s = bs->opaque;
     bdi->cluster_size = s->cluster_size;
-    bdi->vm_state_offset = (int64_t)s->l1_vm_state_index << 
+    bdi->vm_state_offset = (int64_t)s->l1_vm_state_index <<
         (s->cluster_bits + s->l2_bits);
     return 0;
 }
@@ -1247,7 +1247,7 @@
 /* snapshot support */
 
 /* update the refcounts of snapshots and the copied flag */
-static int update_snapshot_refcount(BlockDriverState *bs, 
+static int update_snapshot_refcount(BlockDriverState *bs,
                                     int64_t l1_table_offset,
                                     int l1_size,
                                     int addend)
@@ -1256,7 +1256,7 @@
     uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
     int64_t old_offset, old_l2_offset;
     int l2_size, i, j, l1_modified, l2_modified, nb_csectors, refcount;
-    
+
     l2_cache_reset(bs);
 
     l2_table = NULL;
@@ -1268,7 +1268,7 @@
         if (!l1_table)
             goto fail;
         l1_allocated = 1;
-        if (bdrv_pread(s->hd, l1_table_offset, 
+        if (bdrv_pread(s->hd, l1_table_offset,
                        l1_table, l1_size2) != l1_size2)
             goto fail;
         for(i = 0;i < l1_size; i++)
@@ -1278,7 +1278,7 @@
         l1_table = s->l1_table;
         l1_allocated = 0;
     }
-    
+
     l2_size = s->l2_size * sizeof(uint64_t);
     l2_table = qemu_malloc(l2_size);
     if (!l2_table)
@@ -1298,13 +1298,13 @@
                     old_offset = offset;
                     offset &= ~QCOW_OFLAG_COPIED;
                     if (offset & QCOW_OFLAG_COMPRESSED) {
-                        nb_csectors = ((offset >> s->csize_shift) & 
+                        nb_csectors = ((offset >> s->csize_shift) &
                                        s->csize_mask) + 1;
                         if (addend != 0)
                             update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
                                             nb_csectors * 512, addend);
                         /* compressed clusters are never modified */
-                        refcount = 2; 
+                        refcount = 2;
                     } else {
                         if (addend != 0) {
                             refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
@@ -1323,7 +1323,7 @@
                 }
             }
             if (l2_modified) {
-                if (bdrv_pwrite(s->hd, 
+                if (bdrv_pwrite(s->hd,
                                 l2_offset, l2_table, l2_size) != l2_size)
                     goto fail;
             }
@@ -1345,7 +1345,7 @@
     if (l1_modified) {
         for(i = 0; i < l1_size; i++)
             cpu_to_be64s(&l1_table[i]);
-        if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, 
+        if (bdrv_pwrite(s->hd, l1_table_offset, l1_table,
                         l1_size2) != l1_size2)
             goto fail;
         for(i = 0; i < l1_size; i++)
@@ -1455,7 +1455,7 @@
 
     snapshots_offset = alloc_clusters(bs, snapshots_size);
     offset = snapshots_offset;
-    
+
     for(i = 0; i < s->nb_snapshots; i++) {
         sn = s->snapshots + i;
         memset(&h, 0, sizeof(h));
@@ -1465,7 +1465,7 @@
         h.date_sec = cpu_to_be32(sn->date_sec);
         h.date_nsec = cpu_to_be32(sn->date_nsec);
         h.vm_clock_nsec = cpu_to_be64(sn->vm_clock_nsec);
-        
+
         id_str_size = strlen(sn->id_str);
         name_size = strlen(sn->name);
         h.id_str_size = cpu_to_be16(id_str_size);
@@ -1533,7 +1533,7 @@
 {
     BDRVQcowState *s = bs->opaque;
     int i, ret;
-    
+
     ret = find_snapshot_by_id(bs, name);
     if (ret >= 0)
         return ret;
@@ -1545,14 +1545,14 @@
 }
 
 /* if no id is provided, a new one is constructed */
-static int qcow_snapshot_create(BlockDriverState *bs, 
+static int qcow_snapshot_create(BlockDriverState *bs,
                                 QEMUSnapshotInfo *sn_info)
 {
     BDRVQcowState *s = bs->opaque;
     QCowSnapshot *snapshots1, sn1, *sn = &sn1;
     int i, ret;
     uint64_t *l1_table = NULL;
-    
+
     memset(sn, 0, sizeof(*sn));
 
     if (sn_info->id_str[0] == '\0') {
@@ -1590,7 +1590,7 @@
         l1_table[i] = cpu_to_be64(s->l1_table[i]);
     }
     if (bdrv_pwrite(s->hd, sn->l1_table_offset,
-                    l1_table, s->l1_size * sizeof(uint64_t)) != 
+                    l1_table, s->l1_size * sizeof(uint64_t)) !=
         (s->l1_size * sizeof(uint64_t)))
         goto fail;
     qemu_free(l1_table);
@@ -1616,7 +1616,7 @@
 }
 
 /* copy the snapshot 'snapshot_name' into the current disk image */
-static int qcow_snapshot_goto(BlockDriverState *bs, 
+static int qcow_snapshot_goto(BlockDriverState *bs,
                               const char *snapshot_id)
 {
     BDRVQcowState *s = bs->opaque;
@@ -1637,7 +1637,7 @@
     s->l1_size = sn->l1_size;
     l1_size2 = s->l1_size * sizeof(uint64_t);
     /* copy the snapshot l1 table to the current l1 table */
-    if (bdrv_pread(s->hd, sn->l1_table_offset, 
+    if (bdrv_pread(s->hd, sn->l1_table_offset,
                    s->l1_table, l1_size2) != l1_size2)
         goto fail;
     if (bdrv_pwrite(s->hd, s->l1_table_offset,
@@ -1663,7 +1663,7 @@
     BDRVQcowState *s = bs->opaque;
     QCowSnapshot *sn;
     int snapshot_index, ret;
-    
+
     snapshot_index = find_snapshot_by_id_or_name(bs, snapshot_id);
     if (snapshot_index < 0)
         return -ENOENT;
@@ -1693,7 +1693,7 @@
     return 0;
 }
 
-static int qcow_snapshot_list(BlockDriverState *bs, 
+static int qcow_snapshot_list(BlockDriverState *bs,
                               QEMUSnapshotInfo **psn_tab)
 {
     BDRVQcowState *s = bs->opaque;
@@ -1731,7 +1731,7 @@
 {
     BDRVQcowState *s = bs->opaque;
     int ret, refcount_table_size2, i;
-    
+
     s->refcount_block_cache = qemu_malloc(s->cluster_size);
     if (!s->refcount_block_cache)
         goto fail;
@@ -1760,12 +1760,12 @@
 }
 
 
-static int load_refcount_block(BlockDriverState *bs, 
+static int load_refcount_block(BlockDriverState *bs,
                                int64_t refcount_block_offset)
 {
     BDRVQcowState *s = bs->opaque;
     int ret;
-    ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache, 
+    ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache,
                      s->cluster_size);
     if (ret != s->cluster_size)
         return -EIO;
@@ -1790,7 +1790,7 @@
         if (load_refcount_block(bs, refcount_block_offset) < 0)
             return 1;
     }
-    block_index = cluster_index & 
+    block_index = cluster_index &
         ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
     return be16_to_cpu(s->refcount_block_cache[block_index]);
 }
@@ -1812,7 +1812,7 @@
             }
 #ifdef DEBUG_ALLOC2
             printf("alloc_clusters: size=%lld -> %lld\n",
-                   size, 
+                   size,
                    (s->free_cluster_index - nb_clusters) << s->cluster_bits);
 #endif
             return (s->free_cluster_index - nb_clusters) << s->cluster_bits;
@@ -1839,13 +1839,13 @@
     BDRVQcowState *s = bs->opaque;
     int64_t offset, cluster_offset;
     int free_in_cluster;
-    
+
     assert(size > 0 && size <= s->cluster_size);
     if (s->free_byte_offset == 0) {
         s->free_byte_offset = alloc_clusters(bs, s->cluster_size);
     }
  redo:
-    free_in_cluster = s->cluster_size - 
+    free_in_cluster = s->cluster_size -
         (s->free_byte_offset & (s->cluster_size - 1));
     if (size <= free_in_cluster) {
         /* enough space in current cluster */
@@ -1872,7 +1872,7 @@
     return offset;
 }
 
-static void free_clusters(BlockDriverState *bs, 
+static void free_clusters(BlockDriverState *bs,
                           int64_t offset, int64_t size)
 {
     update_refcount(bs, offset, size, -1);
@@ -1886,6 +1886,8 @@
     int64_t table_offset;
     uint64_t data64;
     uint32_t data32;
+    int old_table_size;
+    int64_t old_table_offset;
 
     if (min_size <= s->refcount_table_size)
         return 0;
@@ -1910,14 +1912,14 @@
     new_table = qemu_mallocz(new_table_size2);
     if (!new_table)
         return -ENOMEM;
-    memcpy(new_table, s->refcount_table, 
+    memcpy(new_table, s->refcount_table,
            s->refcount_table_size * sizeof(uint64_t));
     for(i = 0; i < s->refcount_table_size; i++)
         cpu_to_be64s(&new_table[i]);
     /* Note: we cannot update the refcount now to avoid recursion */
     table_offset = alloc_clusters_noref(bs, new_table_size2);
     ret = bdrv_pwrite(s->hd, table_offset, new_table, new_table_size2);
-    if (ret != new_table_size2) 
+    if (ret != new_table_size2)
         goto fail;
     for(i = 0; i < s->refcount_table_size; i++)
         be64_to_cpus(&new_table[i]);
@@ -1931,11 +1933,14 @@
                     &data32, sizeof(data32)) != sizeof(data32))
         goto fail;
     qemu_free(s->refcount_table);
+    old_table_offset = s->refcount_table_offset;
+    old_table_size = s->refcount_table_size;
     s->refcount_table = new_table;
     s->refcount_table_size = new_table_size;
     s->refcount_table_offset = table_offset;
 
     update_refcount(bs, table_offset, new_table_size2, 1);
+    free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t));
     return 0;
  fail:
     free_clusters(bs, table_offset, new_table_size2);
@@ -1945,7 +1950,7 @@
 
 /* addend must be 1 or -1 */
 /* XXX: cache several refcount block clusters ? */
-static int update_cluster_refcount(BlockDriverState *bs, 
+static int update_cluster_refcount(BlockDriverState *bs,
                                    int64_t cluster_index,
                                    int addend)
 {
@@ -1975,8 +1980,8 @@
             return -EINVAL;
         s->refcount_table[refcount_table_index] = offset;
         data64 = cpu_to_be64(offset);
-        ret = bdrv_pwrite(s->hd, s->refcount_table_offset + 
-                          refcount_table_index * sizeof(uint64_t), 
+        ret = bdrv_pwrite(s->hd, s->refcount_table_offset +
+                          refcount_table_index * sizeof(uint64_t),
                           &data64, sizeof(data64));
         if (ret != sizeof(data64))
             return -EINVAL;
@@ -1991,7 +1996,7 @@
         }
     }
     /* we can update the count and save it */
-    block_index = cluster_index & 
+    block_index = cluster_index &
         ((1 << (s->cluster_bits - REFCOUNT_SHIFT)) - 1);
     refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
     refcount += addend;
@@ -2001,50 +2006,50 @@
         s->free_cluster_index = cluster_index;
     }
     s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
-    if (bdrv_pwrite(s->hd, 
-                    refcount_block_offset + (block_index << REFCOUNT_SHIFT), 
+    if (bdrv_pwrite(s->hd,
+                    refcount_block_offset + (block_index << REFCOUNT_SHIFT),
                     &s->refcount_block_cache[block_index], 2) != 2)
         return -EIO;
     return refcount;
 }
 
-static void update_refcount(BlockDriverState *bs, 
-                            int64_t offset, int64_t length, 
+static void update_refcount(BlockDriverState *bs,
+                            int64_t offset, int64_t length,
                             int addend)
 {
     BDRVQcowState *s = bs->opaque;
     int64_t start, last, cluster_offset;
 
 #ifdef DEBUG_ALLOC2
-    printf("update_refcount: offset=%lld size=%lld addend=%d\n", 
+    printf("update_refcount: offset=%lld size=%lld addend=%d\n",
            offset, length, addend);
 #endif
     if (length <= 0)
         return;
     start = offset & ~(s->cluster_size - 1);
     last = (offset + length - 1) & ~(s->cluster_size - 1);
-    for(cluster_offset = start; cluster_offset <= last; 
+    for(cluster_offset = start; cluster_offset <= last;
         cluster_offset += s->cluster_size) {
         update_cluster_refcount(bs, cluster_offset >> s->cluster_bits, addend);
     }
 }
 
 #ifdef DEBUG_ALLOC
-static void inc_refcounts(BlockDriverState *bs, 
-                          uint16_t *refcount_table, 
+static void inc_refcounts(BlockDriverState *bs,
+                          uint16_t *refcount_table,
                           int refcount_table_size,
                           int64_t offset, int64_t size)
 {
     BDRVQcowState *s = bs->opaque;
     int64_t start, last, cluster_offset;
     int k;
-    
+
     if (size <= 0)
         return;
 
     start = offset & ~(s->cluster_size - 1);
     last = (offset + size - 1) & ~(s->cluster_size - 1);
-    for(cluster_offset = start; cluster_offset <= last; 
+    for(cluster_offset = start; cluster_offset <= last;
         cluster_offset += s->cluster_size) {
         k = cluster_offset >> s->cluster_bits;
         if (k < 0 || k >= refcount_table_size) {
@@ -2057,8 +2062,8 @@
     }
 }
 
-static int check_refcounts_l1(BlockDriverState *bs, 
-                              uint16_t *refcount_table, 
+static int check_refcounts_l1(BlockDriverState *bs,
+                              uint16_t *refcount_table,
                               int refcount_table_size,
                               int64_t l1_table_offset, int l1_size,
                               int check_copied)
@@ -2076,12 +2081,12 @@
     l1_table = qemu_malloc(l1_size2);
     if (!l1_table)
         goto fail;
-    if (bdrv_pread(s->hd, l1_table_offset, 
+    if (bdrv_pread(s->hd, l1_table_offset,
                    l1_table, l1_size2) != l1_size2)
         goto fail;
     for(i = 0;i < l1_size; i++)
         be64_to_cpus(&l1_table[i]);
-    
+
     l2_size = s->l2_size * sizeof(uint64_t);
     l2_table = qemu_malloc(l2_size);
     if (!l2_table)
@@ -2108,10 +2113,10 @@
                                    offset >> s->cluster_bits);
                             offset &= ~QCOW_OFLAG_COPIED;
                         }
-                        nb_csectors = ((offset >> s->csize_shift) & 
+                        nb_csectors = ((offset >> s->csize_shift) &
                                        s->csize_mask) + 1;
                         offset &= s->cluster_offset_mask;
-                        inc_refcounts(bs, refcount_table, 
+                        inc_refcounts(bs, refcount_table,
                                       refcount_table_size,
                                       offset & ~511, nb_csectors * 512);
                     } else {
@@ -2123,13 +2128,13 @@
                             }
                         }
                         offset &= ~QCOW_OFLAG_COPIED;
-                        inc_refcounts(bs, refcount_table, 
+                        inc_refcounts(bs, refcount_table,
                                       refcount_table_size,
                                       offset, s->cluster_size);
                     }
                 }
             }
-            inc_refcounts(bs, refcount_table, 
+            inc_refcounts(bs, refcount_table,
                           refcount_table_size,
                           l2_offset,
                           s->cluster_size);
@@ -2160,7 +2165,7 @@
     /* header */
     inc_refcounts(bs, refcount_table, nb_clusters,
                   0, s->cluster_size);
-    
+
     check_refcounts_l1(bs, refcount_table, nb_clusters,
                        s->l1_table_offset, s->l1_size, 1);
 
@@ -2175,7 +2180,7 @@
 
     /* refcount data */
     inc_refcounts(bs, refcount_table, nb_clusters,
-                  s->refcount_table_offset, 
+                  s->refcount_table_offset,
                   s->refcount_table_size * sizeof(uint64_t));
     for(i = 0; i < s->refcount_table_size; i++) {
         int64_t offset;
diff --git a/block-raw.c b/block-raw.c
index 29882e1..2f2e19f 100644
--- a/block-raw.c
+++ b/block-raw.c
@@ -1,8 +1,8 @@
 /*
  * Block driver for RAW files
- * 
+ *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -59,6 +59,14 @@
 
 //#define DEBUG_FLOPPY
 
+#define DEBUG_BLOCK
+#if defined(DEBUG_BLOCK) && !defined(QEMU_TOOL)
+#define DEBUG_BLOCK_PRINT(formatCstr, args...) do { if (loglevel != 0)	\
+    { fprintf(logfile, formatCstr, ##args); fflush(logfile); } } while (0)
+#else
+#define DEBUG_BLOCK_PRINT(formatCstr, args...)
+#endif
+
 #define FTYPE_FILE   0
 #define FTYPE_CD     1
 #define FTYPE_FD     2
@@ -70,6 +78,7 @@
 typedef struct BDRVRawState {
     int fd;
     int type;
+    unsigned int lseek_err_cnt;
 #if defined(__linux__)
     /* linux floppy specific */
     int fd_open_flags;
@@ -87,6 +96,8 @@
     BDRVRawState *s = bs->opaque;
     int fd, open_flags, ret;
 
+    s->lseek_err_cnt = 0;
+
     open_flags = O_BINARY;
     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
         open_flags |= O_RDWR;
@@ -127,33 +138,92 @@
 #endif
 */
 
-static int raw_pread(BlockDriverState *bs, int64_t offset, 
+static int raw_pread(BlockDriverState *bs, int64_t offset,
                      uint8_t *buf, int count)
 {
     BDRVRawState *s = bs->opaque;
     int ret;
-    
+
     ret = fd_open(bs);
     if (ret < 0)
         return ret;
 
-    lseek(s->fd, offset, SEEK_SET);
+    if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+        ++(s->lseek_err_cnt);
+        if(s->lseek_err_cnt <= 10) {
+            DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                              "] lseek failed : %d = %s\n",
+                              s->fd, bs->filename, offset, buf, count,
+                              bs->total_sectors, errno, strerror(errno));
+        }
+        return -1;
+    }
+    s->lseek_err_cnt=0;
+
     ret = read(s->fd, buf, count);
+    if (ret == count)
+        goto label__raw_read__success;
+
+    DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                      "] read failed %d : %d = %s\n",
+                      s->fd, bs->filename, offset, buf, count,
+                      bs->total_sectors, ret, errno, strerror(errno));
+
+    /* Try harder for CDrom. */
+    if (bs->type == BDRV_TYPE_CDROM) {
+        lseek(s->fd, offset, SEEK_SET);
+        ret = read(s->fd, buf, count);
+        if (ret == count)
+            goto label__raw_read__success;
+        lseek(s->fd, offset, SEEK_SET);
+        ret = read(s->fd, buf, count);
+        if (ret == count)
+            goto label__raw_read__success;
+
+        DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                          "] retry read failed %d : %d = %s\n",
+                          s->fd, bs->filename, offset, buf, count,
+                          bs->total_sectors, ret, errno, strerror(errno));
+    }
+
+label__raw_read__success:
+
     return ret;
 }
 
-static int raw_pwrite(BlockDriverState *bs, int64_t offset, 
+static int raw_pwrite(BlockDriverState *bs, int64_t offset,
                       const uint8_t *buf, int count)
 {
     BDRVRawState *s = bs->opaque;
     int ret;
-    
+
     ret = fd_open(bs);
     if (ret < 0)
         return ret;
 
-    lseek(s->fd, offset, SEEK_SET);
+    if (lseek(s->fd, offset, SEEK_SET) == (off_t)-1) {
+        ++(s->lseek_err_cnt);
+        if(s->lseek_err_cnt) {
+            DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%"
+                              PRId64 "] lseek failed : %d = %s\n",
+                              s->fd, bs->filename, offset, buf, count,
+                              bs->total_sectors, errno, strerror(errno));
+        }
+        return -1;
+    }
+    s->lseek_err_cnt = 0;
+
     ret = write(s->fd, buf, count);
+    if (ret == count)
+        goto label__raw_write__success;
+
+    DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
+                      "] write failed %d : %d = %s\n",
+                      s->fd, bs->filename, offset, buf, count,
+                      bs->total_sectors, ret, errno, strerror(errno));
+
+label__raw_write__success:
+
     return ret;
 }
 
@@ -191,7 +261,7 @@
     struct sigaction act;
 
     aio_initialized = 1;
-    
+
     sigfillset(&act.sa_mask);
     act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
     act.sa_handler = aio_signal_handler;
@@ -333,7 +403,7 @@
     if (aio_read(&acb->aiocb) < 0) {
         qemu_aio_release(acb);
         return NULL;
-    } 
+    }
     return &acb->common;
 }
 
@@ -349,7 +419,7 @@
     if (aio_write(&acb->aiocb) < 0) {
         qemu_aio_release(acb);
         return NULL;
-    } 
+    }
     return &acb->common;
 }
 
@@ -454,7 +524,7 @@
     if (flags || backing_file)
         return -ENOTSUP;
 
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
     if (fd < 0)
         return -EIO;
@@ -479,7 +549,7 @@
     raw_close,
     raw_create,
     raw_flush,
-    
+
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
     .bdrv_aio_cancel = raw_aio_cancel,
@@ -500,7 +570,7 @@
 
 kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
 {
-    kern_return_t       kernResult; 
+    kern_return_t       kernResult;
     mach_port_t     masterPort;
     CFMutableDictionaryRef  classesToMatch;
 
@@ -508,8 +578,8 @@
     if ( KERN_SUCCESS != kernResult ) {
         printf( "IOMasterPort returned %d\n", kernResult );
     }
-    
-    classesToMatch = IOServiceMatching( kIOCDMediaClass ); 
+
+    classesToMatch = IOServiceMatching( kIOCDMediaClass );
     if ( classesToMatch == NULL ) {
         printf( "IOServiceMatching returned a NULL dictionary.\n" );
     } else {
@@ -520,7 +590,7 @@
     {
         printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
     }
-    
+
     return kernResult;
 }
 
@@ -546,7 +616,7 @@
         }
         IOObjectRelease( nextMedia );
     }
-    
+
     return kernResult;
 }
 
@@ -563,10 +633,10 @@
         io_iterator_t mediaIterator;
         char bsdPath[ MAXPATHLEN ];
         int fd;
- 
+
         kernResult = FindEjectableCDMedia( &mediaIterator );
         kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
-    
+
         if ( bsdPath[ 0 ] != '\0' ) {
             strcat(bsdPath,"s0");
             /* some CDs don't have a partition 0 */
@@ -578,7 +648,7 @@
             }
             filename = bsdPath;
         }
-        
+
         if ( mediaIterator )
             IOObjectRelease( mediaIterator );
     }
@@ -636,7 +706,7 @@
     if (s->type != FTYPE_FD)
         return 0;
     last_media_present = (s->fd >= 0);
-    if (s->fd >= 0 && 
+    if (s->fd >= 0 &&
         (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
         close(s->fd);
         s->fd = -1;
@@ -645,7 +715,7 @@
 #endif
     }
     if (s->fd < 0) {
-        if (s->fd_got_error && 
+        if (s->fd_got_error &&
             (qemu_get_clock(rt_clock) - s->fd_error_time) < FD_OPEN_TIMEOUT) {
 #ifdef DEBUG_FLOPPY
             printf("No floppy (open delayed)\n");
@@ -815,7 +885,7 @@
     raw_close,
     NULL,
     raw_flush,
-    
+
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
     .bdrv_aio_cancel = raw_aio_cancel,
@@ -911,7 +981,7 @@
 #else
     overlapped = FILE_FLAG_OVERLAPPED;
 #endif
-    s->hfile = CreateFile(filename, access_flags, 
+    s->hfile = CreateFile(filename, access_flags,
                           FILE_SHARE_READ, NULL,
                           create_flags, overlapped, NULL);
     if (s->hfile == INVALID_HANDLE_VALUE) {
@@ -924,14 +994,14 @@
     return 0;
 }
 
-static int raw_pread(BlockDriverState *bs, int64_t offset, 
+static int raw_pread(BlockDriverState *bs, int64_t offset,
                      uint8_t *buf, int count)
 {
     BDRVRawState *s = bs->opaque;
     OVERLAPPED ov;
     DWORD ret_count;
     int ret;
-    
+
     memset(&ov, 0, sizeof(ov));
     ov.Offset = offset;
     ov.OffsetHigh = offset >> 32;
@@ -946,14 +1016,14 @@
     return ret_count;
 }
 
-static int raw_pwrite(BlockDriverState *bs, int64_t offset, 
+static int raw_pwrite(BlockDriverState *bs, int64_t offset,
                       const uint8_t *buf, int count)
 {
     BDRVRawState *s = bs->opaque;
     OVERLAPPED ov;
     DWORD ret_count;
     int ret;
-    
+
     memset(&ov, 0, sizeof(ov));
     ov.Offset = offset;
     ov.OffsetHigh = offset >> 32;
@@ -1103,7 +1173,7 @@
 {
     BDRVRawState *s = bs->opaque;
     LARGE_INTEGER l;
-    ULARGE_INTEGER available, total, total_free; 
+    ULARGE_INTEGER available, total, total_free;
     DISK_GEOMETRY dg;
     DWORD count;
     BOOL status;
@@ -1141,7 +1211,7 @@
     if (flags || backing_file)
         return -ENOTSUP;
 
-    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
+    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
     if (fd < 0)
         return -EIO;
@@ -1188,7 +1258,7 @@
     raw_close,
     raw_create,
     raw_flush,
-    
+
 #if 0
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
@@ -1267,7 +1337,7 @@
         }
     }
     s->type = find_device_type(bs, filename);
-    
+
     if ((flags & BDRV_O_ACCESS) == O_RDWR) {
         access_flags = GENERIC_READ | GENERIC_WRITE;
     } else {
@@ -1280,7 +1350,7 @@
 #else
     overlapped = FILE_FLAG_OVERLAPPED;
 #endif
-    s->hfile = CreateFile(filename, access_flags, 
+    s->hfile = CreateFile(filename, access_flags,
                           FILE_SHARE_READ, NULL,
                           create_flags, overlapped, NULL);
     if (s->hfile == INVALID_HANDLE_VALUE) {
@@ -1295,7 +1365,7 @@
 
 #if 0
 /***********************************************/
-/* removable device additionnal commands */
+/* removable device additional commands */
 
 static int raw_is_inserted(BlockDriverState *bs)
 {
@@ -1314,10 +1384,10 @@
     if (s->type == FTYPE_FILE)
         return -ENOTSUP;
     if (eject_flag) {
-        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA, 
+        DeviceIoControl(s->hfile, IOCTL_STORAGE_EJECT_MEDIA,
                         NULL, 0, NULL, 0, &lpBytesReturned, NULL);
     } else {
-        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA, 
+        DeviceIoControl(s->hfile, IOCTL_STORAGE_LOAD_MEDIA,
                         NULL, 0, NULL, 0, &lpBytesReturned, NULL);
     }
 }
@@ -1338,7 +1408,7 @@
     raw_close,
     NULL,
     raw_flush,
-    
+
 #if 0
     .bdrv_aio_read = raw_aio_read,
     .bdrv_aio_write = raw_aio_write,
diff --git a/block-vmdk.c b/block-vmdk.c
index be75e0d..1f3709c 100644
--- a/block-vmdk.c
+++ b/block-vmdk.c
@@ -1,9 +1,9 @@
 /*
  * Block driver for the VMDK format
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
  * Copyright (c) 2005 Filip Navara
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -75,9 +75,25 @@
 
     unsigned int cluster_sectors;
     uint32_t parent_cid;
+    int is_parent;
     DiskIOStatistics io;
 } BDRVVmdkState;
 
+typedef struct VmdkMetaData {
+    uint32_t offset;
+    unsigned int l1_index;
+    unsigned int l2_index;
+    unsigned int l2_offset;
+    int valid;
+} VmdkMetaData;
+
+typedef struct ActiveBDRVState{
+    BlockDriverState *hd;            // active image handler
+    uint64_t cluster_offset;         // current write offset
+}ActiveBDRVState;
+
+static ActiveBDRVState activeBDRV;
+
 DiskIOStatistics vmdk_io_statistics(BlockDriverState *bs)
 {
     BDRVVmdkState *s = bs->opaque;
@@ -101,16 +117,16 @@
 
 #define CHECK_CID 1
 
-#define SECTOR_SIZE 512				
+#define SECTOR_SIZE 512
 #define DESC_SIZE 20*SECTOR_SIZE	// 20 sectors of 512 bytes each
-#define HEADER_SIZE 512   			// first sector of 512 bytes 
+#define HEADER_SIZE 512   			// first sector of 512 bytes
 
 static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
 {
     BDRVVmdkState *s = bs->opaque;
     char desc[DESC_SIZE];
     uint32_t cid;
-    char *p_name, *cid_str; 
+    char *p_name, *cid_str;
     size_t cid_str_size;
 
     /* the descriptor offset = 0x200 */
@@ -178,7 +194,7 @@
 {
     int snp_fd, p_fd;
     uint32_t p_cid;
-    char *p_name, *gd_buf, *rgd_buf; 
+    char *p_name, *gd_buf, *rgd_buf;
     const char *real_filename, *temp_str;
     VMDK4Header header;
     uint32_t gde_entries, gd_size;
@@ -262,7 +278,7 @@
     gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
     if (!gt_size)
         goto fail;
-    gde_entries = (uint32_t)(capacity / gt_size);  // number of gde/rgde 
+    gde_entries = (uint32_t)(capacity / gt_size);  // number of gde/rgde
     gd_size = gde_entries * sizeof(uint32_t);
 
     /* write RGD */
@@ -299,7 +315,7 @@
 
     fail_gd:
     qemu_free(gd_buf);
-    fail_rgd:   
+    fail_rgd:
     qemu_free(rgd_buf);
     fail:
     close(p_fd);
@@ -313,11 +329,11 @@
         bdrv_close(bs->backing_hd);
 }
 
-
+int parent_open = 0;
 static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
 {
     BDRVVmdkState *s = bs->opaque;
-    char *p_name; 
+    char *p_name;
     char desc[DESC_SIZE];
     char parent_img_name[1024];
 
@@ -332,7 +348,7 @@
         p_name += sizeof("parentFileNameHint") + 1;
         if ((end_name = strchr(p_name,'\"')) == 0)
             return -1;
-                
+
         strncpy(s->hd->backing_file, p_name, end_name - p_name);
         if (stat(s->hd->backing_file, &file_buf) != 0) {
             path_combine(parent_img_name, sizeof(parent_img_name),
@@ -347,8 +363,10 @@
             bdrv_close(s->hd);
             return -1;
         }
-        if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0)
+        parent_open = 1;
+        if (bdrv_open(s->hd->backing_hd, parent_img_name, BDRV_O_RDONLY) < 0)
             goto failure;
+        parent_open = 0;
     }
 
     return 0;
@@ -360,6 +378,11 @@
     uint32_t magic;
     int l1_size, i, ret;
 
+    if (parent_open)
+        // Parent must be opened as RO.
+        flags = BDRV_O_RDONLY;
+    fprintf(stderr, "(VMDK) image open: flags=0x%x filename=%s\n", flags, bs->filename);
+
     ret = bdrv_file_open(&s->hd, filename, flags);
     if (ret < 0)
         return ret;
@@ -390,11 +413,16 @@
         s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
         if (s->l1_entry_sectors <= 0)
             goto fail;
-        s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1) 
+        s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
             / s->l1_entry_sectors;
         s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
         s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
 
+        if (parent_open)
+            s->is_parent = 1;
+        else
+            s->is_parent = 0;
+
         // try to open parent images, if exist
         if (vmdk_parent_open(bs, filename) != 0)
             goto fail;
@@ -438,7 +466,8 @@
     return -1;
 }
 
-static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate);
+static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
+                                   uint64_t offset, int allocate);
 
 static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
                              uint64_t offset, int allocate)
@@ -454,27 +483,54 @@
 
         if (!vmdk_is_cid_valid(bs))
             return -1;
-        parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, allocate);
-        if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != 
-                                                                            ps->cluster_sectors*512)
-            return -1;
 
-        if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, sizeof(whole_grain)) != 
-                                                                            sizeof(whole_grain))
-            return -1;
+        parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, NULL, offset, allocate);
+
+        if (parent_cluster_offset) {
+            BDRVVmdkState *act_s = activeBDRV.hd->opaque;
+
+            if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512)
+                return -1;
+
+            //Write grain only into the active image
+            if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain))
+                return -1;
+        }
     }
     return 0;
 }
 
-static uint64_t get_cluster_offset(BlockDriverState *bs,
+static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data)
+{
+    BDRVVmdkState *s = bs->opaque;
+
+    /* update L2 table */
+    if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
+                    &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
+        return -1;
+    /* update backup L2 table */
+    if (s->l1_backup_table_offset != 0) {
+        m_data->l2_offset = s->l1_backup_table[m_data->l1_index];
+        if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)),
+                        &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset))
+            return -1;
+    }
+
+    return 0;
+}
+
+static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data,
                                    uint64_t offset, int allocate)
 {
     BDRVVmdkState *s = bs->opaque;
     unsigned int l1_index, l2_offset, l2_index;
     int min_index, i, j;
-    uint32_t min_count, *l2_table, tmp;
+    uint32_t min_count, *l2_table, tmp = 0;
     uint64_t cluster_offset;
-    
+
+    if (m_data)
+        m_data->valid = 0;
+
     l1_index = (offset >> 9) / s->l1_entry_sectors;
     if (l1_index >= s->l1_size)
         return 0;
@@ -503,7 +559,7 @@
         }
     }
     l2_table = s->l2_cache + (min_index * s->l2_size);
-    if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != 
+    if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
                                                                         s->l2_size * sizeof(uint32_t))
         return 0;
 
@@ -512,45 +568,50 @@
  found:
     l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
     cluster_offset = le32_to_cpu(l2_table[l2_index]);
-    if (!cluster_offset) {
-        struct stat file_buf;
 
+    if (!cluster_offset) {
         if (!allocate)
             return 0;
-        stat(s->hd->filename, &file_buf);
-        cluster_offset = file_buf.st_size;
-        bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
+        // Avoid the L2 tables update for the images that have snapshots.
+        if (!s->is_parent) {
+            cluster_offset = bdrv_getlength(s->hd);
+            bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
 
-        cluster_offset >>= 9;
-        /* update L2 table */
-        tmp = cpu_to_le32(cluster_offset);
-        l2_table[l2_index] = tmp;
-        if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), 
-                        &tmp, sizeof(tmp)) != sizeof(tmp))
-            return 0;
-        /* update backup L2 table */
-        if (s->l1_backup_table_offset != 0) {
-            l2_offset = s->l1_backup_table[l1_index];
-            if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), 
-                            &tmp, sizeof(tmp)) != sizeof(tmp))
-                return 0;
+            cluster_offset >>= 9;
+            tmp = cpu_to_le32(cluster_offset);
+            l2_table[l2_index] = tmp;
+            // Save the active image state
+            activeBDRV.cluster_offset = cluster_offset;
+            activeBDRV.hd = bs;
         }
-
+        /* First of all we write grain itself, to avoid race condition
+         * that may to corrupt the image.
+         * This problem may occur because of insufficient space on host disk
+         * or inappropriate VM shutdown.
+         */
         if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
             return 0;
+
+        if (m_data) {
+            m_data->offset = tmp;
+            m_data->l1_index = l1_index;
+            m_data->l2_index = l2_index;
+            m_data->l2_offset = l2_offset;
+            m_data->valid = 1;
+        }
     }
     cluster_offset <<= 9;
     return cluster_offset;
 }
 
-static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num, 
+static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
                              int nb_sectors, int *pnum)
 {
     BDRVVmdkState *s = bs->opaque;
     int index_in_cluster, n;
     uint64_t cluster_offset;
 
-    cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
+    cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
     index_in_cluster = sector_num % s->cluster_sectors;
     n = s->cluster_sectors - index_in_cluster;
     if (n > nb_sectors)
@@ -559,7 +620,7 @@
     return (cluster_offset != 0);
 }
 
-static int vmdk_read(BlockDriverState *bs, int64_t sector_num, 
+static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVVmdkState *s = bs->opaque;
@@ -567,7 +628,7 @@
     uint64_t cluster_offset;
 
     while (nb_sectors > 0) {
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
+        cluster_offset = get_cluster_offset(bs, NULL, sector_num << 9, 0);
         index_in_cluster = sector_num % s->cluster_sectors;
         n = s->cluster_sectors - index_in_cluster;
         if (n > nb_sectors)
@@ -595,24 +656,39 @@
     return 0;
 }
 
-static int vmdk_write(BlockDriverState *bs, int64_t sector_num, 
+static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
                      const uint8_t *buf, int nb_sectors)
 {
     BDRVVmdkState *s = bs->opaque;
+    VmdkMetaData m_data;
     int index_in_cluster, n;
     uint64_t cluster_offset;
     static int cid_update = 0;
 
+    if (sector_num > bs->total_sectors) {
+        fprintf(stderr,
+                "(VMDK) Wrong offset: sector_num=0x%" PRIx64
+                " total_sectors=0x%" PRIx64 "\n",
+                sector_num, bs->total_sectors);
+        return -1;
+    }
+
     while (nb_sectors > 0) {
         index_in_cluster = sector_num & (s->cluster_sectors - 1);
         n = s->cluster_sectors - index_in_cluster;
         if (n > nb_sectors)
             n = nb_sectors;
-        cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
+        cluster_offset = get_cluster_offset(bs, &m_data, sector_num << 9, 1);
         if (!cluster_offset)
             return -1;
+
         if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
             return -1;
+        if (m_data.valid) {
+            /* update L2 tables */
+            if (vmdk_L2update(bs, &m_data) == -1)
+                return -1;
+        }
         nb_sectors -= n;
         sector_num += n;
         buf += n * 512;
@@ -646,7 +722,7 @@
         "# The Disk Data Base \n"
         "#DDB\n"
         "\n"
-        "ddb.virtualHWVersion = \"4\"\n"
+        "ddb.virtualHWVersion = \"%d\"\n"
         "ddb.geometry.cylinders = \"%lu\"\n"
         "ddb.geometry.heads = \"16\"\n"
         "ddb.geometry.sectors = \"63\"\n"
@@ -695,8 +771,8 @@
     header.check_bytes[1] = 0x20;
     header.check_bytes[2] = 0xd;
     header.check_bytes[3] = 0xa;
-    
-    /* write all the data */    
+
+    /* write all the data */
     write(fd, &magic, sizeof(magic));
     write(fd, &header, sizeof(header));
 
@@ -707,7 +783,7 @@
     for (i = 0, tmp = header.rgd_offset + gd_size;
          i < gt_count; i++, tmp += gt_size)
         write(fd, &tmp, sizeof(tmp));
-   
+
     /* write backup grain directory */
     lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
     for (i = 0, tmp = header.gd_offset + gd_size;
@@ -723,7 +799,7 @@
     if ((temp_str = strrchr(real_filename, ':')) != NULL)
         real_filename = temp_str + 1;
     sprintf(desc, desc_template, time(NULL), (unsigned long)total_size,
-            real_filename, total_size / (63 * 16));
+            real_filename, (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), total_size / (63 * 16));
 
     /* write the descriptor */
     lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
diff --git a/block-vpc.c b/block-vpc.c
index 4d228c5..be74c29 100644
--- a/block-vpc.c
+++ b/block-vpc.c
@@ -1,8 +1,8 @@
 /*
  * Block driver for Conectix/Microsoft Virtual PC images
- * 
+ *
  * Copyright (c) 2005 Alex Beregszaszi
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -65,7 +65,7 @@
 
 typedef struct BDRVVPCState {
     int fd;
-    
+
     int pagetable_entries;
     uint32_t *pagetable;
 
@@ -74,7 +74,7 @@
     uint8_t *pageentry_u8;
     uint32_t *pageentry_u32;
     uint16_t *pageentry_u16;
-    
+
     uint64_t last_bitmap;
 #endif
 } BDRVVPCState;
@@ -97,7 +97,7 @@
         return -1;
 
     bs->read_only = 1; // no write support yet
-    
+
     s->fd = fd;
 
     if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
@@ -153,13 +153,13 @@
 
     pagetable_index = offset / s->pageentry_size;
     pageentry_index = (offset % s->pageentry_size) / 512;
-    
+
     if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
 	return -1; // not allocated
 
     bitmap_offset = 512 * s->pagetable[pagetable_index];
     block_offset = bitmap_offset + 512 + (512 * pageentry_index);
-    
+
 //    printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
 //	sector_num, pagetable_index, pageentry_index,
 //	bitmap_offset, block_offset);
@@ -172,7 +172,7 @@
 	lseek(s->fd, bitmap_offset, SEEK_SET);
 
 	s->last_bitmap = bitmap_offset;
-	
+
 	// Scary! Bitmap is stored as big endian 32bit entries,
 	// while we used to look it up byte by byte
 	read(s->fd, s->pageentry_u8, 512);
@@ -184,7 +184,7 @@
 	return -1;
 #else
     lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
-	
+
     read(s->fd, &bitmap_entry, 1);
 
     if ((bitmap_entry >> (pageentry_index % 8)) & 1)
@@ -196,7 +196,7 @@
     return 0;
 }
 
-static int vpc_read(BlockDriverState *bs, int64_t sector_num, 
+static int vpc_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVVPCState *s = bs->opaque;
diff --git a/block-vvfat.c b/block-vvfat.c
index 48a52e3..3237c26 100644
--- a/block-vvfat.c
+++ b/block-vvfat.c
@@ -1,9 +1,9 @@
 /* vim:set shiftwidth=4 ts=8: */
 /*
  * QEMU Block driver for virtual VFAT (shadows a local directory)
- * 
+ *
  * Copyright (c) 2004,2005 Johannes E. Schindelin
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -38,7 +38,7 @@
 /* TODO: add ":bootsector=blabla.img:" */
 /* LATER TODO: add automatic boot sector generation from
     BOOTEASY.ASM and Ranish Partition Manager
-    Note that DOS assumes the system files to be the first files in the 
+    Note that DOS assumes the system files to be the first files in the
     file system (test if the boot sector still relies on that fact)! */
 /* MAYBE TODO: write block-visofs.c */
 /* TODO: call try_commit() only after a timeout */
@@ -153,7 +153,7 @@
 	    index_to<0 || index_to>=array->next ||
 	    index_from<0 || index_from>=array->next)
 	return -1;
-    
+
     if(index_to==index_from)
 	return 0;
 
@@ -167,7 +167,7 @@
 	memmove(to+is*count,to,from-to);
     else
 	memmove(from,from+is*count,to-from);
-    
+
     memcpy(to,buf,is*count);
 
     free(buf);
@@ -242,21 +242,25 @@
     uint8_t magic[2];
 } __attribute__((packed)) bootsector_t;
 
+typedef struct {
+    uint8_t head;
+    uint8_t sector;
+    uint8_t cylinder;
+} mbr_chs_t;
+
 typedef struct partition_t {
     uint8_t attributes; /* 0x80 = bootable */
-    uint8_t start_head;
-    uint8_t start_sector;
-    uint8_t start_cylinder;
-    uint8_t fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xb = FAT32 */
-    uint8_t end_head;
-    uint8_t end_sector;
-    uint8_t end_cylinder;
+    mbr_chs_t start_CHS;
+    uint8_t   fs_type; /* 0x1 = FAT12, 0x6 = FAT16, 0xe = FAT16_LBA, 0xb = FAT32, 0xc = FAT32_LBA */
+    mbr_chs_t end_CHS;
     uint32_t start_sector_long;
-    uint32_t end_sector_long;
+    uint32_t length_sector_long;
 } __attribute__((packed)) partition_t;
 
 typedef struct mbr_t {
-    uint8_t ignored[0x1be];
+    uint8_t ignored[0x1b8];
+    uint32_t nt_id;
+    uint8_t ignored2[2];
     partition_t partition[4];
     uint8_t magic[2];
 } __attribute__((packed)) mbr_t;
@@ -319,10 +323,10 @@
     BlockDriverState* bs; /* pointer to parent */
     unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
     unsigned char first_sectors[0x40*0x200];
-    
+
     int fat_type; /* 16 or 32 */
     array_t fat,directory,mapping;
-   
+
     unsigned int cluster_size;
     unsigned int sectors_per_cluster;
     unsigned int sectors_per_fat;
@@ -332,7 +336,7 @@
     uint32_t sector_count; /* total number of sectors of the partition */
     uint32_t cluster_count; /* total number of clusters of this partition */
     uint32_t max_fat_value;
-   
+
     int current_fd;
     mapping_t* current_mapping;
     unsigned char* cluster; /* points to current cluster */
@@ -350,26 +354,57 @@
     int downcase_short_names;
 } BDRVVVFATState;
 
+/* take the sector position spos and convert it to Cylinder/Head/Sector position
+ * if the position is outside the specified geometry, fill maximum value for CHS
+ * and return 1 to signal overflow.
+ */
+static int sector2CHS(BlockDriverState* bs, mbr_chs_t * chs, int spos){
+    int head,sector;
+    sector   = spos % (bs->secs);  spos/= bs->secs;
+    head     = spos % (bs->heads); spos/= bs->heads;
+    if(spos >= bs->cyls){
+        /* Overflow,
+        it happens if 32bit sector positions are used, while CHS is only 24bit.
+        Windows/Dos is said to take 1023/255/63 as nonrepresentable CHS */
+        chs->head     = 0xFF;
+        chs->sector   = 0xFF;
+        chs->cylinder = 0xFF;
+        return 1;
+    }
+    chs->head     = (uint8_t)head;
+    chs->sector   = (uint8_t)( (sector+1) | ((spos>>8)<<6) );
+    chs->cylinder = (uint8_t)spos;
+    return 0;
+}
 
 static void init_mbr(BDRVVVFATState* s)
 {
     /* TODO: if the files mbr.img and bootsect.img exist, use them */
     mbr_t* real_mbr=(mbr_t*)s->first_sectors;
     partition_t* partition=&(real_mbr->partition[0]);
+    int lba;
 
     memset(s->first_sectors,0,512);
-   
+
+    /* Win NT Disk Signature */
+    real_mbr->nt_id= cpu_to_le32(0xbe1afdfa);
+
     partition->attributes=0x80; /* bootable */
-    partition->start_head=1;
-    partition->start_sector=1;
-    partition->start_cylinder=0;
+
+    /* LBA is used when partition is outside the CHS geometry */
+    lba = sector2CHS(s->bs, &partition->start_CHS, s->first_sectors_number-1);
+    lba|= sector2CHS(s->bs, &partition->end_CHS,   s->sector_count);
+
+    /*LBA partitions are identified only by start/length_sector_long not by CHS*/
+    partition->start_sector_long =cpu_to_le32(s->first_sectors_number-1);
+    partition->length_sector_long=cpu_to_le32(s->sector_count - s->first_sectors_number+1);
+
     /* FAT12/FAT16/FAT32 */
-    partition->fs_type=(s->fat_type==12?0x1:s->fat_type==16?0x6:0xb);
-    partition->end_head=s->bs->heads-1;
-    partition->end_sector=0xff; /* end sector & upper 2 bits of cylinder */;
-    partition->end_cylinder=0xff; /* lower 8 bits of end cylinder */;
-    partition->start_sector_long=cpu_to_le32(s->bs->secs);
-    partition->end_sector_long=cpu_to_le32(s->sector_count);
+    /* DOS uses different types when partition is LBA,
+       probably to prevent older versions from using CHS on them */
+    partition->fs_type= s->fat_type==12 ? 0x1:
+                        s->fat_type==16 ? (lba?0xe:0x06):
+                         /*fat_tyoe==32*/ (lba?0xc:0x0b);
 
     real_mbr->magic[0]=0x55; real_mbr->magic[1]=0xaa;
 }
@@ -478,7 +513,7 @@
     for(i=0;i<11;i++)
 	chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
 	    +(unsigned char)entry->name[i];
-    
+
     return chksum;
 }
 
@@ -554,7 +589,7 @@
 		s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
     }
     memset(s->fat.pointer,0,s->fat.size);
-    
+
     switch(s->fat_type) {
 	case 12: s->max_fat_value=0xfff; break;
 	case 16: s->max_fat_value=0xffff; break;
@@ -579,10 +614,10 @@
 	memcpy(entry->name,filename,strlen(filename));
 	return entry;
     }
-    
+
     entry_long=create_long_filename(s,filename);
-  
-    i = strlen(filename); 
+
+    i = strlen(filename);
     for(j = i - 1; j>0  && filename[j]!='.';j--);
     if (j > 0)
 	i = (j > 8 ? 8 : j);
@@ -592,7 +627,7 @@
     entry=array_get_next(&(s->directory));
     memset(entry->name,0x20,11);
     strncpy(entry->name,filename,i);
-    
+
     if(j > 0)
 	for (i = 0; i < 3 && filename[j+1+i]; i++)
 	    entry->extension[i] = filename[j+1+i];
@@ -618,7 +653,7 @@
 	if(entry1==entry) /* no dupe found */
 	    break;
 
-	/* use all 8 characters of name */	
+	/* use all 8 characters of name */
 	if(entry->name[7]==' ') {
 	    int j;
 	    for(j=6;j>0 && entry->name[j]==' ';j--)
@@ -675,11 +710,11 @@
 	mapping->end = mapping->begin;
 	return -1;
     }
-   
+
     i = mapping->info.dir.first_dir_index =
 	    first_cluster == 0 ? 0 : s->directory.next;
 
-    /* actually read the directory, and allocate the mappings */ 
+    /* actually read the directory, and allocate the mappings */
     while((entry=readdir(dir))) {
 	unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
         char* buffer;
@@ -690,7 +725,7 @@
 
 	if(first_cluster == 0 && (is_dotdot || is_dot))
 	    continue;
-	
+
 	buffer=(char*)malloc(length);
 	assert(buffer);
 	snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
@@ -765,7 +800,7 @@
 	memset(array_get(&(s->directory), cur), 0,
 		(ROOT_ENTRIES - cur) * sizeof(direntry_t));
     }
-	
+
      /* reget the mapping, since s->mapping was possibly realloc()ed */
     mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
     first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
@@ -774,7 +809,7 @@
 
     direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
     set_begin_of_direntry(direntry, mapping->begin);
-   
+
     return 0;
 }
 
@@ -825,7 +860,7 @@
      */
     i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
     s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
-    
+
     array_init(&(s->mapping),sizeof(mapping_t));
     array_init(&(s->directory),sizeof(direntry_t));
 
@@ -857,7 +892,7 @@
 
     for (i = 0, cluster = 0; i < s->mapping.next; i++) {
 	int j;
-	/* MS-DOS expects the FAT to be 0 for the root directory 
+	/* MS-DOS expects the FAT to be 0 for the root directory
 	 * (except for the media byte). */
 	/* LATER TODO: still true for FAT32? */
 	int fix_fat = (i != 0);
@@ -973,10 +1008,9 @@
 
     s->fat_type=16;
     /* LATER TODO: if FAT32, adjust */
-    s->sector_count=0xec04f;
     s->sectors_per_cluster=0x10;
-    /* LATER TODO: this could be wrong for FAT32 */
-    bs->cyls=1023; bs->heads=15; bs->secs=63;
+    /* 504MB disk*/
+    bs->cyls=1024; bs->heads=16; bs->secs=63;
 
     s->current_cluster=0xffffffff;
 
@@ -987,16 +1021,10 @@
     s->qcow_filename = NULL;
     s->fat2 = NULL;
     s->downcase_short_names = 1;
-    
+
     if (!strstart(dirname, "fat:", NULL))
 	return -1;
 
-    if (strstr(dirname, ":rw:")) {
-	if (enable_write_target(s))
-	    return -1;
-	bs->read_only = 0;
-    }
-
     if (strstr(dirname, ":floppy:")) {
 	floppy = 1;
 	s->fat_type = 12;
@@ -1005,6 +1033,8 @@
 	bs->cyls = 80; bs->heads = 2; bs->secs = 36;
     }
 
+    s->sector_count=bs->cyls*bs->heads*bs->secs;
+
     if (strstr(dirname, ":32:")) {
 	fprintf(stderr, "Big fat greek warning: FAT32 has not been tested. You are welcome to do so!\n");
 	s->fat_type = 32;
@@ -1015,6 +1045,12 @@
 	s->sector_count=2880;
     }
 
+    if (strstr(dirname, ":rw:")) {
+	if (enable_write_target(s))
+	    return -1;
+	bs->read_only = 0;
+    }
+
     i = strrchr(dirname, ':') - dirname;
     assert(i >= 3);
     if (dirname[i-2] == ':' && isalpha(dirname[i-1]))
@@ -1024,11 +1060,12 @@
 	dirname += i+1;
 
     bs->total_sectors=bs->cyls*bs->heads*bs->secs;
-    if (s->sector_count > bs->total_sectors)
-	s->sector_count = bs->total_sectors;
+
     if(init_directories(s, dirname))
 	return -1;
 
+    s->sector_count = s->faked_sectors + s->sectors_per_cluster*s->cluster_count;
+
     if(s->first_sectors_number==0x40)
 	init_mbr(s);
 
@@ -1076,7 +1113,7 @@
 	assert(index1<=index2);
 	DLOG(mapping=array_get(&(s->mapping),index1);
 	assert(mapping->begin<=cluster_num);
-	assert(index2 >= s->mapping.next || 
+	assert(index2 >= s->mapping.next ||
 		((mapping = array_get(&(s->mapping),index2)) &&
 		mapping->end>cluster_num)));
     }
@@ -1239,7 +1276,7 @@
 }
 #endif
 
-static int vvfat_read(BlockDriverState *bs, int64_t sector_num, 
+static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
                     uint8_t *buf, int nb_sectors)
 {
     BDRVVVFATState *s = bs->opaque;
@@ -1674,7 +1711,7 @@
 }
 
 /*
- * This function looks at the modified data (qcow). 
+ * This function looks at the modified data (qcow).
  * It returns 0 upon inconsistency or error, and the number of clusters
  * used by the directory, its subdirectories and their files.
  */
@@ -1709,7 +1746,7 @@
     } else
 	/* new directory */
 	schedule_mkdir(s, cluster_num, strdup(path));
-		
+
     lfn_init(&lfn);
     do {
 	int i;
@@ -2049,7 +2086,7 @@
 	    }
 
 	    next_mapping->dir_index = mapping->dir_index;
-	    next_mapping->first_mapping_index = 
+	    next_mapping->first_mapping_index =
 		mapping->first_mapping_index < 0 ?
 		array_index(&(s->mapping), mapping) :
 		mapping->first_mapping_index;
@@ -2069,7 +2106,7 @@
 
 	    mapping = next_mapping;
 	}
-		
+
 	cluster = c1;
     }
 
@@ -2555,7 +2592,7 @@
 	return ret;
     }
 
-    /* copy FAT (with bdrv_read) */ 
+    /* copy FAT (with bdrv_read) */
     memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
 
     /* recurse direntries from root (using bs->bdrv_read) */
@@ -2597,10 +2634,10 @@
     return do_commit(s);
 }
 
-static int vvfat_write(BlockDriverState *bs, int64_t sector_num, 
+static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
                     const uint8_t *buf, int nb_sectors)
 {
-    BDRVVVFATState *s = bs->opaque; 
+    BDRVVVFATState *s = bs->opaque;
     int i, ret;
 
 DLOG(checkpoint());
@@ -2639,7 +2676,7 @@
 		    begin = sector_num;
 		if (end > sector_num + nb_sectors)
 		    end = sector_num + nb_sectors;
-		dir_index  = mapping->dir_index + 
+		dir_index  = mapping->dir_index +
 		    0x10 * (begin - mapping->begin * s->sectors_per_cluster);
 		direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
 
@@ -2698,7 +2735,7 @@
 	*n = nb_sectors;
     else if (*n < 0)
 	return 0;
-    return 1;	
+    return 1;
 }
 
 static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
diff --git a/block.c b/block.c
index 39ec37a..20d2e1c 100644
--- a/block.c
+++ b/block.c
@@ -1,8 +1,8 @@
 /*
  * QEMU System Emulator block driver
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -48,7 +48,7 @@
         int64_t sector_num, const uint8_t *buf, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque);
 static void bdrv_aio_cancel_em(BlockDriverAIOCB *acb);
-static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, 
+static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
                         uint8_t *buf, int nb_sectors);
 static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num,
                          const uint8_t *buf, int nb_sectors);
@@ -167,7 +167,7 @@
     return NULL;
 }
 
-int bdrv_create(BlockDriver *drv, 
+int bdrv_create(BlockDriver *drv,
                 const char *filename, int64_t size_in_sectors,
                 const char *backing_file, int flags)
 {
@@ -180,7 +180,7 @@
 void get_tmp_filename(char *filename, int size)
 {
     char temp_dir[MAX_PATH];
-    
+
     GetTempPath(MAX_PATH, temp_dir);
     GetTempFileName(temp_dir, "qem", 0, filename);
 }
@@ -202,10 +202,10 @@
              (filename[0] >= 'A' && filename[0] <= 'Z')) &&
             filename[1] == ':');
 }
-    
+
 static int is_windows_drive(const char *filename)
 {
-    if (is_windows_drive_prefix(filename) && 
+    if (is_windows_drive_prefix(filename) &&
         filename[2] == '\0')
         return 1;
     if (strstart(filename, "\\\\.\\", NULL) ||
@@ -236,7 +236,7 @@
     memcpy(protocol, filename, len);
     protocol[len] = '\0';
     for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
-        if (drv1->protocol_name && 
+        if (drv1->protocol_name &&
             !strcmp(drv1->protocol_name, protocol))
             return drv1;
     }
@@ -251,7 +251,7 @@
     BlockDriver *drv1, *drv;
     uint8_t buf[2048];
     BlockDriverState *bs;
-    
+
     /* detect host devices. By convention, /dev/cdrom[N] is always
        recognized as a host CDROM */
     if (strstart(filename, "/dev/cdrom", NULL))
@@ -262,13 +262,13 @@
 #else
     {
         struct stat st;
-        if (stat(filename, &st) >= 0 && 
+        if (stat(filename, &st) >= 0 &&
             (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) {
             return &bdrv_host_device;
         }
     }
 #endif
-    
+
     drv = find_protocol(filename);
     /* no need to test disk image formats for vvfat */
     if (drv == &bdrv_vvfat)
@@ -322,9 +322,9 @@
                BlockDriver *drv)
 {
     int ret, open_flags;
-    char tmp_filename[1024];
-    char backing_filename[1024];
-    
+    char tmp_filename[PATH_MAX];
+    char backing_filename[PATH_MAX];
+
     bs->read_only = 0;
     bs->is_temporary = 0;
     bs->encrypted = 0;
@@ -332,7 +332,7 @@
     if (flags & BDRV_O_SNAPSHOT) {
         BlockDriverState *bs1;
         int64_t total_size;
-        
+
         /* if snapshot, we create a temporary backing file and open it
            instead of opening 'filename' directly */
 
@@ -347,10 +347,10 @@
         }
         total_size = bdrv_getlength(bs1) >> SECTOR_BITS;
         bdrv_delete(bs1);
-        
+
         get_tmp_filename(tmp_filename, sizeof(tmp_filename));
         realpath(filename, backing_filename);
-        if (bdrv_create(&bdrv_qcow2, tmp_filename, 
+        if (bdrv_create(&bdrv_qcow2, tmp_filename,
                         total_size, backing_filename, 0) < 0) {
             return -1;
         }
@@ -494,7 +494,7 @@
 }
 
 /* return < 0 if error. See bdrv_write() for the return codes */
-int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
+int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors)
 {
     BlockDriver *drv = bs->drv;
@@ -525,13 +525,13 @@
     }
 }
 
-/* Return < 0 if error. Important errors are: 
+/* Return < 0 if error. Important errors are:
   -EIO         generic I/O error (may happen for all errors)
   -ENOMEDIUM   No media inserted.
   -EINVAL      Invalid sector number or nb_sectors
   -EACCES      Trying to write a read-only device
 */
-int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
+int bdrv_write(BlockDriverState *bs, int64_t sector_num,
                const uint8_t *buf, int nb_sectors)
 {
     BlockDriver *drv = bs->drv;
@@ -540,7 +540,7 @@
     if (bs->read_only)
         return -EACCES;
     if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
-        memcpy(bs->boot_sector_data, buf, 512);   
+        memcpy(bs->boot_sector_data, buf, 512);
     }
     if (drv->bdrv_pwrite) {
         int ret, len;
@@ -557,7 +557,7 @@
     }
 }
 
-static int bdrv_pread_em(BlockDriverState *bs, int64_t offset, 
+static int bdrv_pread_em(BlockDriverState *bs, int64_t offset,
                          uint8_t *buf, int count1)
 {
     uint8_t tmp_buf[SECTOR_SIZE];
@@ -601,7 +601,7 @@
     return count1;
 }
 
-static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset, 
+static int bdrv_pwrite_em(BlockDriverState *bs, int64_t offset,
                           const uint8_t *buf, int count1)
 {
     uint8_t tmp_buf[SECTOR_SIZE];
@@ -650,9 +650,9 @@
 }
 
 /**
- * Read with byte offsets (needed only for file protocols) 
+ * Read with byte offsets (needed only for file protocols)
  */
-int bdrv_pread(BlockDriverState *bs, int64_t offset, 
+int bdrv_pread(BlockDriverState *bs, int64_t offset,
                void *buf1, int count1)
 {
     BlockDriver *drv = bs->drv;
@@ -664,10 +664,10 @@
     return drv->bdrv_pread(bs, offset, buf1, count1);
 }
 
-/** 
- * Write with byte offsets (needed only for file protocols) 
+/**
+ * Write with byte offsets (needed only for file protocols)
  */
-int bdrv_pwrite(BlockDriverState *bs, int64_t offset, 
+int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
                 const void *buf1, int count1)
 {
     BlockDriver *drv = bs->drv;
@@ -729,7 +729,7 @@
     memset(bs->boot_sector_data + size, 0, 512 - size);
 }
 
-void bdrv_set_geometry_hint(BlockDriverState *bs, 
+void bdrv_set_geometry_hint(BlockDriverState *bs,
                             int cyls, int heads, int secs)
 {
     bs->cyls = cyls;
@@ -749,7 +749,7 @@
     bs->translation = translation;
 }
 
-void bdrv_get_geometry_hint(BlockDriverState *bs, 
+void bdrv_get_geometry_hint(BlockDriverState *bs,
                             int *pcyls, int *pheads, int *psecs)
 {
     *pcyls = bs->cyls;
@@ -778,7 +778,7 @@
 }
 
 /* XXX: no longer used */
-void bdrv_set_change_cb(BlockDriverState *bs, 
+void bdrv_set_change_cb(BlockDriverState *bs,
                         void (*change_cb)(void *opaque), void *opaque)
 {
     bs->change_cb = change_cb;
@@ -816,7 +816,7 @@
     }
 }
 
-void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 
+void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
                          void *opaque)
 {
     BlockDriver *drv;
@@ -914,7 +914,7 @@
     }
 }
 
-void bdrv_get_backing_filename(BlockDriverState *bs, 
+void bdrv_get_backing_filename(BlockDriverState *bs,
                                char *filename, int filename_size)
 {
     if (!bs->backing_hd) {
@@ -924,7 +924,7 @@
     }
 }
 
-int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, 
+int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
                           const uint8_t *buf, int nb_sectors)
 {
     BlockDriver *drv = bs->drv;
@@ -934,7 +934,7 @@
         return -ENOTSUP;
     return drv->bdrv_write_compressed(bs, sector_num, buf, nb_sectors);
 }
-    
+
 int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
 {
     BlockDriver *drv = bs->drv;
@@ -949,7 +949,7 @@
 /**************************************************************/
 /* handling of snapshots */
 
-int bdrv_snapshot_create(BlockDriverState *bs, 
+int bdrv_snapshot_create(BlockDriverState *bs,
                          QEMUSnapshotInfo *sn_info)
 {
     BlockDriver *drv = bs->drv;
@@ -960,7 +960,7 @@
     return drv->bdrv_snapshot_create(bs, sn_info);
 }
 
-int bdrv_snapshot_goto(BlockDriverState *bs, 
+int bdrv_snapshot_goto(BlockDriverState *bs,
                        const char *snapshot_id)
 {
     BlockDriver *drv = bs->drv;
@@ -981,7 +981,7 @@
     return drv->bdrv_snapshot_delete(bs, snapshot_id);
 }
 
-int bdrv_snapshot_list(BlockDriverState *bs, 
+int bdrv_snapshot_list(BlockDriverState *bs,
                        QEMUSnapshotInfo **psn_info)
 {
     BlockDriver *drv = bs->drv;
@@ -1006,12 +1006,12 @@
         base = 1024;
         for(i = 0; i < NB_SUFFIXES; i++) {
             if (size < (10 * base)) {
-                snprintf(buf, buf_size, "%0.1f%c", 
+                snprintf(buf, buf_size, "%0.1f%c",
                          (double)size / base,
                          suffixes[i]);
                 break;
             } else if (size < (1000 * base) || i == (NB_SUFFIXES - 1)) {
-                snprintf(buf, buf_size, "%" PRId64 "%c", 
+                snprintf(buf, buf_size, "%" PRId64 "%c",
                          ((size + (base >> 1)) / base),
                          suffixes[i]);
                 break;
@@ -1034,8 +1034,8 @@
     int64_t secs;
 
     if (!sn) {
-        snprintf(buf, buf_size, 
-                 "%-10s%-20s%7s%20s%15s", 
+        snprintf(buf, buf_size,
+                 "%-10s%-20s%7s%20s%15s",
                  "ID", "TAG", "VM SIZE", "DATE", "VM CLOCK");
     } else {
         ti = sn->date_sec;
@@ -1053,10 +1053,10 @@
                  "%02d:%02d:%02d.%03d",
                  (int)(secs / 3600),
                  (int)((secs / 60) % 60),
-                 (int)(secs % 60), 
+                 (int)(secs % 60),
                  (int)((sn->vm_clock_nsec / 1000000) % 1000));
         snprintf(buf, buf_size,
-                 "%-10s%-20s%7s%20s%15s", 
+                 "%-10s%-20s%7s%20s%15s",
                  sn->id_str, sn->name,
                  get_human_readable_size(buf1, sizeof(buf1), sn->vm_state_size),
                  date_buf,
@@ -1077,7 +1077,7 @@
 
     if (!drv)
         return NULL;
-    
+
     /* XXX: we assume that nb_sectors == 0 is suppored by the async read */
     if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
         memcpy(buf, bs->boot_sector_data, 512);
@@ -1100,7 +1100,7 @@
     if (bs->read_only)
         return NULL;
     if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
-        memcpy(bs->boot_sector_data, buf, 512);   
+        memcpy(bs->boot_sector_data, buf, 512);
     }
 
     return drv->bdrv_aio_write(bs, sector_num, buf, nb_sectors, cb, opaque);
@@ -1199,7 +1199,7 @@
 
 #define NOT_DONE 0x7fffffff
 
-static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, 
+static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,
                         uint8_t *buf, int nb_sectors)
 {
     int async_ret;
@@ -1207,7 +1207,7 @@
 
     async_ret = NOT_DONE;
     qemu_aio_wait_start();
-    acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors, 
+    acb = bdrv_aio_read(bs, sector_num, buf, nb_sectors,
                         bdrv_rw_em_cb, &async_ret);
     if (acb == NULL) {
         qemu_aio_wait_end();
@@ -1228,7 +1228,7 @@
 
     async_ret = NOT_DONE;
     qemu_aio_wait_start();
-    acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors, 
+    acb = bdrv_aio_write(bs, sector_num, buf, nb_sectors,
                          bdrv_rw_em_cb, &async_ret);
     if (acb == NULL) {
         qemu_aio_wait_end();
@@ -1256,6 +1256,7 @@
     bdrv_register(&bdrv_vpc);
     bdrv_register(&bdrv_vvfat);
     bdrv_register(&bdrv_qcow2);
+    bdrv_register(&bdrv_parallels);
 }
 
 void *qemu_aio_get(BlockDriverState *bs, BlockDriverCompletionFunc *cb,
@@ -1307,7 +1308,7 @@
 
 /**
  * Return TRUE if the media changed since the last call to this
- * function. It is currently only used for floppy disks 
+ * function. It is currently only used for floppy disks
  */
 int bdrv_media_changed(BlockDriverState *bs)
 {
diff --git a/block_int.h b/block_int.h
index 25f6717..b034023 100644
--- a/block_int.h
+++ b/block_int.h
@@ -1,8 +1,8 @@
 /*
  * QEMU System Emulator block driver
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -24,17 +24,21 @@
 #ifndef BLOCK_INT_H
 #define BLOCK_INT_H
 
+#define BLOCK_FLAG_ENCRYPT	1
+#define BLOCK_FLAG_COMPRESS	2
+#define BLOCK_FLAG_COMPAT6	4
+
 struct BlockDriver {
     const char *format_name;
     int instance_size;
     int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename);
     int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags);
-    int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, 
+    int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num,
                      uint8_t *buf, int nb_sectors);
-    int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, 
+    int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
                       const uint8_t *buf, int nb_sectors);
     void (*bdrv_close)(BlockDriverState *bs);
-    int (*bdrv_create)(const char *filename, int64_t total_sectors, 
+    int (*bdrv_create)(const char *filename, int64_t total_sectors,
                        const char *backing_file, int flags);
     void (*bdrv_flush)(BlockDriverState *bs);
     int (*bdrv_is_allocated)(BlockDriverState *bs, int64_t sector_num,
@@ -52,21 +56,21 @@
     int aiocb_size;
 
     const char *protocol_name;
-    int (*bdrv_pread)(BlockDriverState *bs, int64_t offset, 
+    int (*bdrv_pread)(BlockDriverState *bs, int64_t offset,
                       uint8_t *buf, int count);
-    int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset, 
+    int (*bdrv_pwrite)(BlockDriverState *bs, int64_t offset,
                        const uint8_t *buf, int count);
     int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
     int64_t (*bdrv_getlength)(BlockDriverState *bs);
-    int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num, 
+    int (*bdrv_write_compressed)(BlockDriverState *bs, int64_t sector_num,
                                  const uint8_t *buf, int nb_sectors);
 
-    int (*bdrv_snapshot_create)(BlockDriverState *bs, 
+    int (*bdrv_snapshot_create)(BlockDriverState *bs,
                                 QEMUSnapshotInfo *sn_info);
-    int (*bdrv_snapshot_goto)(BlockDriverState *bs, 
+    int (*bdrv_snapshot_goto)(BlockDriverState *bs,
                               const char *snapshot_id);
     int (*bdrv_snapshot_delete)(BlockDriverState *bs, const char *snapshot_id);
-    int (*bdrv_snapshot_list)(BlockDriverState *bs, 
+    int (*bdrv_snapshot_list)(BlockDriverState *bs,
                               QEMUSnapshotInfo **psn_info);
     int (*bdrv_get_info)(BlockDriverState *bs, BlockDriverInfo *bdi);
 
@@ -75,7 +79,7 @@
     int (*bdrv_media_changed)(BlockDriverState *bs);
     int (*bdrv_eject)(BlockDriverState *bs, int eject_flag);
     int (*bdrv_set_locked)(BlockDriverState *bs, int locked);
-    
+
     BlockDriverAIOCB *free_aiocb;
     struct BlockDriver *next;
 };
@@ -107,7 +111,7 @@
     /* async read/write emulation */
 
     void *sync_aiocb;
-    
+
     /* NOTE: the following infos are only hints for real hardware
        drivers. They are not used by the block driver */
     int cyls, heads, secs, translation;
diff --git a/bswap.h b/bswap.h
index 37fb04e..970c1bb 100644
--- a/bswap.h
+++ b/bswap.h
@@ -48,12 +48,12 @@
     return bswap_16(x);
 }
 
-static inline uint32_t bswap32(uint32_t x) 
+static inline uint32_t bswap32(uint32_t x)
 {
     return bswap_32(x);
 }
 
-static inline uint64_t bswap64(uint64_t x) 
+static inline uint64_t bswap64(uint64_t x)
 {
     return bswap_64(x);
 }
diff --git a/cocoa.m b/cocoa.m
index 9551aff..84f943c 100644
--- a/cocoa.m
+++ b/cocoa.m
@@ -1,9 +1,9 @@
 /*
  * QEMU Cocoa display driver
- * 
+ *
  * Copyright (c) 2005 Pierre d'Herbemont
  *                    many code/inspiration from SDL 1.2 code (LGPL)
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -23,7 +23,7 @@
  * THE SOFTWARE.
  */
 /*
-    Todo :    x  miniaturize window 
+    Todo :    x  miniaturize window
               x  center the window
               -  save window position
               -  handle keyboard event
@@ -84,7 +84,7 @@
     MacSetRectRgn (temp, x, y,
                         x + w, y + h);
     MacUnionRgn (dirty, temp, dirty);
-                
+
     /* Flush the dirty region */
     QDFlushPortBuffer ( [ qd_view  qdPort ], dirty );
     DisposeRgn (dirty);
@@ -102,9 +102,9 @@
     static void *screen_pixels;
     static int  screen_pitch;
     NSRect contentRect;
-    
+
     //printf("resizing to %d %d\n", w, h);
-    
+
     contentRect = NSMakeRect (0, 0, w, h);
     if(window)
     {
@@ -119,44 +119,44 @@
         fprintf(stderr, "(cocoa) can't create window\n");
         exit(1);
     }
-    
+
     if(qd_view)
         [qd_view release];
-    
+
     qd_view = [ [ NSQuickDrawView alloc ] initWithFrame:contentRect ];
-    
+
     if(!qd_view)
     {
          fprintf(stderr, "(cocoa) can't create qd_view\n");
         exit(1);
     }
-    
+
     [ window setAcceptsMouseMovedEvents:YES ];
     [ window setTitle:@"Qemu" ];
     [ window setReleasedWhenClosed:NO ];
-    
+
     /* Set screen to black */
     [ window setBackgroundColor: [NSColor blackColor] ];
-    
+
     /* set window position */
     [ window center ];
-    
+
     [ qd_view setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable ];
     [ [ window contentView ] addSubview:qd_view ];
     [ qd_view release ];
     [ window makeKeyAndOrderFront:nil ];
-    
+
     /* Careful here, the window seems to have to be onscreen to do that */
     LockPortBits ( [ qd_view qdPort ] );
     screen_pixels = GetPixBaseAddr ( GetPortPixMap ( [ qd_view qdPort ] ) );
     screen_pitch  = GetPixRowBytes ( GetPortPixMap ( [ qd_view qdPort ] ) );
     UnlockPortBits ( [ qd_view qdPort ] );
-    { 
-            int vOffset = [ window frame ].size.height - 
+    {
+            int vOffset = [ window frame ].size.height -
                 [ qd_view frame ].size.height - [ qd_view frame ].origin.y;
-            
+
             int hOffset = [ qd_view frame ].origin.x;
-                    
+
             screen_pixels += (vOffset * screen_pitch) + hOffset * (device_bpp/8);
     }
     ds->data = screen_pixels;
@@ -164,7 +164,12 @@
     ds->depth = device_bpp;
     ds->width = w;
     ds->height = h;
-    
+#ifdef __LITTLE_ENDIAN__
+    ds->bgr = 1;
+#else
+    ds->bgr = 0;
+#endif
+
     current_ds = *ds;
 }
 
@@ -305,38 +310,38 @@
     208,//  125     0x7D    0xd0    E0,50   D ARROW QZ_DOWN
     200,//  126     0x7E    0xc8    E0,48   U ARROW QZ_UP
 /* completed according to http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/quartz/SDL_QuartzKeys.h?rev=1.6&content-type=text/x-cvsweb-markup */
-  
+
 /* Aditional 104 Key XP-Keyboard Scancodes from http://www.computer-engineering.org/ps2keyboard/scancodes1.html */
 /*
-    219 //          0xdb            e0,5b   L GUI   
-    220 //          0xdc            e0,5c   R GUI   
-    221 //          0xdd            e0,5d   APPS    
-        //              E0,2A,E0,37         PRNT SCRN   
-        //              E1,1D,45,E1,9D,C5   PAUSE   
-    83  //          0x53    0x53            KP .    
-// ACPI Scan Codes                              
-    222 //          0xde            E0, 5E  Power   
-    223 //          0xdf            E0, 5F  Sleep   
-    227 //          0xe3            E0, 63  Wake    
-// Windows Multimedia Scan Codes                                
-    153 //          0x99            E0, 19  Next Track  
-    144 //          0x90            E0, 10  Previous Track  
-    164 //          0xa4            E0, 24  Stop    
-    162 //          0xa2            E0, 22  Play/Pause  
-    160 //          0xa0            E0, 20  Mute    
-    176 //          0xb0            E0, 30  Volume Up   
-    174 //          0xae            E0, 2E  Volume Down 
-    237 //          0xed            E0, 6D  Media Select    
-    236 //          0xec            E0, 6C  E-Mail  
-    161 //          0xa1            E0, 21  Calculator  
-    235 //          0xeb            E0, 6B  My Computer 
-    229 //          0xe5            E0, 65  WWW Search  
-    178 //          0xb2            E0, 32  WWW Home    
-    234 //          0xea            E0, 6A  WWW Back    
-    233 //          0xe9            E0, 69  WWW Forward 
-    232 //          0xe8            E0, 68  WWW Stop    
-    231 //          0xe7            E0, 67  WWW Refresh 
-    230 //          0xe6            E0, 66  WWW Favorites   
+    219 //          0xdb            e0,5b   L GUI
+    220 //          0xdc            e0,5c   R GUI
+    221 //          0xdd            e0,5d   APPS
+        //              E0,2A,E0,37         PRNT SCRN
+        //              E1,1D,45,E1,9D,C5   PAUSE
+    83  //          0x53    0x53            KP .
+// ACPI Scan Codes
+    222 //          0xde            E0, 5E  Power
+    223 //          0xdf            E0, 5F  Sleep
+    227 //          0xe3            E0, 63  Wake
+// Windows Multimedia Scan Codes
+    153 //          0x99            E0, 19  Next Track
+    144 //          0x90            E0, 10  Previous Track
+    164 //          0xa4            E0, 24  Stop
+    162 //          0xa2            E0, 22  Play/Pause
+    160 //          0xa0            E0, 20  Mute
+    176 //          0xb0            E0, 30  Volume Up
+    174 //          0xae            E0, 2E  Volume Down
+    237 //          0xed            E0, 6D  Media Select
+    236 //          0xec            E0, 6C  E-Mail
+    161 //          0xa1            E0, 21  Calculator
+    235 //          0xeb            E0, 6B  My Computer
+    229 //          0xe5            E0, 65  WWW Search
+    178 //          0xb2            E0, 32  WWW Home
+    234 //          0xea            E0, 6A  WWW Back
+    233 //          0xe9            E0, 69  WWW Forward
+    232 //          0xe8            E0, 68  WWW Stop
+    231 //          0xe7            E0, 67  WWW Refresh
+    230 //          0xe6            E0, 66  WWW Favorites
 */
 };
 
@@ -361,10 +366,10 @@
     NSDate *distantPast;
     NSEvent *event;
     NSAutoreleasePool *pool;
-    
+
     pool = [ [ NSAutoreleasePool alloc ] init ];
     distantPast = [ NSDate distantPast ];
-    
+
     vga_hw_update();
 
     do {
@@ -410,8 +415,8 @@
 
                 case NSKeyDown:
                     {
-                        int keycode = cocoa_keycode_to_qemu([event keyCode]);               
-                        
+                        int keycode = cocoa_keycode_to_qemu([event keyCode]);
+
                         /* handle command Key Combos */
                         if ([event modifierFlags] & NSCommandKeyMask) {
                             switch ([event keyCode]) {
@@ -422,7 +427,7 @@
                                     return;
                             }
                         }
-                        
+
                         /* handle control + alt Key Combos */
                         if (([event modifierFlags] & NSControlKeyMask) && ([event modifierFlags] & NSAlternateKeyMask)) {
                             switch (keycode) {
@@ -477,10 +482,10 @@
                         }
                     }
                     break;
-                    
+
                 case NSKeyUp:
                     {
-                        int keycode = cocoa_keycode_to_qemu([event keyCode]);   
+                        int keycode = cocoa_keycode_to_qemu([event keyCode]);
                         if (is_graphic_console()) {
                             if (keycode & 0x80)
                                 kbd_put_keycode(0xe0);
@@ -488,7 +493,7 @@
                         }
                     }
                     break;
-                    
+
                 case NSMouseMoved:
                     if (grab) {
                         int dx = [event deltaX];
@@ -498,11 +503,11 @@
                         kbd_mouse_event(dx, dy, dz, buttons);
                     }
                     break;
-                        
+
                 case NSLeftMouseDown:
                     if (grab) {
                         int buttons = 0;
-                        
+
                         /* leftclick+command simulates rightclick */
                         if ([event modifierFlags] & NSCommandKeyMask) {
                             buttons |= MOUSE_EVENT_RBUTTON;
@@ -514,7 +519,7 @@
                         [NSApp sendEvent: event];
                     }
                     break;
-                        
+
                 case NSLeftMouseDragged:
                     if (grab) {
                         int dx = [event deltaX];
@@ -529,7 +534,7 @@
                         kbd_mouse_event(dx, dy, dz, buttons);
                     }
                     break;
-                        
+
                 case NSLeftMouseUp:
                     if (grab) {
                         kbd_mouse_event(0, 0, 0, 0);
@@ -541,18 +546,18 @@
                         //[NSApp sendEvent: event];
                     }
                     break;
-                        
+
                 case NSRightMouseDown:
                     if (grab) {
                         int buttons = 0;
-                        
+
                         buttons |= MOUSE_EVENT_RBUTTON;
                         kbd_mouse_event(0, 0, 0, buttons);
                     } else {
                         [NSApp sendEvent: event];
                     }
                     break;
-                    
+
                 case NSRightMouseDragged:
                     if (grab) {
                         int dx = [event deltaX];
@@ -563,7 +568,7 @@
                         kbd_mouse_event(dx, dy, dz, buttons);
                     }
                     break;
-                    
+
                 case NSRightMouseUp:
                     if (grab) {
                         kbd_mouse_event(0, 0, 0, 0);
@@ -571,7 +576,7 @@
                         [NSApp sendEvent: event];
                     }
                     break;
-                        
+
                 case NSOtherMouseDragged:
                     if (grab) {
                         int dx = [event deltaX];
@@ -582,7 +587,7 @@
                         kbd_mouse_event(dx, dy, dz, buttons);
                     }
                     break;
-                    
+
                 case NSOtherMouseDown:
                     if (grab) {
                         int buttons = 0;
@@ -592,7 +597,7 @@
                         [NSApp sendEvent:event];
                     }
                     break;
-                        
+
                 case NSOtherMouseUp:
                     if (grab) {
                         kbd_mouse_event(0, 0, 0, 0);
@@ -600,14 +605,14 @@
                         [NSApp sendEvent: event];
                     }
                     break;
-                        
+
                 case NSScrollWheel:
                     if (grab) {
                         int dz = [event deltaY];
                         kbd_mouse_event(0, 0, -dz, 0);
                     }
                     break;
-                
+
                 default: [NSApp sendEvent:event];
             }
         }
@@ -620,7 +625,7 @@
  ------------------------------------------------------
 */
 
-static void cocoa_cleanup(void) 
+static void cocoa_cleanup(void)
 {
 
 }
@@ -636,9 +641,9 @@
     ds->dpy_update = cocoa_update;
     ds->dpy_resize = cocoa_resize;
     ds->dpy_refresh = cocoa_refresh;
-    
+
     cocoa_resize(ds, 640, 400);
-    
+
     atexit(cocoa_cleanup);
 }
 
@@ -656,17 +661,17 @@
  ------------------------------------------------------
 */
 static void QZ_SetPortAlphaOpaque ()
-{    
+{
     /* Assume 32 bit if( bpp == 32 )*/
     if ( 1 ) {
-    
+
         uint32_t    *pixels = (uint32_t*) current_ds.data;
         uint32_t    rowPixels = current_ds.linesize / 4;
         uint32_t    i, j;
-        
+
         for (i = 0; i < current_ds.height; i++)
             for (j = 0; j < current_ds.width; j++) {
-        
+
                 pixels[ (i * rowPixels) + j ] |= 0xFF000000;
             }
     }
@@ -675,32 +680,32 @@
 @implementation QemuWindow
 - (void)miniaturize:(id)sender
 {
-        
+
     /* make the alpha channel opaque so anim won't have holes in it */
     QZ_SetPortAlphaOpaque ();
-    
+
     [ super miniaturize:sender ];
-    
+
 }
 - (void)display
-{    
-    /* 
+{
+    /*
         This method fires just before the window deminaturizes from the Dock.
-        
+
         We'll save the current visible surface, let the window manager redraw any
-        UI elements, and restore the SDL surface. This way, no expose event 
+        UI elements, and restore the SDL surface. This way, no expose event
         is required, and the deminiaturize works perfectly.
     */
-    
+
     /* make sure pixels are fully opaque */
     QZ_SetPortAlphaOpaque ();
-    
+
     /* save current visible SDL surface */
     [ self cacheImageInRect:[ qd_view frame ] ];
-    
+
     /* let the window manager redraw controls, border, etc */
     [ super display ];
-    
+
     /* restore visible SDL surface */
     [ self restoreCachedImage ];
 }
@@ -737,13 +742,13 @@
     if( gArgc <= 1 || strncmp (gArgv[1], "-psn", 4) == 0)
     {
         NSOpenPanel *op = [[NSOpenPanel alloc] init];
-        
+
         cocoa_resize(&current_ds, 640, 400);
-        
+
         [op setPrompt:@"Boot image"];
-        
+
         [op setMessage:@"Select the disk image you want to boot.\n\nHit the \"Cancel\" button to quit"];
-        
+
         [op beginSheetForDirectory:nil file:nil types:[NSArray arrayWithObjects:@"img",@"iso",@"dmg",@"qcow",@"cow",@"cloop",@"vmdk",nil]
               modalForWindow:window modalDelegate:self
               didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:) contextInfo:NULL];
@@ -769,20 +774,20 @@
     {
         exit(0);
     }
-    
+
     if(returnCode == NSOKButton)
     {
         char *bin = "qemu";
         char *img = (char*)[ [ sheet filename ] cString];
-        
+
         char **argv = (char**)malloc( sizeof(char*)*3 );
-        
+
         asprintf(&argv[0], "%s", bin);
         asprintf(&argv[1], "-hda");
         asprintf(&argv[2], "%s", img);
-        
+
         printf("Using argc %d argv %s -hda %s\n", 3, bin, img);
-        
+
         [self startEmulationWithArgc:3 argv:(char**)argv];
     }
 }
@@ -822,10 +827,10 @@
     NSMenuItem *menuItem;
     NSString *title;
     NSString *appName;
-    
+
     appName = @"Qemu";
     appleMenu = [[NSMenu alloc] initWithTitle:@""];
-    
+
     /* Add menu items */
     title = [@"About " stringByAppendingString:appName];
     [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
@@ -845,7 +850,7 @@
     title = [@"Quit " stringByAppendingString:appName];
     [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
 
-    
+
     /* Put menu into the menubar */
     menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
     [menuItem setSubmenu:appleMenu];
@@ -867,17 +872,17 @@
     NSMenuItem  *menuItem;
 
     windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
-    
+
     /* "Minimize" item */
     menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
     [windowMenu addItem:menuItem];
     [menuItem release];
-    
+
     /* Put menu into the menubar */
     windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
     [windowMenuItem setSubmenu:windowMenu];
     [[NSApp mainMenu] addItem:windowMenuItem];
-    
+
     /* Tell the application object that this is now the window menu */
     [NSApp setWindowsMenu:windowMenu];
 
@@ -891,14 +896,14 @@
     NSAutoreleasePool   *pool = [[NSAutoreleasePool alloc] init];
     QemuCocoaGUIController *gui_controller;
     CPSProcessSerNum PSN;
-    
+
     [NSApplication sharedApplication];
-    
+
     if (!CPSGetCurrentProcess(&PSN))
         if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
             if (!CPSSetFrontProcess(&PSN))
                 [NSApplication sharedApplication];
-                
+
     /* Set up the menubar */
     [NSApp setMainMenu:[[NSMenu alloc] init]];
     setApplicationMenu();
@@ -907,10 +912,10 @@
     /* Create SDLMain and make it the app delegate */
     gui_controller = [[QemuCocoaGUIController alloc] init];
     [NSApp setDelegate:gui_controller];
-    
+
     /* Start the main event loop */
     [NSApp run];
-    
+
     [gui_controller release];
     [pool release];
 }
diff --git a/configure b/configure
index 365b7fb..fc1e59a 100755
--- a/configure
+++ b/configure
@@ -23,7 +23,7 @@
 cross_prefix=""
 cc="gcc"
 gcc3_search="yes"
-gcc3_list="gcc-3.4 gcc34 gcc-3.3 gcc33 gcc-3.2 gcc32"
+gcc3_list="gcc-3.4 gcc34 gcc-3.3.6 gcc-3.3 gcc33 gcc-3.2 gcc32"
 host_cc="gcc"
 ar="ar"
 make="make"
@@ -50,10 +50,13 @@
   mips)
     cpu="mips"
   ;;
-  s390)
+  mips64)
+    cpu="mips64"
+  ;;
+  s390*)
     cpu="s390"
   ;;
-  sparc|sun4[muv])
+  sparc|sun4[cdmuv])
     cpu="sparc"
   ;;
   sparc64)
@@ -86,6 +89,7 @@
 fmod="no"
 fmod_lib=""
 fmod_inc=""
+vnc_tls="yes"
 bsd="no"
 linux="no"
 kqemu="no"
@@ -107,9 +111,22 @@
 CYGWIN*)
 mingw32="yes"
 OS_CFLAGS="-mno-cygwin"
+VL_OS_LDFLAGS="-mno-cygwin"
+if [ "$cpu" = "i386" ] ; then
+    kqemu="yes"
+fi
 ;;
 MINGW32*)
 mingw32="yes"
+if [ "$cpu" = "i386" ] ; then
+    kqemu="yes"
+fi
+;;
+GNU/kFreeBSD)
+oss="yes"
+if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+    kqemu="yes"
+fi
 ;;
 FreeBSD)
 bsd="yes"
@@ -136,7 +153,36 @@
 OS_CFLAGS="-mdynamic-no-pic"
 ;;
 SunOS)
-solaris="yes"
+    solaris="yes"
+    make="gmake"
+    install="ginstall"
+    needs_libsunmath="no"
+    solarisrev=`uname -r | cut -f2 -d.`
+    # have to select again, because `uname -m` returns i86pc
+    # even on an x86_64 box.
+    solariscpu=`isainfo -k`
+    if test "${solariscpu}" = "amd64" ; then
+        cpu="x86_64"
+    fi
+    if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+        if test "$solarisrev" -le 9 ; then
+            if test -f /opt/SUNWspro/prod/lib/libsunmath.so.1; then
+                needs_libsunmath="yes"
+            else
+                echo "QEMU will not link correctly on Solaris 8/X86 or 9/x86 without"
+                echo "libsunmath from the Sun Studio compilers tools, due to a lack of"
+                echo "C99 math features in libm.so in Solaris 8/x86 and Solaris 9/x86"
+                echo "Studio 11 can be downloaded from www.sun.com."
+                exit 1
+            fi
+        fi
+        if test "$solarisrev" -ge 9 ; then
+            kqemu="yes"
+        fi
+    fi
+    if test -f /usr/include/sys/soundcard.h ; then
+        oss=yes
+    fi
 ;;
 *)
 oss="yes"
@@ -155,17 +201,6 @@
   fi
 fi
 
-if [ "$solaris" = "yes" ] ; then
-    make="gmake"
-    install="ginstall"
-    solarisrev=`uname -r | cut -f2 -d.`
-    if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
-        if test "$solarisrev" -gt 10 ; then
-            kqemu="yes"
-        fi
-    fi
-fi
-
 # find source path
 source_path=`dirname "$0"`
 if [ -z "$source_path" ]; then
@@ -228,7 +263,9 @@
   ;;
   --fmod-inc=*) fmod_inc="$optarg"
   ;;
-  --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
+  --disable-vnc-tls) vnc_tls="no"
+  ;;
+  --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; linux_user="no"
   ;;
   --disable-slirp) slirp="no"
   ;;
@@ -262,13 +299,64 @@
   ;;
   --enable-uname-release=*) uname_release="$optarg"
   ;;
+  --sparc_cpu=*)
+      sparc_cpu="$optarg"
+      case $sparc_cpu in
+        v7|v8) SP_CFLAGS="-m32 -mcpu=${sparc_cpu} -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m32"
+                 target_cpu="sparc"; cpu="sparc" ;;
+        v8plus|v8plusa) SP_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m32"
+                 target_cpu="sparc"; cpu="sparc" ;;
+        v9)    SP_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m64"
+                 target_cpu="sparc64"; cpu="sparc64" ;;
+        *)     echo "undefined SPARC architecture. Exiting";exit 1;;
+      esac
+  ;;
   esac
 done
 
+if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then
+    AIOLIBS=
+else
+    AIOLIBS="-lrt"
+fi
+
 # default flags for all hosts
 CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing"
 LDFLAGS="$LDFLAGS -g"
 
+#
+# If cpu ~= sparc and  sparc_cpu hasn't been defined, plug in the right
+# ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit)
+#
+case $cpu in
+    sparc) if test -z "$sparc_cpu" ; then
+               ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__"
+               ARCH_LDFLAGS="-m32"
+           else
+               ARCH_CFLAGS="${SP_CFLAGS}"
+               ARCH_LDFLAGS="${SP_LDFLAGS}"
+           fi
+           ;;
+    sparc64) if test -z "$sparc_cpu" ; then
+               ARCH_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__"
+               ARCH_LDFLAGS="-m64"
+           else
+               ARCH_CFLAGS="${SP_CFLAGS}"
+               ARCH_LDFLAGS="${SP_LDFLAGS}"
+           fi
+           ;;
+esac
+
+if [ "$solaris" = "yes" -a  "$cpu" = "x86_64" ] ; then
+    CFLAGS="${CFLAGS} -m64"
+    OS_CFLAGS="${OS_CFLAGS} -m64"
+fi
+
+if [ "$solaris" = "yes" -a  "$cpu" = "i386" ] ; then
+    CFLAGS="${CFLAGS} -m32"
+    OS_CFLAGS="${OS_CFLAGS} -m32"
+fi
+
 if test x"$show_help" = x"yes" ; then
 cat << EOF
 
@@ -302,7 +390,8 @@
 echo "  --enable-coreaudio       enable Coreaudio audio driver"
 echo "  --enable-alsa            enable ALSA audio driver"
 echo "  --enable-fmod            enable FMOD audio driver"
-echo "  --enabled-dsound         enable DirectSound audio driver"
+echo "  --enable-dsound          enable DirectSound audio driver"
+echo "  --disable-vnc-tls        disable TLS encryption for VNC server"
 echo "  --enable-system          enable all system emulation targets"
 echo "  --disable-system         disable all system emulation targets"
 echo "  --enable-linux-user      enable all linux usermode emulation targets"
@@ -312,6 +401,7 @@
 echo "  --fmod-lib               path to FMOD library"
 echo "  --fmod-inc               path to FMOD includes"
 echo "  --enable-uname-release=R Return R for uname -r in usermode emulation"
+echo "  --sparc_cpu=V            Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
 echo ""
 echo "NOTE: The object files are built at the place where configure is launched"
 exit 1
@@ -326,7 +416,7 @@
 int main(void) {}
 EOF
 
-if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
+if $cc -c -o $TMPO $TMPC 2> /dev/null ; then
   : C compiler works ok
 else
     echo "ERROR: \"$cc\" either does not exist or does not work"
@@ -337,12 +427,9 @@
     linux="no"
     EXESUF=".exe"
     oss="no"
-    if [ "$cpu" = "i386" ] ; then
-        kqemu="yes"
-    fi
 fi
 
-# Check for gcc4, error if pre-gcc4 
+# Check for gcc4, error if pre-gcc4
 if test "$check_gcc" = "yes" ; then
     cat > $TMPC <<EOF
 #if __GNUC__ < 4
@@ -350,20 +437,15 @@
 #endif
 int main(){return 0;}
 EOF
-    check_cc() {
-	which "$1" >&/dev/null
-	return $?
-    }
-
-    if "$cc" -o $TMPE $TMPC 2>/dev/null ; then
+    if "$cc" -o $TMPE $TMPC 2> /dev/null ; then
 	echo "WARNING: \"$cc\" looks like gcc 4.x"
 	found_compat_cc="no"
 	if test "$gcc3_search" = "yes" ; then
 	    echo "Looking for gcc 3.x"
 	    for compat_cc in $gcc3_list ; do
-		if check_cc "$compat_cc" ; then
+		if "$cross_prefix$compat_cc" --version 2> /dev/null | fgrep '(GCC) 3.' > /dev/null 2>&1 ; then
 		    echo "Found \"$compat_cc\""
-		    cc="$compat_cc"
+		    cc="$cross_prefix$compat_cc"
 		    found_compat_cc="yes"
 		    break
 		fi
@@ -388,7 +470,7 @@
   #
   # gcc for solaris 10/fcs in /usr/sfw/bin doesn't compile qemu correctly
   # override the check with --disable-gcc-check
-  # 
+  #
   if test "$solarisrev" -eq 10 -a "$check_gcc" = "yes" ; then
     solgcc=`which $cc`
     if test "$solgcc" = "/usr/sfw/bin/gcc" ; then
@@ -419,17 +501,17 @@
     fi
     exit 1
   fi
-fi 
+fi
 
 
 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 arm-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 sh4-softmmu"
     fi
 # the following are Linux specific
     if [ "$linux_user" = "yes" ] ; then
-        target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user $target_list"
+        target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user ppc64-linux-user sh4-linux-user $target_list"
     fi
 # the following are Darwin specific
     if [ "$darwin_user" = "yes" ] ; then
@@ -455,7 +537,7 @@
 }
 EOF
 
-if $cc -o $TMPE $TMPC 2>/dev/null ; then
+if $cc -o $TMPE $TMPC 2> /dev/null ; then
 $TMPE && bigendian="yes"
 else
 echo big/little test failed
@@ -464,7 +546,7 @@
 else
 
 # if cross compiling, cannot launch a program, so make a static guess
-if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
+if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "mips64" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
     bigendian="yes"
 fi
 
@@ -482,72 +564,71 @@
 }
 EOF
 
-have_gcc3_options="no"
-if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
-   have_gcc3_options="yes"
-fi
-
 ##########################################
 # SDL probe
 
 sdl_too_old=no
 
 if test -z "$sdl" ; then
+    sdl_config="sdl-config"
+    sdl=no
+    sdl_static=no
 
-sdl_config="sdl-config"
-sdl=no
-sdl_static=no
-
-if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then
-# win32 cross compilation case
-    sdl_config="i386-mingw32msvc-sdl-config"
-    sdl=yes
-else
-# normal SDL probe
+    if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then
+    # win32 cross compilation case
+        sdl_config="i386-mingw32msvc-sdl-config"
+        sdl=yes
+    else
+        # normal SDL probe
 cat > $TMPC << EOF
 #include <SDL.h>
 #undef main /* We don't want SDL to override our main() */
 int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
 EOF
+        if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /tmp/qemu-$$-sdl-config.log ; then
+            _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
+            if test "$_sdlversion" -lt 121 ; then
+                sdl_too_old=yes
+            else
+                if test "$cocoa" = "no" ; then
+                    sdl=yes
+                fi
+            fi
 
-if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /dev/null ; then
-_sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
-if test "$_sdlversion" -lt 121 ; then
-sdl_too_old=yes
+            # static link with sdl ?
+            if test "$sdl" = "yes" ; then
+                aa="no"
+                `$sdl_config --static-libs 2>/dev/null | grep \\\-laa > /dev/null` && aa="yes"
+                sdl_static_libs=`$sdl_config --static-libs 2>/dev/null`
+                if [ "$aa" = "yes" ] ; then
+                    sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`"
+                fi
+
+                if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then
+                    sdl_static=yes
+                fi
+            fi # static link
+        fi # sdl compile test
+    fi # cross compilation
 else
- if test "$cocoa" = "no" ; then
-   sdl=yes
- fi
-fi
-
-# static link with sdl ?
-if test "$sdl" = "yes" ; then
-aa="no"
-`$sdl_config --static-libs | grep \\\-laa > /dev/null` && aa="yes"
-sdl_static_libs=`$sdl_config --static-libs`
-if [ "$aa" = "yes" ] ; then
-  sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`"
-fi
-
-if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then
-  sdl_static=yes
-fi
-
-fi # static link
-
-fi # sdl compile test
-
-fi # cross compilation
-
-else
- # Make sure to disable cocoa if sdl was set
- if test "$sdl" = "yes" ; then
-   cocoa="no"
-   coreaudio="no"
- fi
+    # Make sure to disable cocoa if sdl was set
+    if test "$sdl" = "yes" ; then
+       cocoa="no"
+       coreaudio="no"
+    fi
 fi # -z $sdl
 
 ##########################################
+# VNC TLS detection
+if test "$vnc_tls" = "yes" ; then
+  `pkg-config gnutls` || vnc_tls="no"
+fi
+if test "$vnc_tls" = "yes" ; then
+  vnc_tls_cflags=`pkg-config --cflags gnutls`
+  vnc_tls_libs=`pkg-config --libs gnutls`
+fi
+
+##########################################
 # alsa sound support libraries
 
 if test "$alsa" = "yes" ; then
@@ -567,33 +648,34 @@
 fi
 
 # Check if tools are available to build documentation.
-if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
+if [ -x "`which texi2html 2>/dev/null`" ] && \
+   [ -x "`which pod2man 2>/dev/null`" ]; then
   build_docs="yes"
 fi
 
 if test "$mingw32" = "yes" ; then
-if test -z "$prefix" ; then
-    prefix="/c/Program Files/Qemu"
-fi
-mandir="$prefix"
-datadir="$prefix"
-docdir="$prefix"
-bindir="$prefix"
+  if test -z "$prefix" ; then
+      prefix="/c/Program Files/Qemu"
+  fi
+  mansuffix=""
+  datasuffix=""
+  docsuffix=""
+  binsuffix=""
 else
-if test -z "$prefix" ; then
-    prefix="/usr/local"
-fi
-mandir="$prefix/share/man"
-datadir="$prefix/share/qemu"
-docdir="$prefix/share/doc/qemu"
-bindir="$prefix/bin"
+  if test -z "$prefix" ; then
+      prefix="/usr/local"
+  fi
+  mansuffix="/share/man"
+  datasuffix="/share/qemu"
+  docsuffix="/share/doc/qemu"
+  binsuffix="/bin"
 fi
 
 echo "Install prefix    $prefix"
-echo "BIOS directory    $datadir"
-echo "binary directory  $bindir"
+echo "BIOS directory    $prefix$datasuffix"
+echo "binary directory  $prefix$binsuffix"
 if test "$mingw32" = "no" ; then
-echo "Manual directory  $mandir"
+echo "Manual directory  $prefix$mansuffix"
 echo "ELF interp prefix $interp_prefix"
 fi
 echo "Source path       $source_path"
@@ -632,6 +714,15 @@
     fmod_support=""
 fi
 echo "FMOD support      $fmod $fmod_support"
+echo "OSS support       $oss"
+echo "VNC TLS support   $vnc_tls"
+if test "$vnc_tls" = "yes" ; then
+    echo "    TLS CFLAGS    $vnc_tls_cflags"
+    echo "    TLS LIBS      $vnc_tls_libs"
+fi
+if test -n "$sparc_cpu"; then
+    echo "Target Sparc Arch $sparc_cpu"
+fi
 echo "kqemu support     $kqemu"
 echo "kvm support       $kvm"
 echo "Documentation     $build_docs"
@@ -641,6 +732,11 @@
 if test $sdl_too_old = "yes"; then
 echo "-> Your SDL version is too old - please upgrade to have SDL support"
 fi
+if [ -s /tmp/qemu-$$-sdl-config.log ]; then
+  echo "The error log from compiling the libSDL test is: "
+  cat /tmp/qemu-$$-sdl-config.log
+fi
+rm -f /tmp/qemu-$$-sdl-config.log
 #if test "$sdl_static" = "no"; then
 #  echo "WARNING: cannot compile statically with SDL - qemu-fast won't have a graphical output"
 #fi
@@ -649,29 +745,33 @@
 
 #echo "Creating $config_mak and $config_h"
 
+test -f $config_h && mv $config_h ${config_h}~
+
 echo "# Automatically generated by configure - do not modify" > $config_mak
 echo "# Configured with: $0 $@" >> $config_mak
 echo "/* Automatically generated by configure - do not modify */" > $config_h
 
 echo "prefix=$prefix" >> $config_mak
-echo "bindir=$bindir" >> $config_mak
-echo "mandir=$mandir" >> $config_mak
-echo "datadir=$datadir" >> $config_mak
-echo "docdir=$docdir" >> $config_mak
-echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h
+echo "bindir=\${prefix}$binsuffix" >> $config_mak
+echo "mandir=\${prefix}$mansuffix" >> $config_mak
+echo "datadir=\${prefix}$datasuffix" >> $config_mak
+echo "docdir=\${prefix}$docsuffix" >> $config_mak
+echo "#define CONFIG_QEMU_SHAREDIR \"$prefix$datasuffix\"" >> $config_h
 echo "MAKE=$make" >> $config_mak
 echo "INSTALL=$install" >> $config_mak
 echo "CC=$cc" >> $config_mak
-if test "$have_gcc3_options" = "yes" ; then
-  echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
-fi
 echo "HOST_CC=$host_cc" >> $config_mak
 echo "AR=$ar" >> $config_mak
 echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
 echo "OS_CFLAGS=$OS_CFLAGS" >> $config_mak
+echo "OS_LDFLAGS=$OS_LDFLAGS" >> $config_mak
+echo "VL_OS_LDFLAGS=$VL_OS_LDFLAGS" >> $config_mak
+echo "ARCH_CFLAGS=$ARCH_CFLAGS" >> $config_mak
+echo "ARCH_LDFLAGS=$ARCH_LDFLAGS" >> $config_mak
 echo "CFLAGS=$CFLAGS" >> $config_mak
 echo "LDFLAGS=$LDFLAGS" >> $config_mak
 echo "EXESUF=$EXESUF" >> $config_mak
+echo "AIOLIBS=$AIOLIBS" >> $config_mak
 if test "$cpu" = "i386" ; then
   echo "ARCH=i386" >> $config_mak
   echo "#define HOST_I386 1" >> $config_h
@@ -690,6 +790,9 @@
 elif test "$cpu" = "mips" ; then
   echo "ARCH=mips" >> $config_mak
   echo "#define HOST_MIPS 1" >> $config_h
+elif test "$cpu" = "mips64" ; then
+  echo "ARCH=mips64" >> $config_mak
+  echo "#define HOST_MIPS64 1" >> $config_h
 elif test "$cpu" = "s390" ; then
   echo "ARCH=s390" >> $config_mak
   echo "#define HOST_S390 1" >> $config_h
@@ -709,7 +812,7 @@
   echo "ARCH=m68k" >> $config_mak
   echo "#define HOST_M68K 1" >> $config_h
 else
-  echo "Unsupported CPU"
+  echo "Unsupported CPU = $cpu"
   exit 1
 fi
 if test "$bigendian" = "yes" ; then
@@ -720,8 +823,14 @@
 if test "$mingw32" = "yes" ; then
   echo "CONFIG_WIN32=yes" >> $config_mak
   echo "#define CONFIG_WIN32 1" >> $config_h
-elif test -f "/usr/include/byteswap.h" ; then
-  echo "#define HAVE_BYTESWAP_H 1" >> $config_h
+else
+  cat > $TMPC << EOF
+#include <byteswap.h>
+int main(void) { return bswap_32(0); }
+EOF
+  if $cc -o $TMPE $TMPC 2> /dev/null ; then
+    echo "#define HAVE_BYTESWAP_H 1" >> $config_h
+  fi
 fi
 if test "$darwin" = "yes" ; then
   echo "CONFIG_DARWIN=yes" >> $config_mak
@@ -730,6 +839,14 @@
 if test "$solaris" = "yes" ; then
   echo "CONFIG_SOLARIS=yes" >> $config_mak
   echo "#define HOST_SOLARIS $solarisrev" >> $config_h
+  if test "$needs_libsunmath" = "yes" ; then
+    echo "NEEDS_LIBSUNMATH=yes" >> $config_mak
+    echo "#define NEEDS_LIBSUNMATH 1" >> $config_h
+  fi
+fi
+if test -n "$sparc_cpu"; then
+  echo "CONFIG__sparc_${sparc_cpu}__=yes" >> $config_mak
+  echo "#define __sparc_${sparc_cpu}__ 1" >> $config_h
 fi
 if test "$gdbstub" = "yes" ; then
   echo "CONFIG_GDBSTUB=yes" >> $config_mak
@@ -776,6 +893,12 @@
   echo "CONFIG_FMOD_INC=$fmod_inc" >> $config_mak
   echo "#define CONFIG_FMOD 1" >> $config_h
 fi
+if test "$vnc_tls" = "yes" ; then
+  echo "CONFIG_VNC_TLS=yes" >> $config_mak
+  echo "CONFIG_VNC_TLS_CFLAGS=$vnc_tls_cflags" >> $config_mak
+  echo "CONFIG_VNC_TLS_LIBS=$vnc_tls_libs" >> $config_mak
+  echo "#define CONFIG_VNC_TLS 1" >> $config_h
+fi
 qemu_version=`head $source_path/VERSION`
 echo "VERSION=$qemu_version" >>$config_mak
 echo "#define QEMU_VERSION \"$qemu_version\"" >> $config_h
@@ -798,6 +921,14 @@
 
 echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
 
+tools=
+if test `expr "$target_list" : ".*softmmu.*"` != 0 ; then
+  tools="qemu-img\$(EXESUF) $tools"
+fi
+echo "TOOLS=$tools" >> $config_mak
+
+test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h
+
 for target in $target_list; do
 target_dir="$target"
 config_mak=$target_dir/config.mak
@@ -809,27 +940,33 @@
 [ "$target_cpu" = "sparc64" ] && target_bigendian=yes
 [ "$target_cpu" = "ppc" ] && target_bigendian=yes
 [ "$target_cpu" = "ppc64" ] && target_bigendian=yes
+[ "$target_cpu" = "ppcemb" ] && target_bigendian=yes
 [ "$target_cpu" = "mips" ] && target_bigendian=yes
+[ "$target_cpu" = "mipsn32" ] && target_bigendian=yes
+[ "$target_cpu" = "mips64" ] && target_bigendian=yes
 [ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
 [ "$target_cpu" = "m68k" ] && target_bigendian=yes
 target_softmmu="no"
-if expr $target : '.*-softmmu' > /dev/null ; then
-  target_softmmu="yes"
-fi
 target_user_only="no"
-if expr $target : '.*-user' > /dev/null ; then
-  target_user_only="yes"
-fi
-
 target_linux_user="no"
-if expr $target : '.*-linux-user' > /dev/null ; then
-  target_linux_user="yes"
-fi
-
 target_darwin_user="no"
-if expr $target : '.*-darwin-user' > /dev/null ; then
-  target_darwin_user="yes"
-fi
+case "$target" in
+  ${target_cpu}-softmmu)
+    target_softmmu="yes"
+    ;;
+  ${target_cpu}-linux-user)
+    target_user_only="yes"
+    target_linux_user="yes"
+    ;;
+  ${target_cpu}-darwin-user)
+    target_user_only="yes"
+    target_darwin_user="yes"
+    ;;
+  *)
+    echo "ERROR: Target '$target' not recognised"
+    exit 1
+    ;;
+esac
 
 if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
         -a "$sdl" = "no" -a "$cocoa" = "no" ; then
@@ -841,6 +978,8 @@
 
 #echo "Creating $config_mak, $config_h and $target_dir/Makefile"
 
+test -f $config_h && mv $config_h ${config_h}~
+
 mkdir -p $target_dir
 mkdir -p $target_dir/fpu
 if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then
@@ -907,6 +1046,11 @@
   echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
   echo "#define TARGET_PPC 1" >> $config_h
   echo "#define TARGET_PPC64 1" >> $config_h
+elif test "$target_cpu" = "ppcemb" ; then
+  echo "TARGET_ARCH=ppcemb" >> $config_mak
+  echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h
+  echo "#define TARGET_PPC 1" >> $config_h
+  echo "#define TARGET_PPCEMB 1" >> $config_h
 elif test "$target_cpu" = "x86_64" ; then
   echo "TARGET_ARCH=x86_64" >> $config_mak
   echo "#define TARGET_ARCH \"x86_64\"" >> $config_h
@@ -920,8 +1064,16 @@
   echo "TARGET_ARCH=mips" >> $config_mak
   echo "#define TARGET_ARCH \"mips\"" >> $config_h
   echo "#define TARGET_MIPS 1" >> $config_h
-  echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
-  echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
+elif test "$target_cpu" = "mipsn32" -o "$target_cpu" = "mipsn32el" ; then
+  echo "TARGET_ARCH=mipsn32" >> $config_mak
+  echo "#define TARGET_ARCH \"mipsn32\"" >> $config_h
+  echo "#define TARGET_MIPS 1" >> $config_h
+  echo "#define TARGET_MIPSN32 1" >> $config_h
+elif test "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el" ; then
+  echo "TARGET_ARCH=mips64" >> $config_mak
+  echo "#define TARGET_ARCH \"mips64\"" >> $config_h
+  echo "#define TARGET_MIPS 1" >> $config_h
+  echo "#define TARGET_MIPS64 1" >> $config_h
 elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
   echo "TARGET_ARCH=sh4" >> $config_mak
   echo "#define TARGET_ARCH \"sh4\"" >> $config_h
@@ -932,6 +1084,10 @@
   echo "#define TARGET_ARCH \"m68k\"" >> $config_h
   echo "#define TARGET_M68K 1" >> $config_h
   bflt="yes"
+elif test "$target_cpu" = "alpha" ; then
+  echo "TARGET_ARCH=alpha" >> $config_mak
+  echo "#define TARGET_ARCH \"alpha\"" >> $config_h
+  echo "#define TARGET_ALPHA 1" >> $config_h
 else
   echo "Unsupported target CPU"
   exit 1
@@ -957,7 +1113,7 @@
   echo "#define CONFIG_DARWIN_USER 1" >> $config_h
 fi
 
-if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then
+if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k" -o "$target_cpu" = "mips" -o "$target_cpu" = "mipsel" -o "$target_cpu" = "mipsn32" -o "$target_cpu" = "mipsn32el" -o "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el"; then
   echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
   echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
 fi
@@ -994,6 +1150,8 @@
     echo "CONFIG_COCOA=yes" >> $config_mak
 fi
 
+test -f ${config_h}~ && cmp -s $config_h ${config_h}~ && mv ${config_h}~ $config_h
+
 done # for target in $targets
 
 # build tree in object directory if source path is different from current one
diff --git a/console.c b/console.c
index 2b3cd66..ff725c2 100644
--- a/console.c
+++ b/console.c
@@ -1,8 +1,8 @@
 /*
  * QEMU graphical console
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -104,10 +104,16 @@
     return len1;
 }
 
+typedef enum {
+    GRAPHIC_CONSOLE,
+    TEXT_CONSOLE,
+    TEXT_CONSOLE_FIXED_SIZE
+} console_type_t;
+
 /* ??? This is mis-named.
    It is used for both text and graphical consoles.  */
 struct TextConsole {
-    int text_console; /* true if text console */
+    console_type_t console_type;
     DisplayState *ds;
     /* Graphic console state.  */
     vga_hw_update_ptr hw_update;
@@ -174,8 +180,8 @@
         r = (rgba >> 16) & 0xff;
         g = (rgba >> 8) & 0xff;
         b = (rgba) & 0xff;
-        color = (rgb_to_index[r] * 6 * 6) + 
-            (rgb_to_index[g] * 6) + 
+        color = (rgb_to_index[r] * 6 * 6) +
+            (rgb_to_index[g] * 6) +
             (rgb_to_index[b]);
         break;
 #endif
@@ -199,14 +205,14 @@
     return color;
 }
 
-static void vga_fill_rect (DisplayState *ds, 
+static void vga_fill_rect (DisplayState *ds,
                            int posx, int posy, int width, int height, uint32_t color)
 {
     uint8_t *d, *d1;
     int x, y, bpp;
-    
+
     bpp = (ds->depth + 7) >> 3;
-    d1 = ds->data + 
+    d1 = ds->data +
         ds->linesize * posy + bpp * posx;
     for (y = 0; y < height; y++) {
         d = d1;
@@ -244,9 +250,9 @@
     bpp = (ds->depth + 7) >> 3;
     wb = w * bpp;
     if (yd <= ys) {
-        s = ds->data + 
+        s = ds->data +
             ds->linesize * ys + bpp * xs;
-        d = ds->data + 
+        d = ds->data +
             ds->linesize * yd + bpp * xd;
         for (y = 0; y < h; y++) {
             memmove(d, s, wb);
@@ -254,9 +260,9 @@
             s += ds->linesize;
         }
     } else {
-        s = ds->data + 
+        s = ds->data +
             ds->linesize * (ys + h - 1) + bpp * xs;
-        d = ds->data + 
+        d = ds->data +
             ds->linesize * (yd + h - 1) + bpp * xd;
        for (y = 0; y < h; y++) {
             memmove(d, s, wb);
@@ -399,7 +405,7 @@
 }
 #endif
 
-static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
+static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
                           TextAttributes *t_attrib)
 {
     uint8_t *d;
@@ -422,7 +428,7 @@
     }
 
     bpp = (ds->depth + 7) >> 3;
-    d = ds->data + 
+    d = ds->data +
         ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
     linesize = ds->linesize;
     font_ptr = vgafont16 + FONT_HEIGHT * ch;
@@ -519,9 +525,9 @@
             y2 += s->total_height;
         if (y2 < s->height) {
             c = &s->cells[y1 * s->width + x];
-            vga_putcharxy(s->ds, x, y2, c->ch, 
+            vga_putcharxy(s->ds, x, y2, c->ch,
                           &(c->t_attrib));
-            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, 
+            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
                        FONT_WIDTH, FONT_HEIGHT);
         }
     }
@@ -533,21 +539,24 @@
     int y, y1;
 
     if (s == active_console) {
+        int x = s->x;
+        if (x >= s->width) {
+            x = s->width - 1;
+        }
         y1 = (s->y_base + s->y) % s->total_height;
         y = y1 - s->y_displayed;
         if (y < 0)
             y += s->total_height;
         if (y < s->height) {
-            c = &s->cells[y1 * s->width + s->x];
+            c = &s->cells[y1 * s->width + x];
             if (show) {
                 TextAttributes t_attrib = s->t_attrib_default;
                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
-                vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
+                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
             } else {
-                vga_putcharxy(s->ds, s->x, y, c->ch, 
-                              &(c->t_attrib));
+                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
             }
-            dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
+            dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
                        FONT_WIDTH, FONT_HEIGHT);
         }
     }
@@ -558,7 +567,7 @@
     TextCell *c;
     int x, y, y1;
 
-    if (s != active_console) 
+    if (s != active_console)
         return;
 
     vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
@@ -567,7 +576,7 @@
     for(y = 0; y < s->height; y++) {
         c = s->cells + y1 * s->width;
         for(x = 0; x < s->width; x++) {
-            vga_putcharxy(s->ds, x, y, c->ch, 
+            vga_putcharxy(s->ds, x, y, c->ch,
                           &(c->t_attrib));
             c++;
         }
@@ -582,9 +591,9 @@
 {
     TextConsole *s;
     int i, y1;
-    
+
     s = active_console;
-    if (!s || !s->text_console)
+    if (!s || (s->console_type == GRAPHIC_CONSOLE))
         return;
 
     if (ydelta > 0) {
@@ -637,13 +646,13 @@
             c++;
         }
         if (s == active_console && s->y_displayed == s->y_base) {
-            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
-                       s->width * FONT_WIDTH, 
+            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
+                       s->width * FONT_WIDTH,
                        (s->height - 1) * FONT_HEIGHT);
             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
-                          s->width * FONT_WIDTH, FONT_HEIGHT, 
+                          s->width * FONT_WIDTH, FONT_HEIGHT,
                           color_table[0][s->t_attrib_default.bgcol]);
-            dpy_update(s->ds, 0, 0, 
+            dpy_update(s->ds, 0, 0,
                        s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
         }
     }
@@ -772,7 +781,7 @@
             console_put_lf(s);
             break;
         case '\b':  /* backspace */
-            if (s->x > 0) 
+            if (s->x > 0)
                 s->x--;
             break;
         case '\t':  /* tabspace */
@@ -796,8 +805,10 @@
             s->state = TTY_STATE_ESC;
             break;
         default:
-            if (s->x >= s->width - 1) {
-                break;
+            if (s->x >= s->width) {
+                /* line wrap */
+                s->x = 0;
+                console_put_lf(s);
             }
             y1 = (s->y_base + s->y) % s->total_height;
             c = &s->cells[y1 * s->width + s->x];
@@ -805,12 +816,6 @@
             c->t_attrib = s->t_attrib;
             update_xy(s, s->x, s->y);
             s->x++;
-#if 0 /* line wrap disabled */
-            if (s->x >= s->width) {
-                s->x = 0;
-                console_put_lf(s);
-            }
-#endif
             break;
         }
         break;
@@ -827,7 +832,7 @@
     case TTY_STATE_CSI: /* handle escape sequence parameters */
         if (ch >= '0' && ch <= '9') {
             if (s->nb_esc_params < MAX_ESC_PARAMS) {
-                s->esc_params[s->nb_esc_params] = 
+                s->esc_params[s->nb_esc_params] =
                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
             }
         } else {
@@ -991,13 +996,17 @@
     s = consoles[index];
     if (s) {
         active_console = s;
-        if (s->text_console) {
+        if (s->console_type != GRAPHIC_CONSOLE) {
             if (s->g_width != s->ds->width ||
                 s->g_height != s->ds->height) {
+                if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) {
+                    dpy_resize(s->ds, s->g_width, s->g_height);
+                } else {
                 s->g_width = s->ds->width;
                 s->g_height = s->ds->height;
                 text_console_resize(s);
             }
+            }
             console_refresh(s);
         } else {
             vga_hw_invalidate();
@@ -1038,7 +1047,7 @@
     TextConsole *s = opaque;
     int len;
     uint8_t buf[16];
-    
+
     len = qemu_chr_can_read(s->chr);
     if (len > s->out_fifo.count)
         len = s->out_fifo.count;
@@ -1063,7 +1072,7 @@
     int c;
 
     s = active_console;
-    if (!s || !s->text_console)
+    if (!s || (s->console_type == GRAPHIC_CONSOLE))
         return;
 
     switch(keysym) {
@@ -1105,7 +1114,7 @@
     }
 }
 
-static TextConsole *new_console(DisplayState *ds, int text)
+static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
 {
     TextConsole *s;
     int i;
@@ -1116,16 +1125,18 @@
     if (!s) {
         return NULL;
     }
-    if (!active_console || (active_console->text_console && !text))
+    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
+        (console_type == GRAPHIC_CONSOLE))) {
         active_console = s;
+    }
     s->ds = ds;
-    s->text_console = text;
-    if (text) {
+    s->console_type = console_type;
+    if (console_type != GRAPHIC_CONSOLE) {
         consoles[nb_consoles++] = s;
     } else {
         /* HACK: Put graphical consoles before text consoles.  */
         for (i = nb_consoles; i > 0; i--) {
-            if (!consoles[i - 1]->text_console)
+            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
                 break;
             consoles[i] = consoles[i - 1];
         }
@@ -1141,7 +1152,7 @@
 {
     TextConsole *s;
 
-    s = new_console(ds, 0);
+    s = new_console(ds, GRAPHIC_CONSOLE);
     if (!s)
       return NULL;
     s->hw_update = update;
@@ -1153,20 +1164,22 @@
 
 int is_graphic_console(void)
 {
-    return !active_console->text_console;
+    return active_console->console_type == GRAPHIC_CONSOLE;
 }
 
-CharDriverState *text_console_init(DisplayState *ds)
+CharDriverState *text_console_init(DisplayState *ds, const char *p)
 {
     CharDriverState *chr;
     TextConsole *s;
     int i,j;
+    unsigned width;
+    unsigned height;
     static int color_inited;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
     if (!chr)
         return NULL;
-    s = new_console(ds, 1);
+    s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
     if (!s) {
         free(chr);
         return NULL;
@@ -1179,12 +1192,12 @@
     s->out_fifo.buf = s->out_fifo_buf;
     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
-    
+
     if (!color_inited) {
         color_inited = 1;
         for(j = 0; j < 2; j++) {
             for(i = 0; i < 8; i++) {
-                color_table[j][i] = col_expand(s->ds, 
+                color_table[j][i] = col_expand(s->ds,
                         vga_get_color(s->ds, color_table_rgb[j][i]));
             }
         }
@@ -1194,8 +1207,25 @@
     s->total_height = DEFAULT_BACKSCROLL;
     s->x = 0;
     s->y = 0;
-    s->g_width = s->ds->width;
-    s->g_height = s->ds->height;
+    width = s->ds->width;
+    height = s->ds->height;
+    if (p != 0) {
+        width = strtoul(p, (char **)&p, 10);
+        if (*p == 'C') {
+            p++;
+            width *= FONT_WIDTH;
+        }
+        if (*p == 'x') {
+            p++;
+            height = strtoul(p, (char **)&p, 10);
+            if (*p == 'C') {
+                p++;
+                height *= FONT_HEIGHT;
+            }
+        }
+    }
+    s->g_width = width;
+    s->g_height = height;
 
     /* Set text attribute defaults */
     s->t_attrib_default.bold = 0;
diff --git a/cpu-all.h b/cpu-all.h
index 1989094..8ccbace 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -1,6 +1,6 @@
 /*
  * defines common to all virtual CPUs
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -20,20 +20,20 @@
 #ifndef CPU_ALL_H
 #define CPU_ALL_H
 
-#if defined(__arm__) || defined(__sparc__)
+#if defined(__arm__) || defined(__sparc__) || defined(__mips__)
 #define WORDS_ALIGNED
 #endif
 
-/* some important defines: 
- * 
+/* some important defines:
+ *
  * WORDS_ALIGNED : if defined, the host cpu can only make word aligned
  * memory accesses.
- * 
+ *
  * WORDS_BIGENDIAN : if defined, the host cpu is big endian and
  * otherwise little endian.
- * 
+ *
  * (TARGET_WORDS_ALIGNED : same for target cpu (not supported yet))
- * 
+ *
  * TARGET_WORDS_BIGENDIAN : same for target cpu
  */
 
@@ -147,7 +147,7 @@
  * type is:
  * (empty): integer access
  *   f    : float access
- * 
+ *
  * sign is:
  * (empty): for floats or 32 bit size
  *   u    : unsigned
@@ -158,7 +158,7 @@
  *   w: 16 bits
  *   l: 32 bits
  *   q: 64 bits
- * 
+ *
  * endian is:
  * (empty): target cpu endianness or 8 bit access
  *   r    : reversed target cpu endianness (not implemented yet)
@@ -621,7 +621,7 @@
 #define stfq_raw(p, v) stfq_p(saddr((p)), v)
 
 
-#if defined(CONFIG_USER_ONLY) 
+#if defined(CONFIG_USER_ONLY)
 
 /* if user mode, no other memory access functions */
 #define ldub(p) ldub_raw(p)
@@ -644,12 +644,14 @@
 #define lduw_code(p) lduw_raw(p)
 #define ldsw_code(p) ldsw_raw(p)
 #define ldl_code(p) ldl_raw(p)
+#define ldq_code(p) ldq_raw(p)
 
 #define ldub_kernel(p) ldub_raw(p)
 #define ldsb_kernel(p) ldsb_raw(p)
 #define lduw_kernel(p) lduw_raw(p)
 #define ldsw_kernel(p) ldsw_raw(p)
 #define ldl_kernel(p) ldl_raw(p)
+#define ldq_kernel(p) ldq_raw(p)
 #define ldfl_kernel(p) ldfl_raw(p)
 #define ldfq_kernel(p) ldfq_raw(p)
 #define stb_kernel(p, v) stb_raw(p, v)
@@ -683,82 +685,25 @@
 #define PAGE_VALID     0x0008
 /* original state of the write flag (used when tracking self-modifying
    code */
-#define PAGE_WRITE_ORG 0x0010 
+#define PAGE_WRITE_ORG 0x0010
 
 void page_dump(FILE *f);
 int page_get_flags(target_ulong address);
 void page_set_flags(target_ulong start, target_ulong end, int flags);
 void page_unprotect_range(target_ulong data, target_ulong data_size);
 
-#define SINGLE_CPU_DEFINES
-#ifdef SINGLE_CPU_DEFINES
+CPUState *cpu_copy(CPUState *env);
 
-#if defined(TARGET_I386)
-
-#define CPUState CPUX86State
-#define cpu_init cpu_x86_init
-#define cpu_exec cpu_x86_exec
-#define cpu_gen_code cpu_x86_gen_code
-#define cpu_signal_handler cpu_x86_signal_handler
-
-#elif defined(TARGET_ARM)
-
-#define CPUState CPUARMState
-#define cpu_init cpu_arm_init
-#define cpu_exec cpu_arm_exec
-#define cpu_gen_code cpu_arm_gen_code
-#define cpu_signal_handler cpu_arm_signal_handler
-
-#elif defined(TARGET_SPARC)
-
-#define CPUState CPUSPARCState
-#define cpu_init cpu_sparc_init
-#define cpu_exec cpu_sparc_exec
-#define cpu_gen_code cpu_sparc_gen_code
-#define cpu_signal_handler cpu_sparc_signal_handler
-
-#elif defined(TARGET_PPC)
-
-#define CPUState CPUPPCState
-#define cpu_init cpu_ppc_init
-#define cpu_exec cpu_ppc_exec
-#define cpu_gen_code cpu_ppc_gen_code
-#define cpu_signal_handler cpu_ppc_signal_handler
-
-#elif defined(TARGET_M68K)
-#define CPUState CPUM68KState
-#define cpu_init cpu_m68k_init
-#define cpu_exec cpu_m68k_exec
-#define cpu_gen_code cpu_m68k_gen_code
-#define cpu_signal_handler cpu_m68k_signal_handler
-
-#elif defined(TARGET_MIPS)
-#define CPUState CPUMIPSState
-#define cpu_init cpu_mips_init
-#define cpu_exec cpu_mips_exec
-#define cpu_gen_code cpu_mips_gen_code
-#define cpu_signal_handler cpu_mips_signal_handler
-
-#elif defined(TARGET_SH4)
-#define CPUState CPUSH4State
-#define cpu_init cpu_sh4_init
-#define cpu_exec cpu_sh4_exec
-#define cpu_gen_code cpu_sh4_gen_code
-#define cpu_signal_handler cpu_sh4_signal_handler
-
-#else
-
-#error unsupported target CPU
-
-#endif
-
-#endif /* SINGLE_CPU_DEFINES */
-
-void cpu_dump_state(CPUState *env, FILE *f, 
+void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags);
+void cpu_dump_statistics (CPUState *env, FILE *f,
+                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                          int flags);
 
-void cpu_abort(CPUState *env, const char *fmt, ...);
+void cpu_abort(CPUState *env, const char *fmt, ...)
+    __attribute__ ((__format__ (__printf__, 2, 3)))
+    __attribute__ ((__noreturn__));
 extern CPUState *first_cpu;
 extern CPUState *cpu_single_env;
 extern int code_copy_enabled;
@@ -770,10 +715,14 @@
 #define CPU_INTERRUPT_FIQ    0x10 /* Fast interrupt pending.  */
 #define CPU_INTERRUPT_HALT   0x20 /* CPU halt wanted */
 #define CPU_INTERRUPT_SMI    0x40 /* (x86 only) SMI interrupt pending */
+#define CPU_INTERRUPT_DEBUG  0x80 /* Debug event occured.  */
+#define CPU_INTERRUPT_VIRQ   0x100 /* virtual interrupt pending.  */
 
 void cpu_interrupt(CPUState *s, int mask);
 void cpu_reset_interrupt(CPUState *env, int mask);
 
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr);
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr);
 int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
 int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
 void cpu_single_step(CPUState *env, int enabled);
@@ -782,9 +731,9 @@
 /* Return the physical page corresponding to a virtual one. Use it
    only for debugging because no protection checks are done. Return -1
    if no page found. */
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
 
-#define CPU_LOG_TB_OUT_ASM (1 << 0) 
+#define CPU_LOG_TB_OUT_ASM (1 << 0)
 #define CPU_LOG_TB_IN_ASM  (1 << 1)
 #define CPU_LOG_TB_OP      (1 << 2)
 #define CPU_LOG_TB_OP_OPT  (1 << 3)
@@ -841,14 +790,17 @@
    exception, the write memory callback gets the ram offset instead of
    the physical address */
 #define IO_MEM_ROMD        (1)
+#define IO_MEM_SUBPAGE     (2)
 
 typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
 typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
 
-void cpu_register_physical_memory(target_phys_addr_t start_addr, 
+void cpu_register_physical_memory(target_phys_addr_t start_addr,
                                   unsigned long size,
                                   unsigned long phys_offset);
 uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr);
+ram_addr_t qemu_ram_alloc(unsigned int size);
+void qemu_ram_free(ram_addr_t addr);
 int cpu_register_io_memory(int io_index,
                            CPUReadMemoryFunc **mem_read,
                            CPUWriteMemoryFunc **mem_write,
@@ -858,12 +810,12 @@
 
 void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write);
-static inline void cpu_physical_memory_read(target_phys_addr_t addr, 
+static inline void cpu_physical_memory_read(target_phys_addr_t addr,
                                             uint8_t *buf, int len)
 {
     cpu_physical_memory_rw(addr, buf, len, 0);
 }
-static inline void cpu_physical_memory_write(target_phys_addr_t addr, 
+static inline void cpu_physical_memory_write(target_phys_addr_t addr,
                                              const uint8_t *buf, int len)
 {
     cpu_physical_memory_rw(addr, (uint8_t *)buf, len, 1);
@@ -873,14 +825,15 @@
 uint32_t ldl_phys(target_phys_addr_t addr);
 uint64_t ldq_phys(target_phys_addr_t addr);
 void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
+void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
 void stb_phys(target_phys_addr_t addr, uint32_t val);
 void stw_phys(target_phys_addr_t addr, uint32_t val);
 void stl_phys(target_phys_addr_t addr, uint32_t val);
 void stq_phys(target_phys_addr_t addr, uint64_t val);
 
-void cpu_physical_memory_write_rom(target_phys_addr_t addr, 
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
                                    const uint8_t *buf, int len);
-int cpu_memory_rw_debug(CPUState *env, target_ulong addr, 
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write);
 
 #define VGA_DIRTY_FLAG  0x01
@@ -893,7 +846,7 @@
     return phys_ram_dirty[addr >> TARGET_PAGE_BITS] == 0xff;
 }
 
-static inline int cpu_physical_memory_get_dirty(ram_addr_t addr, 
+static inline int cpu_physical_memory_get_dirty(ram_addr_t addr,
                                                 int dirty_flags)
 {
     return phys_ram_dirty[addr >> TARGET_PAGE_BITS] & dirty_flags;
@@ -920,14 +873,14 @@
 
 #if defined(__powerpc__)
 
-static inline uint32_t get_tbl(void) 
+static inline uint32_t get_tbl(void)
 {
     uint32_t tbl;
     asm volatile("mftb %0" : "=r" (tbl));
     return tbl;
 }
 
-static inline uint32_t get_tbu(void) 
+static inline uint32_t get_tbu(void)
 {
 	uint32_t tbl;
 	asm volatile("mftbu %0" : "=r" (tbl));
@@ -986,7 +939,7 @@
     return val;
 }
 
-#elif defined(__sparc_v9__)
+#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
 
 static inline int64_t cpu_get_real_ticks (void)
 {
@@ -1007,10 +960,31 @@
         return rval.i64;
 #endif
 }
+
+#elif defined(__mips__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+#if __mips_isa_rev >= 2
+    uint32_t count;
+    static uint32_t cyc_per_count = 0;
+
+    if (!cyc_per_count)
+        __asm__ __volatile__("rdhwr %0, $3" : "=r" (cyc_per_count));
+
+    __asm__ __volatile__("rdhwr %1, $2" : "=r" (count));
+    return (int64_t)(count * cyc_per_count);
+#else
+    /* FIXME */
+    static int64_t ticks = 0;
+    return ticks++;
+#endif
+}
+
 #else
 /* The host CPU doesn't have an easily accessible cycle counter.
-   Just return a monotonically increasing vlue.  This will be totally wrong,
-   but hopefully better than nothing.  */
+   Just return a monotonically increasing value.  This will be
+   totally wrong, but hopefully better than nothing.  */
 static inline int64_t cpu_get_real_ticks (void)
 {
     static int64_t ticks = 0;
diff --git a/cpu-defs.h b/cpu-defs.h
index 0b49c89..9158776 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -1,6 +1,6 @@
 /*
  * common defines for all CPUs
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -29,7 +29,7 @@
 #error TARGET_LONG_BITS must be defined before including this header
 #endif
 
-#ifndef TARGET_PHYS_ADDR_BITS 
+#ifndef TARGET_PHYS_ADDR_BITS
 #if TARGET_LONG_BITS >= HOST_LONG_BITS
 #define TARGET_PHYS_ADDR_BITS TARGET_LONG_BITS
 #else
@@ -44,10 +44,14 @@
 typedef int32_t target_long;
 typedef uint32_t target_ulong;
 #define TARGET_FMT_lx "%08x"
+#define TARGET_FMT_ld "%d"
+#define TARGET_FMT_lu "%u"
 #elif TARGET_LONG_SIZE == 8
 typedef int64_t target_long;
 typedef uint64_t target_ulong;
 #define TARGET_FMT_lx "%016" PRIx64
+#define TARGET_FMT_ld "%" PRId64
+#define TARGET_FMT_lu "%" PRIu64
 #else
 #error TARGET_LONG_SIZE undefined
 #endif
@@ -60,8 +64,10 @@
 
 #if TARGET_PHYS_ADDR_BITS == 32
 typedef uint32_t target_phys_addr_t;
+#define TARGET_FMT_plx "%08x"
 #elif TARGET_PHYS_ADDR_BITS == 64
 typedef uint64_t target_phys_addr_t;
+#define TARGET_FMT_plx "%016" PRIx64
 #else
 #error TARGET_PHYS_ADDR_BITS undefined
 #endif
@@ -76,6 +82,7 @@
 #define EXCP_DEBUG      0x10002 /* cpu stopped after a breakpoint or singlestep */
 #define EXCP_HALTED     0x10003 /* cpu is halted (waiting for external event) */
 #define MAX_BREAKPOINTS 32
+#define MAX_WATCHPOINTS 32
 
 #define TB_JMP_CACHE_BITS 12
 #define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
@@ -92,19 +99,28 @@
 #define CPU_TLB_SIZE (1 << CPU_TLB_BITS)
 
 typedef struct CPUTLBEntry {
-    /* bit 31 to TARGET_PAGE_BITS : virtual address 
+    /* bit 31 to TARGET_PAGE_BITS : virtual address
        bit TARGET_PAGE_BITS-1..IO_MEM_SHIFT : if non zero, memory io
                                               zone number
        bit 3                      : indicates that the entry is invalid
        bit 2..0                   : zero
     */
-    target_ulong addr_read; 
-    target_ulong addr_write; 
-    target_ulong addr_code; 
+    target_ulong addr_read;
+    target_ulong addr_write;
+    target_ulong addr_code;
     /* addend to virtual address to get physical address */
-    target_phys_addr_t addend; 
+    target_phys_addr_t addend;
 } CPUTLBEntry;
 
+/* Alpha has 4 different running levels */
+#if defined(TARGET_ALPHA)
+#define NB_MMU_MODES 4
+#elif defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+#define NB_MMU_MODES 3
+#else
+#define NB_MMU_MODES 2
+#endif
+
 #define CPU_COMMON                                                      \
     struct TranslationBlock *current_tb; /* currently executing TB  */  \
     /* soft mmu support */                                              \
@@ -116,7 +132,7 @@
     target_ulong mem_write_vaddr; /* target virtual addr at which the   \
                                      memory was written */              \
     /* 0 = kernel, 1 = user */                                          \
-    CPUTLBEntry tlb_table[2][CPU_TLB_SIZE];                             \
+    CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE];                  \
     struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE];           \
                                                                         \
     /* from this point: preserved by CPU reset */                       \
@@ -125,6 +141,13 @@
     int nb_breakpoints;                                                 \
     int singlestep_enabled;                                             \
                                                                         \
+    struct {                                                            \
+        target_ulong vaddr;                                             \
+        target_phys_addr_t addend;                                      \
+    } watchpoint[MAX_WATCHPOINTS];                                      \
+    int nb_watchpoints;                                                 \
+    int watchpoint_hit;                                                 \
+                                                                        \
     void *next_cpu; /* next CPU sharing TB cache */                     \
     int cpu_index; /* CPU index (informative) */                        \
     /* user data */                                                     \
diff --git a/cpu-exec.c b/cpu-exec.c
index e1293ad..79e18eb 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -1,6 +1,6 @@
 /*
  *  i386 emulator main execution loop
- * 
+ *
  *  Copyright (c) 2003-2005 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -45,13 +45,14 @@
 //#define DEBUG_EXEC
 //#define DEBUG_SIGNAL
 
-#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K)
-/* XXX: unify with i386 target */
 void cpu_loop_exit(void)
 {
+    /* NOTE: the register at this point must be saved by hand because
+       longjmp restore them */
+    regs_to_env();
     longjmp(env->jmp_env, 1);
 }
-#endif
+
 #if !(defined(TARGET_SPARC) || defined(TARGET_SH4) || defined(TARGET_M68K))
 #define reg_T2
 #endif
@@ -59,7 +60,7 @@
 /* exit the current TB from a signal handler. The host registers are
    restored in a state compatible with the CPU emulator
  */
-void cpu_resume_from_signal(CPUState *env1, void *puc) 
+void cpu_resume_from_signal(CPUState *env1, void *puc)
 {
 #if !defined(CONFIG_SOFTMMU)
     struct ucontext *uc = puc;
@@ -81,20 +82,20 @@
 
 static TranslationBlock *tb_find_slow(target_ulong pc,
                                       target_ulong cs_base,
-                                      unsigned int flags)
+                                      uint64_t flags)
 {
     TranslationBlock *tb, **ptb1;
     int code_gen_size;
     unsigned int h;
     target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
     uint8_t *tc_ptr;
-    
+
     spin_lock(&tb_lock);
 
     tb_invalidated_flag = 0;
-    
+
     regs_to_env(); /* XXX: do it just before cpu_gen_code() */
-    
+
     /* find translated block using physical mappings */
     phys_pc = get_phys_addr_code(env, pc);
     phys_page1 = phys_pc & TARGET_PAGE_MASK;
@@ -105,13 +106,13 @@
         tb = *ptb1;
         if (!tb)
             goto not_found;
-        if (tb->pc == pc && 
+        if (tb->pc == pc &&
             tb->page_addr[0] == phys_page1 &&
-            tb->cs_base == cs_base && 
+            tb->cs_base == cs_base &&
             tb->flags == flags) {
             /* check next page if needed */
             if (tb->page_addr[1] != -1) {
-                virt_page2 = (pc & TARGET_PAGE_MASK) + 
+                virt_page2 = (pc & TARGET_PAGE_MASK) +
                     TARGET_PAGE_SIZE;
                 phys_page2 = get_phys_addr_code(env, virt_page2);
                 if (tb->page_addr[1] == phys_page2)
@@ -139,7 +140,7 @@
     tb->flags = flags;
     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
-    
+
     /* check next page if needed */
     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
     phys_page2 = -1;
@@ -147,7 +148,7 @@
         phys_page2 = get_phys_addr_code(env, virt_page2);
     }
     tb_link_phys(tb, phys_pc, phys_page2);
-    
+
  found:
     /* we add the TB in the virtual pc hash table */
     env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
@@ -159,7 +160,7 @@
 {
     TranslationBlock *tb;
     target_ulong cs_base, pc;
-    unsigned int flags;
+    uint64_t flags;
 
     /* we record a subset of the CPU state. It will
        always be the same before a given translated block
@@ -167,6 +168,7 @@
 #if defined(TARGET_I386)
     flags = env->hflags;
     flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
+    flags |= env->intercept;
     cs_base = env->segs[R_CS].base;
     pc = cs_base + env->eip;
 #elif defined(TARGET_ARM)
@@ -184,29 +186,35 @@
     flags = (((env->pstate & PS_PEF) >> 1) | ((env->fprs & FPRS_FEF) << 2))
         | (env->pstate & PS_PRIV) | ((env->lsu & (DMMU_E | IMMU_E)) >> 2);
 #else
-    // FPU enable . MMU enabled . MMU no-fault . Supervisor
-    flags = (env->psref << 3) | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
+    // FPU enable . MMU Boot . MMU enabled . MMU no-fault . Supervisor
+    flags = (env->psref << 4) | (((env->mmuregs[0] & MMU_BM) >> 14) << 3)
+        | ((env->mmuregs[0] & (MMU_E | MMU_NF)) << 1)
         | env->psrs;
 #endif
     cs_base = env->npc;
     pc = env->pc;
 #elif defined(TARGET_PPC)
-    flags = (msr_pr << MSR_PR) | (msr_fp << MSR_FP) |
-        (msr_se << MSR_SE) | (msr_le << MSR_LE);
+    flags = env->hflags;
     cs_base = 0;
     pc = env->nip;
 #elif defined(TARGET_MIPS)
     flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK);
     cs_base = 0;
-    pc = env->PC;
+    pc = env->PC[env->current_tc];
 #elif defined(TARGET_M68K)
-    flags = env->fpcr & M68K_FPCR_PREC;
+    flags = (env->fpcr & M68K_FPCR_PREC)  /* Bit  6 */
+            | (env->sr & SR_S)            /* Bit  13 */
+            | ((env->macsr >> 4) & 0xf);  /* Bits 0-3 */
     cs_base = 0;
     pc = env->pc;
 #elif defined(TARGET_SH4)
     flags = env->sr & (SR_MD | SR_RB);
     cs_base = 0;         /* XXXXX */
     pc = env->pc;
+#elif defined(TARGET_ALPHA)
+    flags = env->ps;
+    cs_base = 0;
+    pc = env->pc;
 #else
 #error unsupported CPU
 #endif
@@ -247,59 +255,10 @@
     TranslationBlock *tb;
     uint8_t *tc_ptr;
 
-#if defined(TARGET_I386)
-    /* handle exit of HALTED state */
-    if (env1->hflags & HF_HALTED_MASK) {
-        /* disable halt condition */
-        if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
-            (env1->eflags & IF_MASK)) {
-            env1->hflags &= ~HF_HALTED_MASK;
-        } else {
-            return EXCP_HALTED;
-        }
-    }
-#elif defined(TARGET_PPC)
-    if (env1->halted) {
-        if (env1->msr[MSR_EE] && 
-            (env1->interrupt_request & 
-             (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) {
-            env1->halted = 0;
-        } else {
-            return EXCP_HALTED;
-        }
-    }
-#elif defined(TARGET_SPARC)
-    if (env1->halted) {
-        if ((env1->interrupt_request & CPU_INTERRUPT_HARD) &&
-            (env1->psret != 0)) {
-            env1->halted = 0;
-        } else {
-            return EXCP_HALTED;
-        }
-    }
-#elif defined(TARGET_ARM)
-    if (env1->halted) {
-        /* An interrupt wakes the CPU even if the I and F CPSR bits are
-           set.  */
-        if (env1->interrupt_request
-            & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD)) {
-            env1->halted = 0;
-        } else {
-            return EXCP_HALTED;
-        }
-    }
-#elif defined(TARGET_MIPS)
-    if (env1->halted) {
-        if (env1->interrupt_request &
-            (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) {
-            env1->halted = 0;
-        } else {
-            return EXCP_HALTED;
-        }
-    }
-#endif
+    if (cpu_halted(env1) == EXCP_HALTED)
+        return EXCP_HALTED;
 
-    cpu_single_env = env1; 
+    cpu_single_env = env1;
 
     /* first we save global registers */
 #define SAVE_HOST_REGS 1
@@ -310,23 +269,24 @@
     asm volatile ("mov %%i7, %0" : "=r" (saved_i7));
 #endif
 
-#if defined(TARGET_I386)
     env_to_regs();
+#if defined(TARGET_I386)
     /* put eflags in CPU temporary format */
     CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
     DF = 1 - (2 * ((env->eflags >> 10) & 1));
     CC_OP = CC_OP_EFLAGS;
     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
-#elif defined(TARGET_ARM)
 #elif defined(TARGET_SPARC)
 #if defined(reg_REGWPTR)
     saved_regwptr = REGWPTR;
 #endif
-#elif defined(TARGET_PPC)
 #elif defined(TARGET_M68K)
     env->cc_op = CC_OP_FLAGS;
     env->cc_dest = env->sr & 0xf;
     env->cc_x = (env->sr >> 4) & 1;
+#elif defined(TARGET_ALPHA)
+#elif defined(TARGET_ARM)
+#elif defined(TARGET_PPC)
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
     /* XXXXX */
@@ -350,9 +310,9 @@
                        which will be handled outside the cpu execution
                        loop */
 #if defined(TARGET_I386)
-                    do_interrupt_user(env->exception_index, 
-                                      env->exception_is_int, 
-                                      env->error_code, 
+                    do_interrupt_user(env->exception_index,
+                                      env->exception_is_int,
+                                      env->error_code,
                                       env->exception_next_eip);
 #endif
                     ret = env->exception_index;
@@ -362,10 +322,12 @@
                     /* simulate a real cpu exception. On i386, it can
                        trigger new exceptions, but we do not handle
                        double or triple faults yet. */
-                    do_interrupt(env->exception_index, 
-                                 env->exception_is_int, 
-                                 env->error_code, 
+                    do_interrupt(env->exception_index,
+                                 env->exception_is_int,
+                                 env->error_code,
                                  env->exception_next_eip, 0);
+                    /* successfully delivered */
+                    env->old_exception = -1;
 #elif defined(TARGET_PPC)
                     do_interrupt(env);
 #elif defined(TARGET_MIPS)
@@ -376,10 +338,14 @@
                     do_interrupt(env);
 #elif defined(TARGET_SH4)
 		    do_interrupt(env);
+#elif defined(TARGET_ALPHA)
+                    do_interrupt(env);
+#elif defined(TARGET_M68K)
+                    do_interrupt(0);
 #endif
                 }
                 env->exception_index = -1;
-            } 
+            }
 #ifdef USE_KQEMU
             if (kqemu_is_ok(env) && env->interrupt_request == 0) {
                 int ret;
@@ -415,14 +381,33 @@
             T0 = 0; /* force lookup of first TB */
             for(;;) {
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
-                /* g1 can be modified by some libc? functions */ 
+                /* g1 can be modified by some libc? functions */
                 tmp_T0 = T0;
-#endif	    
+#endif
                 interrupt_request = env->interrupt_request;
-                if (__builtin_expect(interrupt_request, 0)) {
+                if (__builtin_expect(interrupt_request, 0)
+#if defined(TARGET_I386)
+			&& env->hflags & HF_GIF_MASK
+#endif
+				) {
+                    if (interrupt_request & CPU_INTERRUPT_DEBUG) {
+                        env->interrupt_request &= ~CPU_INTERRUPT_DEBUG;
+                        env->exception_index = EXCP_DEBUG;
+                        cpu_loop_exit();
+                    }
+#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
+    defined(TARGET_PPC) || defined(TARGET_ALPHA)
+                    if (interrupt_request & CPU_INTERRUPT_HALT) {
+                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
+                        env->halted = 1;
+                        env->exception_index = EXCP_HLT;
+                        cpu_loop_exit();
+                    }
+#endif
 #if defined(TARGET_I386)
                     if ((interrupt_request & CPU_INTERRUPT_SMI) &&
                         !(env->hflags & HF_SMM_MASK)) {
+                        svm_check_intercept(SVM_EXIT_SMI);
                         env->interrupt_request &= ~CPU_INTERRUPT_SMI;
                         do_smm_enter();
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
@@ -431,10 +416,11 @@
                         T0 = 0;
 #endif
                     } else if ((interrupt_request & CPU_INTERRUPT_HARD) &&
-                        (env->eflags & IF_MASK) && 
+                        (env->eflags & IF_MASK || env->hflags & HF_HIF_MASK) &&
                         !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
                         int intno;
-                        env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+                        svm_check_intercept(SVM_EXIT_INTR);
+                        env->interrupt_request &= ~(CPU_INTERRUPT_HARD | CPU_INTERRUPT_VIRQ);
                         intno = cpu_get_pic_interrupt(env);
                         if (loglevel & CPU_LOG_TB_IN_ASM) {
                             fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
@@ -447,6 +433,25 @@
 #else
                         T0 = 0;
 #endif
+#if !defined(CONFIG_USER_ONLY)
+                    } else if ((interrupt_request & CPU_INTERRUPT_VIRQ) &&
+                        (env->eflags & IF_MASK) && !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
+                         int intno;
+                         /* FIXME: this should respect TPR */
+                         env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
+                         svm_check_intercept(SVM_EXIT_VINTR);
+                         intno = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_vector));
+                         if (loglevel & CPU_LOG_TB_IN_ASM)
+                             fprintf(logfile, "Servicing virtual hardware INT=0x%02x\n", intno);
+	                 do_interrupt(intno, 0, 0, -1, 1);
+                         stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl),
+                                  ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl)) & ~V_IRQ_MASK);
+#if defined(__sparc__) && !defined(HOST_SOLARIS)
+                         tmp_T0 = 0;
+#else
+                         T0 = 0;
+#endif
+#endif
                     }
 #elif defined(TARGET_PPC)
 #if 0
@@ -454,37 +459,22 @@
                         cpu_ppc_reset(env);
                     }
 #endif
-                    if (msr_ee != 0) {
-                        if ((interrupt_request & CPU_INTERRUPT_HARD)) {
-			    /* Raise it */
-			    env->exception_index = EXCP_EXTERNAL;
-			    env->error_code = 0;
-                            do_interrupt(env);
+                    if (interrupt_request & CPU_INTERRUPT_HARD) {
+                        ppc_hw_interrupt(env);
+                        if (env->pending_interrupts == 0)
                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
-                            tmp_T0 = 0;
+                        tmp_T0 = 0;
 #else
-                            T0 = 0;
+                        T0 = 0;
 #endif
-                        } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) {
-                            /* Raise it */
-                            env->exception_index = EXCP_DECR;
-                            env->error_code = 0;
-                            do_interrupt(env);
-                            env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
-#if defined(__sparc__) && !defined(HOST_SOLARIS)
-                            tmp_T0 = 0;
-#else
-                            T0 = 0;
-#endif
-                        }
                     }
 #elif defined(TARGET_MIPS)
                     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+                        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
                         (env->CP0_Status & (1 << CP0St_IE)) &&
-                        (env->CP0_Status & env->CP0_Cause & 0x0000FF00) &&
-                        !(env->hflags & MIPS_HFLAG_EXL) &&
-                        !(env->hflags & MIPS_HFLAG_ERL) &&
+                        !(env->CP0_Status & (1 << CP0St_EXL)) &&
+                        !(env->CP0_Status & (1 << CP0St_ERL)) &&
                         !(env->hflags & MIPS_HFLAG_DM)) {
                         /* Raise it */
                         env->exception_index = EXCP_EXT_INTERRUPT;
@@ -508,6 +498,9 @@
 			    env->interrupt_request &= ~CPU_INTERRUPT_HARD;
 			    do_interrupt(env->interrupt_index);
 			    env->interrupt_index = 0;
+#if !defined(TARGET_SPARC64) && !defined(CONFIG_USER_ONLY)
+                            cpu_check_irqs(env);
+#endif
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
                             tmp_T0 = 0;
 #else
@@ -517,12 +510,7 @@
 		    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
 			//do_interrupt(0, 0, 0, 0, 0);
 			env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
-		    } else if (interrupt_request & CPU_INTERRUPT_HALT) {
-			env->interrupt_request &= ~CPU_INTERRUPT_HALT;
-			env->halted = 1;
-			env->exception_index = EXCP_HLT;
-			cpu_loop_exit();
-                    }
+		    }
 #elif defined(TARGET_ARM)
                     if (interrupt_request & CPU_INTERRUPT_FIQ
                         && !(env->uncached_cpsr & CPSR_F)) {
@@ -536,6 +524,22 @@
                     }
 #elif defined(TARGET_SH4)
 		    /* XXXXX */
+#elif defined(TARGET_ALPHA)
+                    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. */
@@ -557,32 +561,9 @@
                 }
 #ifdef DEBUG_EXEC
                 if ((loglevel & CPU_LOG_TB_CPU)) {
-#if defined(TARGET_I386)
                     /* restore flags in standard format */
-#ifdef reg_EAX
-                    env->regs[R_EAX] = EAX;
-#endif
-#ifdef reg_EBX
-                    env->regs[R_EBX] = EBX;
-#endif
-#ifdef reg_ECX
-                    env->regs[R_ECX] = ECX;
-#endif
-#ifdef reg_EDX
-                    env->regs[R_EDX] = EDX;
-#endif
-#ifdef reg_ESI
-                    env->regs[R_ESI] = ESI;
-#endif
-#ifdef reg_EDI
-                    env->regs[R_EDI] = EDI;
-#endif
-#ifdef reg_EBP
-                    env->regs[R_EBP] = EBP;
-#endif
-#ifdef reg_ESP
-                    env->regs[R_ESP] = ESP;
-#endif
+                    regs_to_env();
+#if defined(TARGET_I386)
                     env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
                     cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
                     env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
@@ -604,8 +585,10 @@
                     cpu_dump_state(env, logfile, fprintf, 0);
 #elif defined(TARGET_SH4)
 		    cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_ALPHA)
+                    cpu_dump_state(env, logfile, fprintf, 0);
 #else
-#error unsupported target CPU 
+#error unsupported target CPU
 #endif
                 }
 #endif
@@ -619,7 +602,7 @@
 #endif
 #if defined(__sparc__) && !defined(HOST_SOLARIS)
                 T0 = tmp_T0;
-#endif	    
+#endif
                 /* see if we can patch the calling TB. When the TB
                    spans two pages, we cannot safely do a direct
                    jump. */
@@ -630,7 +613,7 @@
 #endif
                         tb->page_addr[1] == -1
 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
-                    && (tb->cflags & CF_CODE_COPY) == 
+                    && (tb->cflags & CF_CODE_COPY) ==
                     (((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
 #endif
                     ) {
@@ -638,7 +621,7 @@
                     tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
 #if defined(USE_CODE_COPY)
                     /* propagates the FP use info */
-                    ((TranslationBlock *)(T0 & ~3))->cflags |= 
+                    ((TranslationBlock *)(T0 & ~3))->cflags |=
                         (tb->cflags & CF_FP_USED);
 #endif
                     spin_unlock(&tb_lock);
@@ -652,8 +635,9 @@
                 __asm__ __volatile__("call	%0\n\t"
                                      "mov	%%o7,%%i0"
                                      : /* no outputs */
-                                     : "r" (gen_func) 
+                                     : "r" (gen_func)
                                      : "i0", "i1", "i2", "i3", "i4", "i5",
+                                       "o0", "o1", "o2", "o3", "o4", "o5",
                                        "l0", "l1", "l2", "l3", "l4", "l5",
                                        "l6", "l7");
 #elif defined(__arm__)
@@ -766,7 +750,7 @@
                     cpu_loop_exit();
                 }
 #endif
-            }
+            } /* for(;;) */
         } else {
             env_to_regs();
         }
@@ -795,6 +779,7 @@
               | env->cc_dest | (env->cc_x << 4);
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
+#elif defined(TARGET_ALPHA)
     /* XXXXX */
 #else
 #error unsupported target CPU
@@ -807,7 +792,7 @@
 #include "hostregs_helper.h"
 
     /* fail safe : never use cpu_single_env outside cpu_exec() */
-    cpu_single_env = NULL; 
+    cpu_single_env = NULL;
     return ret;
 }
 
@@ -834,7 +819,7 @@
     env = s;
     if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
         selector &= 0xffff;
-        cpu_x86_load_seg_cache(env, seg_reg, selector, 
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
                                (selector << 4), 0xffff, 0);
     } else {
         load_seg(seg_reg, selector);
@@ -848,7 +833,7 @@
 
     saved_env = env;
     env = s;
-    
+
     helper_fsave((target_ulong)ptr, data32);
 
     env = saved_env;
@@ -860,7 +845,7 @@
 
     saved_env = env;
     env = s;
-    
+
     helper_frstor((target_ulong)ptr, data32);
 
     env = saved_env;
@@ -877,7 +862,7 @@
    write caused the exception and otherwise 0'. 'old_set' is the
    signal set which should be restored */
 static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
-                                    int is_write, sigset_t *old_set, 
+                                    int is_write, sigset_t *old_set,
                                     void *puc)
 {
     TranslationBlock *tb;
@@ -886,7 +871,7 @@
     if (cpu_single_env)
         env = cpu_single_env; /* XXX: find a correct solution for multithread */
 #if defined(DEBUG_SIGNAL)
-    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+    qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
                 pc, address, is_write, *(unsigned long *)old_set);
 #endif
     /* XXX: locking issue */
@@ -895,7 +880,7 @@
     }
 
     /* see if it is an MMU fault */
-    ret = cpu_x86_handle_mmu_fault(env, address, is_write, 
+    ret = cpu_x86_handle_mmu_fault(env, address, is_write,
                                    ((env->hflags & HF_CPL_MASK) == 3), 0);
     if (ret < 0)
         return 0; /* not an MMU fault */
@@ -910,7 +895,7 @@
     }
     if (ret == 1) {
 #if 0
-        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", 
+        printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
                env->eip, env->cr[2], env->error_code);
 #endif
         /* we restore the process signal mask as the sigreturn should
@@ -937,7 +922,7 @@
     if (cpu_single_env)
         env = cpu_single_env; /* XXX: find a correct solution for multithread */
 #if defined(DEBUG_SIGNAL)
-    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
     /* XXX: locking issue */
@@ -973,7 +958,7 @@
     if (cpu_single_env)
         env = cpu_single_env; /* XXX: find a correct solution for multithread */
 #if defined(DEBUG_SIGNAL)
-    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
     /* XXX: locking issue */
@@ -1005,11 +990,11 @@
 {
     TranslationBlock *tb;
     int ret;
-    
+
     if (cpu_single_env)
         env = cpu_single_env; /* XXX: find a correct solution for multithread */
 #if defined(DEBUG_SIGNAL)
-    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
     /* XXX: locking issue */
@@ -1033,7 +1018,7 @@
     }
     if (ret == 1) {
 #if 0
-        printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
+        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
                env->nip, env->error_code, tb);
 #endif
     /* we restore the process signal mask as the sigreturn should
@@ -1059,7 +1044,7 @@
     if (cpu_single_env)
         env = cpu_single_env; /* XXX: find a correct solution for multithread */
 #if defined(DEBUG_SIGNAL)
-    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
     /* XXX: locking issue */
@@ -1094,11 +1079,11 @@
 {
     TranslationBlock *tb;
     int ret;
-    
+
     if (cpu_single_env)
         env = cpu_single_env; /* XXX: find a correct solution for multithread */
 #if defined(DEBUG_SIGNAL)
-    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
     /* XXX: locking issue */
@@ -1122,8 +1107,8 @@
     }
     if (ret == 1) {
 #if 0
-        printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
-               env->nip, env->error_code, tb);
+        printf("PF exception: PC=0x" TARGET_FMT_lx " error=0x%x %p\n",
+               env->PC, env->error_code, tb);
 #endif
     /* we restore the process signal mask as the sigreturn should
        do it (XXX: use sigsetjmp) */
@@ -1144,11 +1129,11 @@
 {
     TranslationBlock *tb;
     int ret;
-    
+
     if (cpu_single_env)
         env = cpu_single_env; /* XXX: find a correct solution for multithread */
 #if defined(DEBUG_SIGNAL)
-    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", 
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
            pc, address, is_write, *(unsigned long *)old_set);
 #endif
     /* XXX: locking issue */
@@ -1171,7 +1156,52 @@
         cpu_restore_state(tb, env, pc, puc);
     }
 #if 0
-        printf("PF exception: NIP=0x%08x error=0x%x %p\n", 
+        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
+               env->nip, env->error_code, tb);
+#endif
+    /* we restore the process signal mask as the sigreturn should
+       do it (XXX: use sigsetjmp) */
+    sigprocmask(SIG_SETMASK, old_set, NULL);
+    cpu_loop_exit();
+    /* never comes here */
+    return 1;
+}
+
+#elif defined (TARGET_ALPHA)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+                                    int is_write, sigset_t *old_set,
+                                    void *puc)
+{
+    TranslationBlock *tb;
+    int ret;
+
+    if (cpu_single_env)
+        env = cpu_single_env; /* XXX: find a correct solution for multithread */
+#if defined(DEBUG_SIGNAL)
+    printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+           pc, address, is_write, *(unsigned long *)old_set);
+#endif
+    /* XXX: locking issue */
+    if (is_write && page_unprotect(h2g(address), pc, puc)) {
+        return 1;
+    }
+
+    /* see if it is an MMU fault */
+    ret = cpu_alpha_handle_mmu_fault(env, address, is_write, 1, 0);
+    if (ret < 0)
+        return 0; /* not an MMU fault */
+    if (ret == 0)
+        return 1; /* the MMU fault was handled without causing real CPU fault */
+
+    /* now we have a real cpu fault */
+    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, puc);
+    }
+#if 0
+        printf("PF exception: NIP=0x%08x error=0x%x %p\n",
                env->nip, env->error_code, tb);
 #endif
     /* we restore the process signal mask as the sigreturn should
@@ -1200,7 +1230,7 @@
 #endif
 
 #if defined(USE_CODE_COPY)
-static void cpu_send_trap(unsigned long pc, int trap, 
+static void cpu_send_trap(unsigned long pc, int trap,
                           struct ucontext *uc)
 {
     TranslationBlock *tb;
@@ -1219,7 +1249,7 @@
 }
 #endif
 
-int cpu_signal_handler(int host_signum, void *pinfo, 
+int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
     siginfo_t *info = pinfo;
@@ -1242,8 +1272,8 @@
         return 1;
     } else
 #endif
-        return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
-                                 trapno == 0xe ? 
+        return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                                 trapno == 0xe ?
                                  (ERROR_sig(uc) >> 1) & 1 : 0,
                                  &uc->uc_sigmask, puc);
 }
@@ -1258,8 +1288,8 @@
     unsigned long pc;
 
     pc = uc->uc_mcontext.gregs[REG_RIP];
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
-                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? 
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
                              (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
                              &uc->uc_sigmask, puc);
 }
@@ -1315,7 +1345,7 @@
 # define TRAP_sig(context)			EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
 #endif /* __APPLE__ */
 
-int cpu_signal_handler(int host_signum, void *pinfo, 
+int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
     siginfo_t *info = pinfo;
@@ -1333,13 +1363,13 @@
     if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
         is_write = 1;
 #endif
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                              is_write, &uc->uc_sigmask, puc);
 }
 
 #elif defined(__alpha__)
 
-int cpu_signal_handler(int host_signum, void *pinfo, 
+int cpu_signal_handler(int host_signum, void *pinfo,
                            void *puc)
 {
     siginfo_t *info = pinfo;
@@ -1364,12 +1394,12 @@
 	is_write = 1;
     }
 
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                              is_write, &uc->uc_sigmask, puc);
 }
 #elif defined(__sparc__)
 
-int cpu_signal_handler(int host_signum, void *pinfo, 
+int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
     siginfo_t *info = pinfo;
@@ -1378,7 +1408,7 @@
     unsigned long pc;
     int is_write;
     uint32_t insn;
-    
+
     /* XXX: is there a standard glibc define ? */
     pc = regs[1];
     /* XXX: need kernel patch to get write flag faster */
@@ -1397,42 +1427,42 @@
 	break;
       }
     }
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                              is_write, sigmask, NULL);
 }
 
 #elif defined(__arm__)
 
-int cpu_signal_handler(int host_signum, void *pinfo, 
+int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
     siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
     int is_write;
-    
+
     pc = uc->uc_mcontext.gregs[R15];
     /* XXX: compute is_write */
     is_write = 0;
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                              is_write,
                              &uc->uc_sigmask, puc);
 }
 
 #elif defined(__mc68000)
 
-int cpu_signal_handler(int host_signum, void *pinfo, 
+int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
     siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
     int is_write;
-    
+
     pc = uc->uc_mcontext.gregs[16];
     /* XXX: compute is_write */
     is_write = 0;
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
                              is_write,
                              &uc->uc_sigmask, puc);
 }
@@ -1473,20 +1503,35 @@
 
 #elif defined(__s390__)
 
-int cpu_signal_handler(int host_signum, void *pinfo, 
+int cpu_signal_handler(int host_signum, void *pinfo,
                        void *puc)
 {
     siginfo_t *info = pinfo;
     struct ucontext *uc = puc;
     unsigned long pc;
     int is_write;
-    
+
     pc = uc->uc_mcontext.psw.addr;
     /* XXX: compute is_write */
     is_write = 0;
-    return handle_cpu_signal(pc, (unsigned long)info->si_addr, 
-                             is_write,
-                             &uc->uc_sigmask, puc);
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
+}
+
+#elif defined(__mips__)
+
+int cpu_signal_handler(int host_signum, void *pinfo,
+                       void *puc)
+{
+    siginfo_t *info = pinfo;
+    struct ucontext *uc = puc;
+    greg_t pc = uc->uc_mcontext.pc;
+    int is_write;
+
+    /* XXX: compute is_write */
+    is_write = 0;
+    return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+                             is_write, &uc->uc_sigmask, puc);
 }
 
 #else
diff --git a/cutils.c b/cutils.c
index e00a559..1413f1b 100644
--- a/cutils.c
+++ b/cutils.c
@@ -1,6 +1,6 @@
 /*
  * Simple C functions to supplement the C library
- * 
+ *
  * Copyright (c) 2006 Fabrice Bellard
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -45,7 +45,7 @@
 {
     int len;
     len = strlen(buf);
-    if (len < buf_size) 
+    if (len < buf_size)
         pstrcpy(buf + len, buf_size - len, s);
     return buf;
 }
diff --git a/d3des.c b/d3des.c
new file mode 100644
index 0000000..eaca581
--- /dev/null
+++ b/d3des.c
@@ -0,0 +1,434 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.  Also the bytebit[] array
+ * has been reversed so that the most significant bit in each byte of the
+ * key is ignored, not the least significant.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software 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.
+ */
+
+/* D3DES (V5.09) -
+ *
+ * A portable, public domain, version of the Data Encryption Standard.
+ *
+ * Written with Symantec's THINK (Lightspeed) C by Richard Outerbridge.
+ * Thanks to: Dan Hoey for his excellent Initial and Inverse permutation
+ * code;  Jim Gillogly & Phil Karn for the DES key schedule code; Dennis
+ * Ferguson, Eric Young and Dana How for comparing notes; and Ray Lau,
+ * for humouring me on.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge.
+ * (GEnie : OUTER; CIS : [71755,204]) Graven Imagery, 1992.
+ */
+
+#include "d3des.h"
+
+static void scrunch(unsigned char *, unsigned long *);
+static void unscrun(unsigned long *, unsigned char *);
+static void desfunc(unsigned long *, unsigned long *);
+static void cookey(unsigned long *);
+
+static unsigned long KnL[32] = { 0L };
+
+static unsigned short bytebit[8]	= {
+	01, 02, 04, 010, 020, 040, 0100, 0200 };
+
+static unsigned long bigbyte[24] = {
+	0x800000L,	0x400000L,	0x200000L,	0x100000L,
+	0x80000L,	0x40000L,	0x20000L,	0x10000L,
+	0x8000L,	0x4000L,	0x2000L,	0x1000L,
+	0x800L, 	0x400L, 	0x200L, 	0x100L,
+	0x80L,		0x40L,		0x20L,		0x10L,
+	0x8L,		0x4L,		0x2L,		0x1L	};
+
+/* Use the key schedule specified in the Standard (ANSI X3.92-1981). */
+
+static unsigned char pc1[56] = {
+	56, 48, 40, 32, 24, 16,  8,	 0, 57, 49, 41, 33, 25, 17,
+	 9,  1, 58, 50, 42, 34, 26,	18, 10,  2, 59, 51, 43, 35,
+	62, 54, 46, 38, 30, 22, 14,	 6, 61, 53, 45, 37, 29, 21,
+	13,  5, 60, 52, 44, 36, 28,	20, 12,  4, 27, 19, 11,  3 };
+
+static unsigned char totrot[16] = {
+	1,2,4,6,8,10,12,14,15,17,19,21,23,25,27,28 };
+
+static unsigned char pc2[48] = {
+	13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+	22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+	40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+	43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31 };
+
+void deskey(key, edf)	/* Thanks to James Gillogly & Phil Karn! */
+unsigned char *key;
+int edf;
+{
+	register int i, j, l, m, n;
+	unsigned char pc1m[56], pcr[56];
+	unsigned long kn[32];
+
+	for ( j = 0; j < 56; j++ ) {
+		l = pc1[j];
+		m = l & 07;
+		pc1m[j] = (key[l >> 3] & bytebit[m]) ? 1 : 0;
+		}
+	for( i = 0; i < 16; i++ ) {
+		if( edf == DE1 ) m = (15 - i) << 1;
+		else m = i << 1;
+		n = m + 1;
+		kn[m] = kn[n] = 0L;
+		for( j = 0; j < 28; j++ ) {
+			l = j + totrot[i];
+			if( l < 28 ) pcr[j] = pc1m[l];
+			else pcr[j] = pc1m[l - 28];
+			}
+		for( j = 28; j < 56; j++ ) {
+		    l = j + totrot[i];
+		    if( l < 56 ) pcr[j] = pc1m[l];
+		    else pcr[j] = pc1m[l - 28];
+		    }
+		for( j = 0; j < 24; j++ ) {
+			if( pcr[pc2[j]] ) kn[m] |= bigbyte[j];
+			if( pcr[pc2[j+24]] ) kn[n] |= bigbyte[j];
+			}
+		}
+	cookey(kn);
+	return;
+	}
+
+static void cookey(raw1)
+register unsigned long *raw1;
+{
+	register unsigned long *cook, *raw0;
+	unsigned long dough[32];
+	register int i;
+
+	cook = dough;
+	for( i = 0; i < 16; i++, raw1++ ) {
+		raw0 = raw1++;
+		*cook	 = (*raw0 & 0x00fc0000L) << 6;
+		*cook	|= (*raw0 & 0x00000fc0L) << 10;
+		*cook	|= (*raw1 & 0x00fc0000L) >> 10;
+		*cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+		*cook	 = (*raw0 & 0x0003f000L) << 12;
+		*cook	|= (*raw0 & 0x0000003fL) << 16;
+		*cook	|= (*raw1 & 0x0003f000L) >> 4;
+		*cook++ |= (*raw1 & 0x0000003fL);
+		}
+	usekey(dough);
+	return;
+	}
+
+void cpkey(into)
+register unsigned long *into;
+{
+	register unsigned long *from, *endp;
+
+	from = KnL, endp = &KnL[32];
+	while( from < endp ) *into++ = *from++;
+	return;
+	}
+
+void usekey(from)
+register unsigned long *from;
+{
+	register unsigned long *to, *endp;
+
+	to = KnL, endp = &KnL[32];
+	while( to < endp ) *to++ = *from++;
+	return;
+	}
+
+void des(inblock, outblock)
+unsigned char *inblock, *outblock;
+{
+	unsigned long work[2];
+
+	scrunch(inblock, work);
+	desfunc(work, KnL);
+	unscrun(work, outblock);
+	return;
+	}
+
+static void scrunch(outof, into)
+register unsigned char *outof;
+register unsigned long *into;
+{
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into++ |= (*outof++ & 0xffL);
+	*into	 = (*outof++ & 0xffL) << 24;
+	*into	|= (*outof++ & 0xffL) << 16;
+	*into	|= (*outof++ & 0xffL) << 8;
+	*into	|= (*outof   & 0xffL);
+	return;
+	}
+
+static void unscrun(outof, into)
+register unsigned long *outof;
+register unsigned char *into;
+{
+	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
+	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
+	*into++ = (unsigned char)((*outof >>  8) & 0xffL);
+	*into++ = (unsigned char)(*outof++	 & 0xffL);
+	*into++ = (unsigned char)((*outof >> 24) & 0xffL);
+	*into++ = (unsigned char)((*outof >> 16) & 0xffL);
+	*into++ = (unsigned char)((*outof >>  8) & 0xffL);
+	*into	=  (unsigned char)(*outof	 & 0xffL);
+	return;
+	}
+
+static unsigned long SP1[64] = {
+	0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+	0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+	0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+	0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+	0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+	0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+	0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+	0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+	0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+	0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+	0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+	0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+	0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+	0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+	0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L };
+
+static unsigned long SP2[64] = {
+	0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+	0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+	0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+	0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+	0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+	0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+	0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+	0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+	0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+	0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+	0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+	0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+	0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+	0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+	0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+	0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L };
+
+static unsigned long SP3[64] = {
+	0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+	0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+	0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+	0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+	0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+	0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+	0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+	0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+	0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+	0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+	0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+	0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+	0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+	0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+	0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+	0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L };
+
+static unsigned long SP4[64] = {
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+	0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+	0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+	0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+	0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+	0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+	0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+	0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+	0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+	0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+	0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+	0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+	0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L };
+
+static unsigned long SP5[64] = {
+	0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+	0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+	0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+	0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+	0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+	0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+	0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+	0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+	0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+	0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+	0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+	0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+	0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+	0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+	0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+	0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L };
+
+static unsigned long SP6[64] = {
+	0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+	0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+	0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+	0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+	0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+	0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+	0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+	0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+	0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+	0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+	0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+	0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+	0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+	0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+	0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L };
+
+static unsigned long SP7[64] = {
+	0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+	0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+	0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+	0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+	0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+	0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+	0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+	0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+	0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+	0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+	0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+	0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+	0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+	0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+	0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+	0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L };
+
+static unsigned long SP8[64] = {
+	0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+	0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+	0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+	0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+	0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+	0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+	0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+	0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+	0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+	0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+	0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+	0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+	0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+	0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+	0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+	0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L };
+
+static void desfunc(block, keys)
+register unsigned long *block, *keys;
+{
+	register unsigned long fval, work, right, leftt;
+	register int round;
+
+	leftt = block[0];
+	right = block[1];
+	work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+	right ^= work;
+	leftt ^= (work << 4);
+	work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+	right ^= work;
+	leftt ^= (work << 16);
+	work = ((right >> 2) ^ leftt) & 0x33333333L;
+	leftt ^= work;
+	right ^= (work << 2);
+	work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+	leftt ^= work;
+	right ^= (work << 8);
+	right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = ((leftt << 1) | ((leftt >> 31) & 1L)) & 0xffffffffL;
+
+	for( round = 0; round < 8; round++ ) {
+		work  = (right << 28) | (right >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = right ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		leftt ^= fval;
+		work  = (leftt << 28) | (leftt >> 4);
+		work ^= *keys++;
+		fval  = SP7[ work		 & 0x3fL];
+		fval |= SP5[(work >>  8) & 0x3fL];
+		fval |= SP3[(work >> 16) & 0x3fL];
+		fval |= SP1[(work >> 24) & 0x3fL];
+		work  = leftt ^ *keys++;
+		fval |= SP8[ work		 & 0x3fL];
+		fval |= SP6[(work >>  8) & 0x3fL];
+		fval |= SP4[(work >> 16) & 0x3fL];
+		fval |= SP2[(work >> 24) & 0x3fL];
+		right ^= fval;
+		}
+
+	right = (right << 31) | (right >> 1);
+	work = (leftt ^ right) & 0xaaaaaaaaL;
+	leftt ^= work;
+	right ^= work;
+	leftt = (leftt << 31) | (leftt >> 1);
+	work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+	right ^= work;
+	leftt ^= (work << 8);
+	work = ((leftt >> 2) ^ right) & 0x33333333L;
+	right ^= work;
+	leftt ^= (work << 2);
+	work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+	leftt ^= work;
+	right ^= (work << 16);
+	work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+	leftt ^= work;
+	right ^= (work << 4);
+	*block++ = right;
+	*block = leftt;
+	return;
+	}
+
+/* Validation sets:
+ *
+ * Single-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : c957 4425 6a5e d31d
+ *
+ * Double-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : 7f1d 0a77 826b 8aff
+ *
+ * Double-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : 27a0 8440 406a df60 278f 47cf 42d6 15d7
+ *
+ * Triple-length key, single-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cde7
+ * Cipher : de0b 7c06 ae5e 0ed5
+ *
+ * Triple-length key, double-length plaintext -
+ * Key	  : 0123 4567 89ab cdef fedc ba98 7654 3210 89ab cdef 0123 4567
+ * Plain  : 0123 4567 89ab cdef 0123 4567 89ab cdff
+ * Cipher : ad0d 1b30 ac17 cf07 0ed1 1c63 81e4 4de5
+ *
+ * d3des V5.0a rwo 9208.07 18:44 Graven Imagery
+ **********************************************************************/
diff --git a/d3des.h b/d3des.h
new file mode 100644
index 0000000..ea3da44
--- /dev/null
+++ b/d3des.h
@@ -0,0 +1,51 @@
+/*
+ * This is D3DES (V5.09) by Richard Outerbridge with the double and
+ * triple-length support removed for use in VNC.
+ *
+ * These changes are:
+ *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
+ *
+ * This software 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.
+ */
+
+/* d3des.h -
+ *
+ *	Headers and defines for d3des.c
+ *	Graven Imagery, 1992.
+ *
+ * Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
+ *	(GEnie : OUTER; CIS : [71755,204])
+ */
+
+#define EN0	0	/* MODE == encrypt */
+#define DE1	1	/* MODE == decrypt */
+
+extern void deskey(unsigned char *, int);
+/*		      hexkey[8]     MODE
+ * Sets the internal key register according to the hexadecimal
+ * key contained in the 8 bytes of hexkey, according to the DES,
+ * for encryption or decryption according to MODE.
+ */
+
+extern void usekey(unsigned long *);
+/*		    cookedkey[32]
+ * Loads the internal key register with the data in cookedkey.
+ */
+
+extern void cpkey(unsigned long *);
+/*		   cookedkey[32]
+ * Copies the contents of the internal key register into the storage
+ * located at &cookedkey[0].
+ */
+
+extern void des(unsigned char *, unsigned char *);
+/*		    from[8]	      to[8]
+ * Encrypts/Decrypts (according to the key currently loaded in the
+ * internal key register) one block of eight bytes at address 'from'
+ * into the block at address 'to'.  They can be the same.
+ */
+
+/* d3des.h V5.09 rwo 9208.04 15:06 Graven Imagery
+ ********************************************************************/
diff --git a/darwin-user/main.c b/darwin-user/main.c
index 78cf864..d0de491 100644
--- a/darwin-user/main.c
+++ b/darwin-user/main.c
@@ -124,32 +124,47 @@
     return cpu_ppc_get_tb(env) >> 32;
 }
 
-static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
+uint32_t cpu_ppc_load_atbl (CPUState *env)
 {
-    /* TO FIX */
+    return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
 }
 
-void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+uint32_t cpu_ppc_load_atbu (CPUState *env)
 {
-    cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
+    return cpu_ppc_get_tb(env) >> 32;
 }
 
-void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
 {
-    cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
+    cpu_ppc_load_tbu(env);
 }
 
-uint32_t cpu_ppc_load_decr (CPUState *env)
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
 {
-    /* TO FIX */
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/* XXX: to be fixed */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
+{
     return -1;
 }
 
-void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
 {
-    /* TO FIX */
+    return -1;
 }
 
+#define EXCP_DUMP(env, fmt, args...)                                         \
+do {                                                                          \
+    fprintf(stderr, fmt , ##args);                                            \
+    cpu_dump_state(env, stderr, fprintf, 0);                                  \
+    if (loglevel != 0) {                                                      \
+        fprintf(logfile, fmt , ##args);                                       \
+        cpu_dump_state(env, logfile, fprintf, 0);                             \
+    }                                                                         \
+} while (0)
+
 void cpu_loop(CPUPPCState *env)
 {
     int trapnr;
@@ -158,16 +173,336 @@
 
     for(;;) {
         trapnr = cpu_ppc_exec(env);
-        if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
-            trapnr != EXCP_TRACE) {
-            if (loglevel > 0) {
-                cpu_dump_state(env, logfile, fprintf, 0);
-            }
-        }
         switch(trapnr) {
-        case EXCP_NONE:
+        case POWERPC_EXCP_NONE:
+            /* Just go on */
             break;
-        case EXCP_SYSCALL_USER:
+        case POWERPC_EXCP_CRITICAL: /* Critical input                        */
+            cpu_abort(env, "Critical interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
+            cpu_abort(env, "Machine check exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DSI:      /* Data storage exception                */
+#ifndef DAR
+/* To deal with multiple qemu header version as host for the darwin-user code */
+# define DAR SPR_DAR
+#endif
+            EXCP_DUMP(env, "Invalid data memory access: 0x" ADDRX "\n",
+                      env->spr[SPR_DAR]);
+            /* Handle this via the gdb */
+            gdb_handlesig (env, SIGSEGV);
+
+            info.si_addr = (void*)env->nip;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
+            EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n",
+                      env->spr[SPR_DAR]);
+            /* Handle this via the gdb */
+            gdb_handlesig (env, SIGSEGV);
+
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_EXTERNAL: /* External input                        */
+            cpu_abort(env, "External interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
+            EXCP_DUMP(env, "Unaligned memory access\n");
+            info.si_errno = 0;
+            info.si_code = BUS_ADRALN;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
+            /* XXX: check this */
+            switch (env->error_code & ~0xF) {
+            case POWERPC_EXCP_FP:
+                EXCP_DUMP(env, "Floating point program exception\n");
+                /* Set FX */
+                env->fpscr[7] |= 0x8;
+                /* Finally, update FEX */
+                if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
+                    ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
+                    env->fpscr[7] |= 0x4;
+                info.si_signo = SIGFPE;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_FP_OX:
+                    info.si_code = FPE_FLTOVF;
+                    break;
+                case POWERPC_EXCP_FP_UX:
+                    info.si_code = FPE_FLTUND;
+                    break;
+                case POWERPC_EXCP_FP_ZX:
+                case POWERPC_EXCP_FP_VXZDZ:
+                    info.si_code = FPE_FLTDIV;
+                    break;
+                case POWERPC_EXCP_FP_XX:
+                    info.si_code = FPE_FLTRES;
+                    break;
+                case POWERPC_EXCP_FP_VXSOFT:
+                    info.si_code = FPE_FLTINV;
+                    break;
+                case POWERPC_EXCP_FP_VXNAN:
+                case POWERPC_EXCP_FP_VXISI:
+                case POWERPC_EXCP_FP_VXIDI:
+                case POWERPC_EXCP_FP_VXIMZ:
+                case POWERPC_EXCP_FP_VXVC:
+                case POWERPC_EXCP_FP_VXSQRT:
+                case POWERPC_EXCP_FP_VXCVI:
+                    info.si_code = FPE_FLTSUB;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
+                              env->error_code);
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_INVAL:
+                EXCP_DUMP(env, "Invalid instruction\n");
+                info.si_signo = SIGILL;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_INVAL_INVAL:
+                    info.si_code = ILL_ILLOPC;
+                    break;
+                case POWERPC_EXCP_INVAL_LSWX:
+                    info.si_code = ILL_ILLOPN;
+                    break;
+                case POWERPC_EXCP_INVAL_SPR:
+                    info.si_code = ILL_PRVREG;
+                    break;
+                case POWERPC_EXCP_INVAL_FP:
+                    info.si_code = ILL_COPROC;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
+                              env->error_code & 0xF);
+                    info.si_code = ILL_ILLADR;
+                    break;
+                }
+                /* Handle this via the gdb */
+                gdb_handlesig (env, SIGSEGV);
+                break;
+            case POWERPC_EXCP_PRIV:
+                EXCP_DUMP(env, "Privilege violation\n");
+                info.si_signo = SIGILL;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_PRIV_OPC:
+                    info.si_code = ILL_PRVOPC;
+                    break;
+                case POWERPC_EXCP_PRIV_REG:
+                    info.si_code = ILL_PRVREG;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
+                              env->error_code & 0xF);
+                    info.si_code = ILL_PRVOPC;
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_TRAP:
+                cpu_abort(env, "Tried to call a TRAP\n");
+                break;
+            default:
+                /* Should not happen ! */
+                cpu_abort(env, "Unknown program exception (%02x)\n",
+                          env->error_code);
+                break;
+            }
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
+            EXCP_DUMP(env, "No floating point allowed\n");
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_COPROC;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
+            cpu_abort(env, "Syscall exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
+            EXCP_DUMP(env, "No APU instruction allowed\n");
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_COPROC;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
+            cpu_abort(env, "Decrementer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
+            cpu_abort(env, "Fix interval timer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
+            cpu_abort(env, "Watchdog timer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
+            cpu_abort(env, "Data TLB exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
+            cpu_abort(env, "Instruction TLB exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DEBUG:    /* Debug interrupt                       */
+            gdb_handlesig (env, SIGTRAP);
+            break;
+#if defined(TARGET_PPCEMB)
+        case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
+            EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_COPROC;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
+            cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
+            break;
+        case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
+            cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
+            break;
+        case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
+            cpu_abort(env, "Performance monitor exception not handled\n");
+            break;
+        case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
+            cpu_abort(env, "Doorbell interrupt while in user mode. "
+                       "Aborting\n");
+            break;
+        case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
+            cpu_abort(env, "Doorbell critical interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+#endif /* defined(TARGET_PPCEMB) */
+        case POWERPC_EXCP_RESET:    /* System reset exception                */
+            cpu_abort(env, "Reset interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+#if defined(TARGET_PPC64) /* PowerPC 64 */
+        case POWERPC_EXCP_DSEG:     /* Data segment exception                */
+            cpu_abort(env, "Data segment exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
+            cpu_abort(env, "Instruction segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+#endif /* defined(TARGET_PPC64) */
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+        case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
+            cpu_abort(env, "Hypervisor decrementer interrupt "
+                      "while in user mode. Aborting\n");
+            break;
+#endif /* defined(TARGET_PPC64H) */
+        case POWERPC_EXCP_TRACE:    /* Trace exception                       */
+            /* Nothing to do:
+             * we use this exception to emulate step-by-step execution mode.
+             */
+            break;
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+        case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
+            cpu_abort(env, "Hypervisor data storage exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
+            cpu_abort(env, "Hypervisor instruction storage exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
+            cpu_abort(env, "Hypervisor data segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
+            cpu_abort(env, "Hypervisor instruction segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+#endif /* defined(TARGET_PPC64H) */
+        case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
+            EXCP_DUMP(env, "No Altivec instructions allowed\n");
+            info.si_signo = SIGILL;
+            info.si_errno = 0;
+            info.si_code = ILL_COPROC;
+            info.si_addr = (void*)(env->nip - 4);
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
+            cpu_abort(env, "Programable interval timer interrupt "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_IO:       /* IO error exception                    */
+            cpu_abort(env, "IO error exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
+            cpu_abort(env, "Run mode exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
+            cpu_abort(env, "Emulation trap exception not handled\n");
+            break;
+        case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
+            cpu_abort(env, "Instruction fetch TLB exception "
+                      "while in user-mode. Aborting");
+            break;
+        case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
+            cpu_abort(env, "Data load TLB exception while in user-mode. "
+                      "Aborting");
+            break;
+        case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
+            cpu_abort(env, "Data store TLB exception while in user-mode. "
+                      "Aborting");
+            break;
+        case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
+            cpu_abort(env, "Floating-point assist exception not handled\n");
+            break;
+        case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
+            cpu_abort(env, "Instruction address breakpoint exception "
+                      "not handled\n");
+            break;
+        case POWERPC_EXCP_SMI:      /* System management interrupt           */
+            cpu_abort(env, "System management interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
+            cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_PERFM:    /* Embedded performance monitor IRQ      */
+            cpu_abort(env, "Performance monitor exception not handled\n");
+            break;
+        case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
+            cpu_abort(env, "Vector assist exception not handled\n");
+            break;
+        case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
+            cpu_abort(env, "Soft patch exception not handled\n");
+            break;
+        case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
+            cpu_abort(env, "Maintenance exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_STOP:     /* stop translation                      */
+            /* We did invalidate the instruction cache. Go on */
+            break;
+        case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
+            /* We just stopped because of a branch. Go on */
+            break;
+        case POWERPC_EXCP_SYSCALL_USER:
+            /* system call in user-mode emulation */
             /* system call */
             if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
                 ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4],
@@ -194,235 +529,12 @@
             /* Return value */
             env->gpr[3] = ret;
             break;
-        case EXCP_RESET:
-            /* Should not happen ! */
-            fprintf(stderr, "RESET asked... Stop emulation\n");
-            if (loglevel)
-                fprintf(logfile, "RESET asked... Stop emulation\n");
-                abort();
-        case EXCP_MACHINE_CHECK:
-            fprintf(stderr, "Machine check exeption...  Stop emulation\n");
-            if (loglevel)
-                fprintf(logfile, "RESET asked... Stop emulation\n");
-                info.si_signo = SIGBUS;
-            info.si_errno = 0;
-            info.si_code = BUS_OBJERR;
-            info.si_addr = (void*)(env->nip - 4);
-            queue_signal(info.si_signo, &info);
-        case EXCP_DSI:
-#ifndef DAR
-/* To deal with multiple qemu header version as host for the darwin-user code */
-# define DAR SPR_DAR
-#endif
-            fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
-            if (loglevel) {
-                fprintf(logfile, "Invalid data memory access: 0x%08x\n",
-                        env->spr[DAR]);
-            }
-            /* Handle this via the gdb */
-            gdb_handlesig (env, SIGSEGV);
-
-            info.si_addr = (void*)env->nip;
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_ISI:
-            fprintf(stderr, "Invalid instruction fetch\n");
-            if (loglevel)
-                fprintf(logfile, "Invalid instruction fetch\n");
-            /* Handle this via the gdb */
-            gdb_handlesig (env, SIGSEGV);
-
-            info.si_addr = (void*)(env->nip - 4);
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_EXTERNAL:
-            /* Should not happen ! */
-            fprintf(stderr, "External interruption... Stop emulation\n");
-            if (loglevel)
-                fprintf(logfile, "External interruption... Stop emulation\n");
-                abort();
-        case EXCP_ALIGN:
-            fprintf(stderr, "Invalid unaligned memory access\n");
-            if (loglevel)
-                fprintf(logfile, "Invalid unaligned memory access\n");
-                info.si_signo = SIGBUS;
-            info.si_errno = 0;
-            info.si_code = BUS_ADRALN;
-            info.si_addr = (void*)(env->nip - 4);
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_PROGRAM:
-            switch (env->error_code & ~0xF) {
-                case EXCP_FP:
-                    fprintf(stderr, "Program exception\n");
-                    if (loglevel)
-                        fprintf(logfile, "Program exception\n");
-                        /* Set FX */
-                        env->fpscr[7] |= 0x8;
-                    /* Finally, update FEX */
-                    if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
-                        ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
-                        env->fpscr[7] |= 0x4;
-                        info.si_signo = SIGFPE;
-                    info.si_errno = 0;
-                    switch (env->error_code & 0xF) {
-                        case EXCP_FP_OX:
-                            info.si_code = FPE_FLTOVF;
-                            break;
-                        case EXCP_FP_UX:
-                            info.si_code = FPE_FLTUND;
-                            break;
-                        case EXCP_FP_ZX:
-                        case EXCP_FP_VXZDZ:
-                            info.si_code = FPE_FLTDIV;
-                            break;
-                        case EXCP_FP_XX:
-                            info.si_code = FPE_FLTRES;
-                            break;
-                        case EXCP_FP_VXSOFT:
-                            info.si_code = FPE_FLTINV;
-                            break;
-                        case EXCP_FP_VXNAN:
-                        case EXCP_FP_VXISI:
-                        case EXCP_FP_VXIDI:
-                        case EXCP_FP_VXIMZ:
-                        case EXCP_FP_VXVC:
-                        case EXCP_FP_VXSQRT:
-                        case EXCP_FP_VXCVI:
-                            info.si_code = FPE_FLTSUB;
-                            break;
-                        default:
-                            fprintf(stderr, "Unknown floating point exception "
-                                    "(%02x)\n", env->error_code);
-                            if (loglevel) {
-                                fprintf(logfile, "Unknown floating point exception "
-                                        "(%02x)\n", env->error_code & 0xF);
-                            }
-                    }
-                        break;
-                case EXCP_INVAL:
-                    fprintf(stderr, "Invalid instruction\n");
-                    if (loglevel)
-                        fprintf(logfile, "Invalid instruction\n");
-                        info.si_signo = SIGILL;
-                    info.si_errno = 0;
-                    switch (env->error_code & 0xF) {
-                        case EXCP_INVAL_INVAL:
-                            info.si_code = ILL_ILLOPC;
-                            break;
-                        case EXCP_INVAL_LSWX:
-                            info.si_code = ILL_ILLOPN;
-                            break;
-                        case EXCP_INVAL_SPR:
-                            info.si_code = ILL_PRVREG;
-                            break;
-                        case EXCP_INVAL_FP:
-                            info.si_code = ILL_COPROC;
-                            break;
-                        default:
-                            fprintf(stderr, "Unknown invalid operation (%02x)\n",
-                                    env->error_code & 0xF);
-                            if (loglevel) {
-                                fprintf(logfile, "Unknown invalid operation (%02x)\n",
-                                        env->error_code & 0xF);
-                            }
-                                info.si_code = ILL_ILLADR;
-                            break;
-                    }
-                        /* Handle this via the gdb */
-                        gdb_handlesig (env, SIGSEGV);
-                    break;
-                case EXCP_PRIV:
-                    fprintf(stderr, "Privilege violation\n");
-                    if (loglevel)
-                        fprintf(logfile, "Privilege violation\n");
-                        info.si_signo = SIGILL;
-                    info.si_errno = 0;
-                    switch (env->error_code & 0xF) {
-                        case EXCP_PRIV_OPC:
-                            info.si_code = ILL_PRVOPC;
-                            break;
-                        case EXCP_PRIV_REG:
-                            info.si_code = ILL_PRVREG;
-                            break;
-                        default:
-                            fprintf(stderr, "Unknown privilege violation (%02x)\n",
-                                    env->error_code & 0xF);
-                            info.si_code = ILL_PRVOPC;
-                            break;
-                    }
-                        break;
-                case EXCP_TRAP:
-                    fprintf(stderr, "Tried to call a TRAP\n");
-                    if (loglevel)
-                        fprintf(logfile, "Tried to call a TRAP\n");
-                        abort();
-                default:
-                    /* Should not happen ! */
-                    fprintf(stderr, "Unknown program exception (%02x)\n",
-                            env->error_code);
-                    if (loglevel) {
-                        fprintf(logfile, "Unknwon program exception (%02x)\n",
-                                env->error_code);
-                    }
-                        abort();
-            }
-            info.si_addr = (void*)(env->nip - 4);
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_NO_FP:
-            fprintf(stderr, "No floating point allowed\n");
-            if (loglevel)
-                fprintf(logfile, "No floating point allowed\n");
-                info.si_signo = SIGILL;
-            info.si_errno = 0;
-            info.si_code = ILL_COPROC;
-            info.si_addr = (void*)(env->nip - 4);
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_DECR:
-            /* Should not happen ! */
-            fprintf(stderr, "Decrementer exception\n");
-            if (loglevel)
-                fprintf(logfile, "Decrementer exception\n");
-            abort();
-        case EXCP_TRACE:
-            /* Pass to gdb: we use this to trace execution */
-            gdb_handlesig (env, SIGTRAP);
-            break;
-        case EXCP_FP_ASSIST:
-            /* Should not happen ! */
-            fprintf(stderr, "Floating point assist exception\n");
-            if (loglevel)
-                fprintf(logfile, "Floating point assist exception\n");
-            abort();
-        case EXCP_MTMSR:
-            /* We reloaded the msr, just go on */
-            if (msr_pr == 0) {
-                fprintf(stderr, "Tried to go into supervisor mode !\n");
-                if (loglevel)
-                    fprintf(logfile, "Tried to go into supervisor mode !\n");
-                abort();
-            }
-            break;
-        case EXCP_BRANCH:
-            /* We stopped because of a jump... */
-            break;
         case EXCP_INTERRUPT:
-            /* Don't know why this should ever happen... */
-            fprintf(stderr, "EXCP_INTERRUPT\n");
-            break;
-        case EXCP_DEBUG:
-            gdb_handlesig (env, SIGTRAP);
+            /* just indicate that signals should be handled asap */
             break;
         default:
-            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
-                    trapnr);
-            if (loglevel) {
-                fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
-                        "0x%02x - aborting\n", trapnr, env->error_code);
-            }
-                abort();
+            cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
+            break;
         }
         process_pending_signals(env);
     }
diff --git a/darwin-user/mmap.c b/darwin-user/mmap.c
index ada613d..b4055ab 100644
--- a/darwin-user/mmap.c
+++ b/darwin-user/mmap.c
@@ -199,7 +199,7 @@
 
     if (!(flags & MAP_FIXED)) {
 #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
-        /* tell the kenel to search at the same place as i386 */
+        /* tell the kernel to search at the same place as i386 */
         if (host_start == 0) {
             host_start = last_start;
             last_start += HOST_PAGE_ALIGN(len);
diff --git a/darwin-user/syscall.c b/darwin-user/syscall.c
index f2543aa..f17e591 100644
--- a/darwin-user/syscall.c
+++ b/darwin-user/syscall.c
@@ -53,6 +53,8 @@
 #include <mach/ndr.h>
 #include <mach/mig_errors.h>
 
+#include <sys/xattr.h>
+
 #include "qemu.h"
 
 //#define DEBUG_SYSCALL
@@ -367,7 +369,14 @@
         case 200: /* host_info */
         {
             mig_reply_error_t *err = (mig_reply_error_t *)hdr;
-            struct host_basic_info *data = (void *)(err+1);
+            struct {
+                uint32_t unknow1;
+                uint32_t max_cpus;
+                uint32_t avail_cpus;
+                uint32_t memory_size;
+                uint32_t cpu_type;
+                uint32_t cpu_subtype;
+            } *data = (void *)(err+1);
 
             DPRINTF("maxcpu = 0x%x\n",   data->max_cpus);
             DPRINTF("numcpu = 0x%x\n",   data->avail_cpus);
@@ -444,21 +453,49 @@
     case -31:
         DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
                 arg1, arg2, arg3, arg4, arg5, arg6, arg7);
-
         ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7);
-
         break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+    case -33:
+        DPRINTF("semaphore_signal_trap(0x%x)\n", arg1);
+        ret = semaphore_signal_trap(arg1);
+        break;
+    case -34:
+        DPRINTF("semaphore_signal_all_trap(0x%x)\n", arg1);
+        ret = semaphore_signal_all_trap(arg1);
+        break;
+    case -35:
+        DPRINTF("semaphore_signal_thread_trap(0x%x)\n", arg1, arg2);
+        ret = semaphore_signal_thread_trap(arg1,arg2);
+        break;
+#endif
     case -36:
         DPRINTF("semaphore_wait_trap(0x%x)\n", arg1);
         extern int semaphore_wait_trap(int); // XXX: is there any header for that?
         ret = semaphore_wait_trap(arg1);
         break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+    case -37:
+        DPRINTF("semaphore_wait_signal_trap(0x%x, 0x%x)\n", arg1, arg2);
+        ret = semaphore_wait_signal_trap(arg1,arg2);
+        break;
+#endif
     case -43:
         DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
                 arg1, arg2, arg3, arg4, arg5);
         ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5);
         tswap32s((uint32_t*)arg3);
         break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+    case -61:
+        DPRINTF("syscall_thread_switch(0x%x, 0x%x, 0x%x)\n",
+                arg1, arg2, arg3);
+        ret = syscall_thread_switch(arg1, arg2, arg3);  // just a hint to the scheduler; can drop?
+        break;
+#endif
     case -89:
         DPRINTF("mach_timebase_info(0x%x)\n", arg1);
         struct mach_timebase_info info;
@@ -1299,7 +1336,7 @@
         if(!(sysctl = sysctl->childs))
             break;
     }
-    
+
     if(ret->childs)
         qerror("we shouldn't have a directory element\n");
 
@@ -1338,13 +1375,16 @@
         //bswap_syctl(name, namelen, newp, newlen);
         tswap32s((uint32_t*)oldlenp);
     }
-        
+
     if(name) /* Sometimes sysctl is called with no arg1, ignore */
         ret = get_errno(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
 
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
     if (!is_error(ret) && bswap_syctl(name, namelen, oldp, *oldlenp) != 0) {
         return -ENOTDIR;
     }
+#endif
+
     if(name) {
         //bswap_syctl(name, namelen, newp, newlen);
         tswap32s((uint32_t*)oldlenp);
diff --git a/darwin-user/syscalls.h b/darwin-user/syscalls.h
index 7c361ce..34d95da 100644
--- a/darwin-user/syscalls.h
+++ b/darwin-user/syscalls.h
@@ -42,7 +42,7 @@
  ENTRY("getppid",                  SYS_getppid,                        getppid,                           0, CALL_DIRECT, VOID)   /* 39  */
  ENTRY("",                         40,                                 no_syscall,                        0, CALL_INDIRECT, VOID) /* 40  old lstat */
  ENTRY("dup",                      SYS_dup,                            dup,                               1, CALL_DIRECT, INT)   /* 41  */
- ENTRY("pipe",                     SYS_pipe,                           unimpl_unix_syscall,               0, CALL_INDIRECT, PTR)   /* 42  */
+ ENTRY("pipe",                     SYS_pipe,                           pipe,               0, CALL_INDIRECT, PTR)   /* 42  */
  ENTRY("getegid",                  SYS_getegid,                        getegid,                           0, CALL_NOERRNO, VOID)  /* 43  */
  ENTRY("profil",                   SYS_profil,                         profil,                            4, CALL_DIRECT, PTR, SIZE, INT, INT)   /* 44  */
  ENTRY("ktrace",                   SYS_ktrace,                         no_syscall,                        4, CALL_INDIRECT, VOID) /* 45  */
@@ -247,7 +247,7 @@
  ENTRY("fsetxattr",                SYS_fsetxattr,                      no_syscall,                        6, CALL_INDIRECT, VOID)   /* 237  */
  ENTRY("removexattr",              SYS_removexattr,                    no_syscall,                        3, CALL_INDIRECT, VOID)   /* 238  */
  ENTRY("fremovexattr",             SYS_fremovexattr,                   no_syscall,                        3, CALL_INDIRECT, VOID)   /* 239  */
- ENTRY("listxattr",                SYS_listxattr,                      no_syscall,                        4, CALL_INDIRECT, VOID)   /* 240  */
+ ENTRY("listxattr",                SYS_listxattr,                      listxattr,                         4, CALL_INDIRECT, VOID)   /* 240  */
  ENTRY("flistxattr",               SYS_flistxattr,                     no_syscall,                        4, CALL_INDIRECT, VOID)   /* 241  */
  ENTRY("fsctl",                    SYS_fsctl,                          fsctl,                             4, CALL_DIRECT, PTR, UINT, PTR, UINT)   /* 242  */
  ENTRY("initgroups",               SYS_initgroups,                     unimpl_unix_syscall,               3, CALL_INDIRECT, UINT, PTR, INT)   /* 243  */
diff --git a/dis-asm.h b/dis-asm.h
index 73b4380..bacd9c4 100644
--- a/dis-asm.h
+++ b/dis-asm.h
@@ -44,7 +44,7 @@
 
 enum bfd_endian { BFD_ENDIAN_BIG, BFD_ENDIAN_LITTLE, BFD_ENDIAN_UNKNOWN };
 
-enum bfd_architecture 
+enum bfd_architecture
 {
   bfd_arch_unknown,    /* File arch not known */
   bfd_arch_obscure,    /* Arch known, not one of these */
@@ -67,14 +67,14 @@
 #define bfd_mach_mcf5249   16
 #define bfd_mach_mcf547x   17
 #define bfd_mach_mcf548x   18
-  bfd_arch_vax,        /* DEC Vax */   
+  bfd_arch_vax,        /* DEC Vax */
   bfd_arch_i960,       /* Intel 960 */
      /* The order of the following is important.
-       lower number indicates a machine type that 
+       lower number indicates a machine type that
        only accepts a subset of the instructions
        available to machines with higher numbers.
        The exception is the "ca", which is
-       incompatible with all other machines except 
+       incompatible with all other machines except
        "core". */
 
 #define bfd_mach_i960_core      1
@@ -181,6 +181,7 @@
 #define bfd_mach_sh4al_dsp  0x4d
 #define bfd_mach_sh5        0x50
   bfd_arch_alpha,      /* Dec Alpha */
+#define bfd_mach_alpha 1
   bfd_arch_arm,        /* Advanced Risc Machines ARM */
 #define bfd_mach_arm_2         1
 #define bfd_mach_arm_2a                2
@@ -201,6 +202,8 @@
   bfd_arch_mn10300,    /* Matsushita MN10300 */
   bfd_arch_last
   };
+#define bfd_mach_s390_31 31
+#define bfd_mach_s390_64 64
 
 typedef struct symbol_cache_entry
 {
@@ -225,7 +228,7 @@
   dis_dref2			/* Two data references in instruction */
 };
 
-/* This struct is passed into the instruction decoding routine, 
+/* This struct is passed into the instruction decoding routine,
    and is passed back out into each callback.  The various fields are used
    for conveying information from your main routine into your callbacks,
    for passing information into the instruction decoders (such as the
@@ -377,6 +380,8 @@
 extern int print_insn_v850		PARAMS ((bfd_vma, disassemble_info*));
 extern int print_insn_tic30		PARAMS ((bfd_vma, disassemble_info*));
 extern int print_insn_ppc		PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_alpha             PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_s390		PARAMS ((bfd_vma, disassemble_info*));
 
 #if 0
 /* Fetch the disassembler for a given BFD, if that support is available.  */
@@ -419,7 +424,7 @@
 /* Call this macro to initialize only the internal variables for the
    disassembler.  Architecture dependent things such as byte order, or machine
    variant are not touched by this macro.  This makes things much easier for
-   GDB which must initialize these things seperatly.  */
+   GDB which must initialize these things separately.  */
 
 #define INIT_DISASSEMBLE_INFO_NO_ARCH(INFO, STREAM, FPRINTF_FUNC) \
   (INFO).fprintf_func = (FPRINTF_FUNC), \
diff --git a/disas.c b/disas.c
index 2979927..ae20d37 100644
--- a/disas.c
+++ b/disas.c
@@ -134,10 +134,10 @@
 }
 #endif
 
-/* Disassemble this for me please... (debugging). 'flags' has teh following
+/* Disassemble this for me please... (debugging). 'flags' has the following
    values:
     i386 - nonzero means 16 bit code
-    arm  - nonzero means thumb code 
+    arm  - nonzero means thumb code
     ppc  - nonzero means little endian
     other targets - unused
  */
@@ -162,7 +162,7 @@
 #if defined(TARGET_I386)
     if (flags == 2)
         disasm_info.mach = bfd_mach_x86_64;
-    else if (flags == 1) 
+    else if (flags == 1)
         disasm_info.mach = bfd_mach_i386_i8086;
     else
         disasm_info.mach = bfd_mach_i386_i386;
@@ -176,15 +176,20 @@
     print_insn = print_insn_sparc;
 #ifdef TARGET_SPARC64
     disasm_info.mach = bfd_mach_sparc_v9b;
-#endif    
-#elif defined(TARGET_PPC)
-    if (flags)
-        disasm_info.endian = BFD_ENDIAN_LITTLE;
-#ifdef TARGET_PPC64
-    disasm_info.mach = bfd_mach_ppc64;
-#else
-    disasm_info.mach = bfd_mach_ppc;
 #endif
+#elif defined(TARGET_PPC)
+    if (flags >> 16)
+        disasm_info.endian = BFD_ENDIAN_LITTLE;
+    if (flags & 0xFFFF) {
+        /* If we have a precise definitions of the instructions set, use it */
+        disasm_info.mach = flags & 0xFFFF;
+    } else {
+#ifdef TARGET_PPC64
+        disasm_info.mach = bfd_mach_ppc64;
+#else
+        disasm_info.mach = bfd_mach_ppc;
+#endif
+    }
     print_insn = print_insn_ppc;
 #elif defined(TARGET_M68K)
     print_insn = print_insn_m68k;
@@ -197,6 +202,9 @@
 #elif defined(TARGET_SH4)
     disasm_info.mach = bfd_mach_sh4;
     print_insn = print_insn_sh;
+#elif defined(TARGET_ALPHA)
+    disasm_info.mach = bfd_mach_alpha;
+    print_insn = print_insn_alpha;
 #else
     fprintf(out, "0x" TARGET_FMT_lx
 	    ": Asm output not supported on this arch\n", code);
@@ -255,7 +263,10 @@
     print_insn = print_insn_alpha;
 #elif defined(__sparc__)
     print_insn = print_insn_sparc;
-#elif defined(__arm__) 
+#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
+    disasm_info.mach = bfd_mach_sparc_v9b;
+#endif
+#elif defined(__arm__)
     print_insn = print_insn_arm;
 #elif defined(__MIPSEB__)
     print_insn = print_insn_big_mips;
@@ -263,6 +274,8 @@
     print_insn = print_insn_little_mips;
 #elif defined(__m68k__)
     print_insn = print_insn_m68k;
+#elif defined(__s390__)
+    print_insn = print_insn_s390;
 #else
     fprintf(out, "0x%lx: Asm output not supported on this arch\n",
 	    (long) code);
@@ -290,7 +303,7 @@
     Elf32_Sym *sym;
     struct syminfo *s;
     target_ulong addr;
-    
+
     for (s = syminfos; s; s = s->next) {
 	sym = s->disas_symtab;
 	for (i = 0; i < s->disas_num_syms; i++) {
@@ -302,8 +315,8 @@
 		continue;
 
 	    addr = sym[i].st_value;
-#ifdef TARGET_ARM
-            /* The bottom address bit marks a Thumb symbol.  */
+#if defined(TARGET_ARM) || defined (TARGET_MIPS)
+            /* The bottom address bit marks a Thumb or MIPS16 symbol.  */
             addr &= ~(target_ulong)1;
 #endif
 	    if (orig_addr >= addr
@@ -369,7 +382,7 @@
 #if defined(TARGET_I386)
     if (flags == 2)
         disasm_info.mach = bfd_mach_x86_64;
-    else if (flags == 1) 
+    else if (flags == 1)
         disasm_info.mach = bfd_mach_i386_i8086;
     else
         disasm_info.mach = bfd_mach_i386_i386;
@@ -378,6 +391,9 @@
     print_insn = print_insn_arm;
 #elif defined(TARGET_SPARC)
     print_insn = print_insn_sparc;
+#ifdef TARGET_SPARC64
+    disasm_info.mach = bfd_mach_sparc_v9b;
+#endif
 #elif defined(TARGET_PPC)
 #ifdef TARGET_PPC64
     disasm_info.mach = bfd_mach_ppc64;
diff --git a/dyngen-exec.h b/dyngen-exec.h
index 7b313d6..37c593e 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -78,27 +78,30 @@
 #define UINT32_MAX		(4294967295U)
 #define UINT64_MAX		((uint64_t)(18446744073709551615))
 
+#ifdef _BSD
+typedef struct __sFILE FILE;
+#else
 typedef struct FILE FILE;
+#endif
 extern int fprintf(FILE *, const char *, ...);
+extern int fputs(const char *, FILE *);
 extern int printf(const char *, ...);
 #undef NULL
 #define NULL 0
 
-#ifdef __i386__
+#if defined(__i386__)
 #define AREG0 "ebp"
 #define AREG1 "ebx"
 #define AREG2 "esi"
 #define AREG3 "edi"
-#endif
-#ifdef __x86_64__
-#define AREG0 "rbp"
-#define AREG1 "rbx"
+#elif defined(__x86_64__)
+#define AREG0 "r14"
+#define AREG1 "r15"
 #define AREG2 "r12"
 #define AREG3 "r13"
-//#define AREG4 "r14"
-//#define AREG5 "r15"
-#endif
-#ifdef __powerpc__
+//#define AREG4 "rbp"
+//#define AREG5 "rbx"
+#elif defined(__powerpc__)
 #define AREG0 "r27"
 #define AREG1 "r24"
 #define AREG2 "r25"
@@ -116,20 +119,22 @@
 #endif
 #define USE_INT_TO_FLOAT_HELPERS
 #define BUGGY_GCC_DIV64
-#endif
-#ifdef __arm__
+#elif defined(__arm__)
 #define AREG0 "r7"
 #define AREG1 "r4"
 #define AREG2 "r5"
 #define AREG3 "r6"
-#endif
-#ifdef __mips__
-#define AREG0 "s3"
+#elif defined(__mips__)
+#define AREG0 "fp"
 #define AREG1 "s0"
 #define AREG2 "s1"
 #define AREG3 "s2"
-#endif
-#ifdef __sparc__
+#define AREG4 "s3"
+#define AREG5 "s4"
+#define AREG6 "s5"
+#define AREG7 "s6"
+#define AREG8 "s7"
+#elif defined(__sparc__)
 #ifdef HOST_SOLARIS
 #define AREG0 "g2"
 #define AREG1 "g3"
@@ -158,14 +163,12 @@
 #endif
 #endif
 #define USE_FP_CONVERT
-#endif
-#ifdef __s390__
+#elif defined(__s390__)
 #define AREG0 "r10"
 #define AREG1 "r7"
 #define AREG2 "r8"
 #define AREG3 "r9"
-#endif
-#ifdef __alpha__
+#elif defined(__alpha__)
 /* Note $15 is the frame pointer, so anything in op-i386.c that would
    require a frame pointer, like alloca, would probably loose.  */
 #define AREG0 "$15"
@@ -175,19 +178,19 @@
 #define AREG4 "$12"
 #define AREG5 "$13"
 #define AREG6 "$14"
-#endif
-#ifdef __mc68000
+#elif defined(__mc68000)
 #define AREG0 "%a5"
 #define AREG1 "%a4"
 #define AREG2 "%d7"
 #define AREG3 "%d6"
 #define AREG4 "%d5"
-#endif
-#ifdef __ia64__
+#elif defined(__ia64__)
 #define AREG0 "r7"
 #define AREG1 "r4"
 #define AREG2 "r5"
 #define AREG3 "r6"
+#else
+#error unsupported CPU
 #endif
 
 /* force GCC to generate only one epilog at the end of the function */
@@ -206,7 +209,7 @@
 /* the symbols are considered non exported so a br immediate is generated */
 #define __hidden __attribute__((visibility("hidden")))
 #else
-#define __hidden 
+#define __hidden
 #endif
 
 #if defined(__alpha__)
@@ -240,40 +243,37 @@
 #define ASM_NAME(x) #x
 #endif
 
-#ifdef __i386__
+#if defined(__i386__)
 #define EXIT_TB() asm volatile ("ret")
 #define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __x86_64__
+#elif defined(__x86_64__)
 #define EXIT_TB() asm volatile ("ret")
 #define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __powerpc__
+#elif defined(__powerpc__)
 #define EXIT_TB() asm volatile ("blr")
 #define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __s390__
+#elif defined(__s390__)
 #define EXIT_TB() asm volatile ("br %r14")
-#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __alpha__
+#define GOTO_LABEL_PARAM(n) asm volatile ("bras %r7,8; .long " ASM_NAME(__op_gen_label) #n "; l %r7, 0(%r7); br %r7")
+#elif defined(__alpha__)
 #define EXIT_TB() asm volatile ("ret")
-#endif
-#ifdef __ia64__
+#elif defined(__ia64__)
 #define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
 #define GOTO_LABEL_PARAM(n) asm volatile ("br.sptk.many " \
 					  ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __sparc__
+#elif defined(__sparc__)
 #define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop")
 #define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n ";nop")
-#endif
-#ifdef __arm__
+#elif defined(__arm__)
 #define EXIT_TB() asm volatile ("b exec_loop")
 #define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __mc68000
+#elif defined(__mc68000)
 #define EXIT_TB() asm volatile ("rts")
+#elif defined(__mips__)
+#define EXIT_TB() asm volatile ("jr $ra")
+#define GOTO_LABEL_PARAM(n) asm volatile (".set noat; la $1, " ASM_NAME(__op_gen_label) #n "; jr $1; .set at")
+#else
+#error unsupported CPU
 #endif
 
 #endif /* !defined(__DYNGEN_EXEC_H__) */
diff --git a/dyngen.c b/dyngen.c
index bcfb86e..f136e02 100644
--- a/dyngen.c
+++ b/dyngen.c
@@ -1,6 +1,6 @@
 /*
  *  Generic Dynamic compiler generator
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  *  The COFF object format support was extracted from Kazu's QEMU port
@@ -117,6 +117,21 @@
 #define elf_check_arch(x) ((x) == EM_68K)
 #define ELF_USES_RELOCA
 
+#elif defined(HOST_MIPS)
+
+#define ELF_CLASS	ELFCLASS32
+#define ELF_ARCH	EM_MIPS
+#define elf_check_arch(x) ((x) == EM_MIPS)
+#define ELF_USES_RELOC
+
+#elif defined(HOST_MIPS64)
+
+/* Assume n32 ABI here, which is ELF32. */
+#define ELF_CLASS	ELFCLASS32
+#define ELF_ARCH	EM_MIPS
+#define elf_check_arch(x) ((x) == EM_MIPS)
+#define ELF_USES_RELOCA
+
 #else
 #error unsupported CPU - please update the code
 #endif
@@ -148,11 +163,11 @@
 
 #ifdef CONFIG_FORMAT_COFF
 
-#include "a.out.h"
-
 typedef int32_t host_long;
 typedef uint32_t host_ulong;
 
+#include "a.out.h"
+
 #define FILENAMELEN 256
 
 typedef struct coff_sym {
@@ -189,11 +204,11 @@
 struct nlist_extended
 {
    union {
-   char *n_name; 
-   long  n_strx; 
+   char *n_name;
+   long  n_strx;
    } n_un;
-   unsigned char n_type; 
-   unsigned char n_sect; 
+   unsigned char n_type;
+   unsigned char n_sect;
    short st_desc;
    unsigned long st_value;
    unsigned long st_size;
@@ -357,10 +372,10 @@
   } swaptest;
 
   swaptest.i = 1;
-  return (h->e_ident[EI_DATA] == ELFDATA2MSB) != 
+  return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
       (swaptest.b[0] == 0);
 }
-  
+
 void elf_swap_ehdr(struct elfhdr *h)
 {
     swab16s(&h->e_type);			/* Object file type */
@@ -413,7 +428,7 @@
 #endif
 }
 
-struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr, 
+struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
                                   const char *name)
 {
     int i;
@@ -438,7 +453,7 @@
 
     for(i = 0; i < ehdr.e_shnum; i++) {
         sec = &shdr[i];
-        if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index) 
+        if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
             return i;
     }
     return 0;
@@ -468,11 +483,11 @@
     ElfW(Sym) *sym;
     char *shstr;
     ELF_RELOC *rel;
-    
+
     fd = open(filename, O_RDONLY);
-    if (fd < 0) 
+    if (fd < 0)
         error("can't open file '%s'", filename);
-    
+
     /* Read ELF header.  */
     if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
         error("unable to read file header");
@@ -509,7 +524,7 @@
     /* read all section data */
     sdata = malloc(sizeof(void *) * ehdr.e_shnum);
     memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
-    
+
     for(i = 0;i < ehdr.e_shnum; i++) {
         sec = &shdr[i];
         if (sec->sh_type != SHT_NOBITS)
@@ -554,7 +569,7 @@
 
     symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
     strtab = (char *)sdata[symtab_sec->sh_link];
-    
+
     nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
     if (do_swap) {
         for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
@@ -594,7 +609,7 @@
 {
     char *q;
     int c, i, len;
-    
+
     if (ext_sym->e.e.e_zeroes != 0) {
         q = sym->st_name;
         for(i = 0; i < 8; i++) {
@@ -628,7 +643,7 @@
 		if (sym->st_syment->e_scnum == data_shndx &&
                     text_data >= sym->st_value &&
                     text_data < sym->st_value + sym->st_size) {
-                    
+
                     return sym->st_name;
 
 		}
@@ -686,15 +701,15 @@
     uint32_t *n_strtab;
     EXE_SYM *sym;
     EXE_RELOC *rel;
-	
-    fd = open(filename, O_RDONLY 
+
+    fd = open(filename, O_RDONLY
 #ifdef _WIN32
               | O_BINARY
 #endif
               );
-    if (fd < 0) 
+    if (fd < 0)
         error("can't open file '%s'", filename);
-    
+
     /* Read COFF header.  */
     if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
         error("unable to read file header");
@@ -707,11 +722,11 @@
 
     /* read section headers */
     shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
-	
+
     /* read all section data */
     sdata = malloc(sizeof(void *) * fhdr.f_nscns);
     memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
-    
+
     const char *p;
     for(i = 0;i < fhdr.f_nscns; i++) {
         sec = &shdr[i];
@@ -732,7 +747,7 @@
     if (!data_sec)
         error("could not find .data section");
     coff_data_shndx = data_sec - shdr;
-    
+
     coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ);
     for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
         for(i=0;i<8;i++)
@@ -742,8 +757,8 @@
 
 
     n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
-    strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab); 
-    
+    strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab);
+
     nb_syms = fhdr.f_nsyms;
 
     for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
@@ -790,12 +805,12 @@
 		} else {
 			sym->st_size = 0;
 		}
-		
+
 		sym->st_type = ext_sym->e_type;
 		sym->st_shndx = ext_sym->e_scnum;
 	}
 
-		
+
     /* find text relocations, if any */
     sec = &shdr[coff_text_shndx];
     coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ);
@@ -803,7 +818,7 @@
 
     /* set coff relocation */
     relocs = malloc(sizeof(struct coff_rel) * nb_relocs);
-    for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs; 
+    for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs;
          i++, ext_rel++, rel++) {
         memset(rel, 0, sizeof(*rel));
         rel->r_reloc = ext_rel;
@@ -832,7 +847,7 @@
 
 /* relocs */
 struct relocation_info *relocs;
-	
+
 /* symbols */
 EXE_SYM			*symtab;
 struct nlist 	*symtab_std;
@@ -852,10 +867,10 @@
 static char *get_sym_name(EXE_SYM *sym)
 {
 	char *name = find_str_by_index(sym->n_un.n_strx);
-	
+
 	if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */
 		return "debug";
-			
+
 	if(!name)
 		return name;
 	if(name[0]=='_')
@@ -865,7 +880,7 @@
 }
 
 /* find a section index given its segname, sectname */
-static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname, 
+static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname,
                                   const char *sectname)
 {
     int i;
@@ -881,7 +896,7 @@
 }
 
 /* find a section header given its segname, sectname */
-struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname, 
+struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname,
                                   const char *sectname)
 {
     int index = find_mach_sec_index(section_hdr, shnum, segname, sectname);
@@ -894,7 +909,7 @@
 static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value)
 {
     struct scattered_relocation_info * scarel;
-	
+
     if(R_SCATTERED & rel->r_address) {
         scarel = (struct scattered_relocation_info*)rel;
         if(scarel->r_type != PPC_RELOC_PAIR)
@@ -911,7 +926,7 @@
 static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
 {
 	int i, ret = -1;
-	
+
 	for( i = 0 ; i < nb_syms; i++ )
 	{
 	    if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) &&
@@ -930,35 +945,35 @@
 	}
 }
 
-/* 
- *  Find symbol name given a (virtual) address, and a section which is of type 
+/*
+ *  Find symbol name given a (virtual) address, and a section which is of type
  *  S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
  */
 static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec_hdr)
 {
     unsigned int tocindex, symindex, size;
     const char *name = 0;
-    
+
     /* Sanity check */
     if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) )
         return (char*)0;
-		
+
 	if( sec_hdr->flags & S_SYMBOL_STUBS ){
 		size = sec_hdr->reserved2;
 		if(size == 0)
 		    error("size = 0");
-		
+
 	}
 	else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS ||
 	            sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS)
 		size = sizeof(unsigned long);
 	else
 		return 0;
-		
+
     /* Compute our index in toc */
 	tocindex = (address - sec_hdr->addr)/size;
 	symindex = tocdylib[sec_hdr->reserved1 + tocindex];
-	
+
 	name = get_sym_name(&symtab[symindex]);
 
     return name;
@@ -983,24 +998,24 @@
 	int sectnum = rel->r_symbolnum;
 	int sectoffset;
 	int other_half=0;
-	
+
 	/* init the slide value */
 	*sslide = 0;
-	
+
 	if(R_SCATTERED & rel->r_address)
 		return (char *)find_reloc_name_given_its_address(sca_rel->r_value);
 
 	if(rel->r_extern)
 	{
 		/* ignore debug sym */
-		if ( symtab[rel->r_symbolnum].n_type & N_STAB ) 
+		if ( symtab[rel->r_symbolnum].n_type & N_STAB )
 			return 0;
 		return get_sym_name(&symtab[rel->r_symbolnum]);
 	}
 
 	/* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */
 	sectoffset = *(uint32_t *)(text + rel->r_address) & 0xffff;
-			
+
 	if(sectnum==0xffffff)
 		return 0;
 
@@ -1026,14 +1041,14 @@
 
 	if(rel->r_pcrel)
 		sectoffset += rel->r_address;
-			
+
 	if (rel->r_type == PPC_RELOC_BR24)
 		name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, &section_hdr[sectnum-1]);
 
 	/* search it in the full symbol list, if not found */
 	if(!name)
 		name = (char *)find_sym_with_value_and_sec_number(sectoffset, sectnum, sslide);
-	
+
 	return name;
 }
 
@@ -1065,11 +1080,11 @@
     unsigned int i, j;
 	EXE_SYM *sym;
 	struct nlist *syment;
-    
+
 	fd = open(filename, O_RDONLY);
-    if (fd < 0) 
+    if (fd < 0)
         error("can't open file '%s'", filename);
-		
+
     /* Read Mach header.  */
     if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
         error("unable to read file header");
@@ -1078,13 +1093,13 @@
     if (!check_mach_header(mach_hdr)) {
         error("bad Mach header");
     }
-    
+
     if (mach_hdr.cputype != CPU_TYPE_POWERPC)
         error("Unsupported CPU");
-        
+
     if (mach_hdr.filetype != MH_OBJECT)
         error("Unsupported Mach Object");
-    
+
     /* read segment headers */
     for(i=0, j=sizeof(mach_hdr); i<mach_hdr.ncmds ; i++)
     {
@@ -1128,26 +1143,26 @@
     /* read all section data */
     sdata = (uint8_t **)malloc(sizeof(void *) * segment->nsects);
     memset(sdata, 0, sizeof(void *) * segment->nsects);
-    
+
 	/* Load the data in section data */
 	for(i = 0; i < segment->nsects; i++) {
         sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size);
     }
-	
+
     /* text section */
 	text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
 	i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
 	if (i == -1 || !text_sec_hdr)
         error("could not find __TEXT,__text section");
     text = sdata[i];
-	
+
     /* Make sure dysym was loaded */
     if(!(int)dysymtabcmd)
         error("could not find __DYSYMTAB segment");
-    
+
     /* read the table of content of the indirect sym */
     tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
-    
+
     /* Make sure symtab was loaded  */
     if(!(int)symtabcmd)
         error("could not find __SYMTAB segment");
@@ -1155,20 +1170,20 @@
 
     symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist));
     strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize);
-	
+
 	symtab = malloc(sizeof(EXE_SYM) * nb_syms);
-	
+
 	/* Now transform the symtab, to an extended version, with the sym size, and the C name */
 	for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
         struct nlist *sym_follow, *sym_next = 0;
         unsigned int j;
 		memset(sym, 0, sizeof(*sym));
-		
+
 		if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
             continue;
-			
+
 		memcpy(sym, syment, sizeof(*syment));
-			
+
 		/* Find the following symbol in order to get the current symbol size */
         for(j = 0, sym_follow = symtab_std; j < nb_syms; j++, sym_follow++) {
             if ( sym_follow->n_sect != 1 || sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
@@ -1186,7 +1201,7 @@
 		else
             sym->st_size = text_sec_hdr->size - sym->st_value;
 	}
-	
+
     /* Find Reloc */
     relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
     nb_relocs = text_sec_hdr->nreloc;
@@ -1271,9 +1286,9 @@
     uint8_t data_allocated[1024];
     unsigned int data_index;
     int type;
-    
+
     memset(data_allocated, 0, sizeof(data_allocated));
-    
+
     p = p_start;
     min_offset = p_end - p_start;
     spare = 0x7fffffff;
@@ -1316,25 +1331,25 @@
             if (spare > max_pool - offset)
                 spare = max_pool - offset;
             if ((offset & 3) !=0)
-                error("%s:%04x: pc offset must be 32 bit aligned", 
+                error("%s:%04x: pc offset must be 32 bit aligned",
                       name, start_offset + p - p_start);
             if (offset < 0)
                 error("%s:%04x: Embedded literal value",
                       name, start_offset + p - p_start);
             pc_offset = p - p_start + offset + 8;
-            if (pc_offset <= (p - p_start) || 
+            if (pc_offset <= (p - p_start) ||
                 pc_offset >= (p_end - p_start))
-                error("%s:%04x: pc offset must point inside the function code", 
+                error("%s:%04x: pc offset must point inside the function code",
                       name, start_offset + p - p_start);
             if (pc_offset < min_offset)
                 min_offset = pc_offset;
             if (outfile) {
                 /* The intruction position */
-                fprintf(outfile, "    arm_ldr_ptr->ptr = gen_code_ptr + %d;\n", 
+                fprintf(outfile, "    arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
                         p - p_start);
                 /* The position of the constant pool data.  */
                 data_index = ((p_end - p_start) - pc_offset) >> 2;
-                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n", 
+                fprintf(outfile, "    arm_ldr_ptr->data_ptr = arm_data_ptr - %d;\n",
                         data_index);
                 fprintf(outfile, "    arm_ldr_ptr->type = %d;\n", type);
                 fprintf(outfile, "    arm_ldr_ptr++;\n");
@@ -1417,7 +1432,7 @@
 #define MAX_ARGS 3
 
 /* generate op code */
-void gen_code(const char *name, host_ulong offset, host_ulong size, 
+void gen_code(const char *name, host_ulong offset, host_ulong size,
               FILE *outfile, int gen_switch)
 {
     int copy_size = 0;
@@ -1463,7 +1478,7 @@
         }
         copy_size = len;
     }
-#endif    
+#endif
 #elif defined(HOST_PPC)
     {
         uint8_t *p;
@@ -1495,7 +1510,7 @@
 #endif
         if (get32((uint32_t *)p) != 0x6bfa8001)
             error("ret expected at the end of %s", name);
-        copy_size = p - p_start;	    
+        copy_size = p - p_start;
     }
 #elif defined(HOST_IA64)
     {
@@ -1596,14 +1611,14 @@
         } else {
             error("No save at the beginning of %s", name);
         }
-        
+
         /* Skip a preceeding nop, if present.  */
         if (p > p_start) {
             skip_insn = get32((uint32_t *)(p - 0x4));
             if (skip_insn == 0x01000000)
                 p -= 4;
         }
-        
+
         copy_size = p - p_start;
     }
 #elif defined(HOST_ARM)
@@ -1624,7 +1639,7 @@
             p_start -= 4;
             start_offset -= 4;
         }
-        copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end, 
+        copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
                                       relocs, nb_relocs);
     }
 #elif defined(HOST_M68K)
@@ -1635,12 +1650,32 @@
             error("empty code for %s", name);
         // remove NOP's, probably added for alignment
         while ((get16((uint16_t *)p) == 0x4e71) &&
-               (p>p_start)) 
+               (p>p_start))
             p -= 2;
         if (get16((uint16_t *)p) != 0x4e75)
             error("rts expected at the end of %s", name);
         copy_size = p - p_start;
     }
+#elif defined(HOST_MIPS) || defined(HOST_MIPS64)
+    {
+#define INSN_RETURN     0x03e00008
+#define INSN_NOP        0x00000000
+
+        uint8_t *p = p_end;
+
+        if (p < (p_start + 0x8)) {
+            error("empty code for %s", name);
+        } else {
+            uint32_t end_insn1, end_insn2;
+
+            p -= 0x8;
+            end_insn1 = get32((uint32_t *)(p + 0x0));
+            end_insn2 = get32((uint32_t *)(p + 0x4));
+            if (end_insn1 != INSN_RETURN && end_insn2 != INSN_NOP)
+                error("jr ra not found at end of %s", name);
+        }
+        copy_size = p - p_start;
+    }
 #else
 #error unsupported CPU
 #endif
@@ -1665,7 +1700,7 @@
             }
         }
     }
-    
+
     nb_args = 0;
     while (nb_args < MAX_ARGS && args_present[nb_args])
         nb_args++;
@@ -1702,7 +1737,7 @@
                 sym_name = get_rel_sym_name(rel);
                 if(!sym_name)
                     continue;
-                if (*sym_name && 
+                if (*sym_name &&
                     !strstart(sym_name, "__op_param", NULL) &&
                     !strstart(sym_name, "__op_jmp", NULL) &&
                     !strstart(sym_name, "__op_gen_label", NULL)) {
@@ -1715,8 +1750,9 @@
 		    }
 #endif
 #if defined(__APPLE__)
-/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
-                    fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
+                    /* Set __attribute((unused)) on darwin because we
+                       want to avoid warning when we don't use the symbol.  */
+                    fprintf(outfile, "    extern char %s __attribute__((unused));\n", sym_name);
 #elif defined(HOST_IA64)
 			if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
 				/*
@@ -1740,7 +1776,7 @@
         {
             EXE_SYM *sym;
             const char *sym_name, *p;
-            unsigned long val;
+            host_ulong val;
             int n;
 
             for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
@@ -1748,7 +1784,7 @@
                 if (strstart(sym_name, "__op_label", &p)) {
                     uint8_t *ptr;
                     unsigned long offset;
-                    
+
                     /* test if the variable refers to a label inside
                        the code we are generating */
 #ifdef CONFIG_FORMAT_COFF
@@ -1772,7 +1808,7 @@
 #ifdef CONFIG_FORMAT_MACH
                     offset -= section_hdr[sym->n_sect-1].addr;
 #endif
-                    val = *(unsigned long *)(ptr + offset);
+                    val = *(host_ulong *)(ptr + offset);
 #ifdef ELF_USES_RELOCA
                     {
                         int reloc_shndx, nb_relocs1, j;
@@ -1780,7 +1816,7 @@
                         /* try to find a matching relocation */
                         reloc_shndx = find_reloc(sym->st_shndx);
                         if (reloc_shndx) {
-                            nb_relocs1 = shdr[reloc_shndx].sh_size / 
+                            nb_relocs1 = shdr[reloc_shndx].sh_size /
                                 shdr[reloc_shndx].sh_entsize;
                             rel = (ELF_RELOC *)sdata[reloc_shndx];
                             for(j = 0; j < nb_relocs1; j++) {
@@ -1792,7 +1828,7 @@
                             }
                         }
                     }
-#endif                    
+#endif
                     if (val >= start_offset && val <= start_offset + copy_size) {
                         n = strtol(p, NULL, 10);
                         fprintf(outfile, "    label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
@@ -1801,7 +1837,7 @@
             }
         }
 
-        /* load parameres in variables */
+        /* load parameters in variables */
         for(i = 0; i < nb_args; i++) {
             fprintf(outfile, "    param%d = *opparam_ptr++;\n", i + 1);
         }
@@ -1809,7 +1845,7 @@
         /* patch relocations */
 #if defined(HOST_I386)
             {
-                char name[256];
+                char relname[256];
                 int type;
                 int addend;
                 int reloc_offset;
@@ -1832,18 +1868,18 @@
                         continue;
                     }
 
-                    get_reloc_expr(name, sizeof(name), sym_name);
+                    get_reloc_expr(relname, sizeof(relname), sym_name);
                     addend = get32((uint32_t *)(text + rel->r_offset));
 #ifdef CONFIG_FORMAT_ELF
                     type = ELF32_R_TYPE(rel->r_info);
                     switch(type) {
                     case R_386_32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                reloc_offset, name, addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                reloc_offset, relname, addend);
                         break;
                     case R_386_PC32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", 
-                                reloc_offset, name, reloc_offset, addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
+                                reloc_offset, relname, reloc_offset, addend);
                         break;
                     default:
                         error("unsupported i386 relocation (%d)", type);
@@ -1865,12 +1901,12 @@
                     type = rel->r_type;
                     switch(type) {
                     case DIR32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                reloc_offset, name, addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                reloc_offset, relname, addend);
                         break;
                     case DISP32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n", 
-                                reloc_offset, name, reloc_offset, addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
+                                reloc_offset, relname, reloc_offset, addend);
                         break;
                     default:
                         error("unsupported i386 relocation (%d)", type);
@@ -1883,7 +1919,7 @@
             }
 #elif defined(HOST_X86_64)
             {
-                char name[256];
+                char relname[256];
                 int type;
                 int addend;
                 int reloc_offset;
@@ -1891,22 +1927,22 @@
                 if (rel->r_offset >= start_offset &&
 		    rel->r_offset < start_offset + copy_size) {
                     sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
-                    get_reloc_expr(name, sizeof(name), sym_name);
+                    get_reloc_expr(relname, sizeof(relname), sym_name);
                     type = ELF32_R_TYPE(rel->r_info);
                     addend = rel->r_addend;
                     reloc_offset = rel->r_offset - start_offset;
                     switch(type) {
                     case R_X86_64_32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n", 
-                                reloc_offset, name, addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
+                                reloc_offset, relname, addend);
                         break;
                     case R_X86_64_32S:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n", 
-                                reloc_offset, name, addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
+                                reloc_offset, relname, addend);
                         break;
                     case R_X86_64_PC32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n", 
-                                reloc_offset, name, reloc_offset, addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
+                                reloc_offset, relname, reloc_offset, addend);
                         break;
                     default:
                         error("unsupported X86_64 relocation (%d)", type);
@@ -1917,7 +1953,7 @@
 #elif defined(HOST_PPC)
             {
 #ifdef CONFIG_FORMAT_ELF
-                char name[256];
+                char relname[256];
                 int type;
                 int addend;
                 int reloc_offset;
@@ -1937,31 +1973,31 @@
                                     n, reloc_offset);
                             continue;
                         }
-                        
-                        get_reloc_expr(name, sizeof(name), sym_name);
+
+                        get_reloc_expr(relname, sizeof(relname), sym_name);
                         type = ELF32_R_TYPE(rel->r_info);
                         addend = rel->r_addend;
                         switch(type) {
                         case R_PPC_ADDR32:
-                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    reloc_offset, name, addend);
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    reloc_offset, relname, addend);
                             break;
                         case R_PPC_ADDR16_LO:
-                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n", 
-                                    reloc_offset, name, addend);
+                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
+                                    reloc_offset, relname, addend);
                             break;
                         case R_PPC_ADDR16_HI:
-                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n", 
-                                    reloc_offset, name, addend);
+                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
+                                    reloc_offset, relname, addend);
                             break;
                         case R_PPC_ADDR16_HA:
-                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n", 
-                                    reloc_offset, name, addend);
+                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
+                                    reloc_offset, relname, addend);
                             break;
                         case R_PPC_REL24:
                             /* warning: must be at 32 MB distancy */
-                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n", 
-                                    reloc_offset, reloc_offset, name, reloc_offset, addend);
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
+                                    reloc_offset, reloc_offset, relname, reloc_offset, addend);
                             break;
                         default:
                             error("unsupported powerpc relocation (%d)", type);
@@ -1969,98 +2005,97 @@
                     }
                 }
 #elif defined(CONFIG_FORMAT_MACH)
-				struct scattered_relocation_info *scarel;
-				struct relocation_info * rel;
-				char final_sym_name[256];
-				const char *sym_name;
-				const char *p;
-				int slide, sslide;
-				int i;
-	
-				for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
-					unsigned int offset, length, value = 0;
-					unsigned int type, pcrel, isym = 0;
-					unsigned int usesym = 0;
-				
-					if(R_SCATTERED & rel->r_address) {
-						scarel = (struct scattered_relocation_info*)rel;
-						offset = (unsigned int)scarel->r_address;
-						length = scarel->r_length;
-						pcrel = scarel->r_pcrel;
-						type = scarel->r_type;
-						value = scarel->r_value;
-					} else {
-						value = isym = rel->r_symbolnum;
-						usesym = (rel->r_extern);
-						offset = rel->r_address;
-						length = rel->r_length;
-						pcrel = rel->r_pcrel;
-						type = rel->r_type;
-					}
-				
-					slide = offset - start_offset;
-		
-					if (!(offset >= start_offset && offset < start_offset + size)) 
-						continue;  /* not in our range */
+                struct scattered_relocation_info *scarel;
+                struct relocation_info * rel;
+                char final_sym_name[256];
+                const char *sym_name;
+                const char *p;
+                int slide, sslide;
+                int i;
 
-					sym_name = get_reloc_name(rel, &sslide);
-					
-					if(usesym && symtab[isym].n_type & N_STAB)
-						continue; /* don't handle STAB (debug sym) */
-					
-					if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
-						int n;
-						n = strtol(p, NULL, 10);
-						fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
-							n, slide);
-						continue; /* Nothing more to do */
-					}
-					
-					if(!sym_name)
-					{
-						fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
-						           name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
-						continue; /* dunno how to handle without final_sym_name */
-					}
-													   
-                                        get_reloc_expr(final_sym_name, sizeof(final_sym_name), 
-                                                       sym_name);
-					switch(type) {
-					case PPC_RELOC_BR24:
-					    if (!strstart(sym_name,"__op_gen_label",&p)) {
-    						fprintf(outfile, "{\n");
-    						fprintf(outfile, "    uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
-    						fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n", 
-											slide, slide, name, sslide );
-    						fprintf(outfile, "}\n");
-    					} else {
-							fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
-											slide, slide, final_sym_name, slide);
-    					}
-						break;
-					case PPC_RELOC_HI16:
-						fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n", 
-							slide, final_sym_name, sslide);
-						break;
-					case PPC_RELOC_LO16:
-						fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n", 
-					slide, final_sym_name, sslide);
+                for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
+                    unsigned int offset, length, value = 0;
+                    unsigned int type, pcrel, isym = 0;
+                    unsigned int usesym = 0;
+
+                    if(R_SCATTERED & rel->r_address) {
+                        scarel = (struct scattered_relocation_info*)rel;
+                        offset = (unsigned int)scarel->r_address;
+                        length = scarel->r_length;
+                        pcrel = scarel->r_pcrel;
+                        type = scarel->r_type;
+                        value = scarel->r_value;
+                    } else {
+                        value = isym = rel->r_symbolnum;
+                        usesym = (rel->r_extern);
+                        offset = rel->r_address;
+                        length = rel->r_length;
+                        pcrel = rel->r_pcrel;
+                        type = rel->r_type;
+                    }
+
+                    slide = offset - start_offset;
+
+                    if (!(offset >= start_offset && offset < start_offset + size))
+                        continue;  /* not in our range */
+
+                        sym_name = get_reloc_name(rel, &sslide);
+
+                        if(usesym && symtab[isym].n_type & N_STAB)
+                            continue; /* don't handle STAB (debug sym) */
+
+                        if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
+                            int n;
+                            n = strtol(p, NULL, 10);
+                            fprintf(outfile, "    jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n",
+                                    n, slide);
+                            continue; /* Nothing more to do */
+                        }
+
+                        if(!sym_name) {
+                            fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
+                                    name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
+                            continue; /* dunno how to handle without final_sym_name */
+                        }
+
+                        get_reloc_expr(final_sym_name, sizeof(final_sym_name),
+                                       sym_name);
+                        switch(type) {
+                        case PPC_RELOC_BR24:
+                            if (!strstart(sym_name,"__op_gen_label",&p)) {
+                                fprintf(outfile, "{\n");
+                                fprintf(outfile, "    uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
+                                fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n",
+                                        slide, slide, name, sslide);
+                                fprintf(outfile, "}\n");
+                            } else {
+                                fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
+                                        slide, slide, final_sym_name, slide);
+                            }
                             break;
-					case PPC_RELOC_HA16:
-						fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n", 
-							slide, final_sym_name, sslide);
-						break;
-				default:
-					error("unsupported powerpc relocation (%d)", type);
-				}
-			}
+                        case PPC_RELOC_HI16:
+                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
+                                    slide, final_sym_name, sslide);
+                            break;
+                        case PPC_RELOC_LO16:
+                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n",
+                                    slide, final_sym_name, sslide);
+                            break;
+                        case PPC_RELOC_HA16:
+                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n",
+                                    slide, final_sym_name, sslide);
+                            break;
+                        default:
+                            error("unsupported powerpc relocation (%d)", type);
+                    }
+                }
 #else
 #error unsupport object format
 #endif
             }
 #elif defined(HOST_S390)
             {
-                char name[256];
+                char relname[256];
                 int type;
                 int addend;
                 int reloc_offset;
@@ -2068,22 +2103,22 @@
                     if (rel->r_offset >= start_offset &&
 			rel->r_offset < start_offset + copy_size) {
                         sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
-                        get_reloc_expr(name, sizeof(name), sym_name);
+                        get_reloc_expr(relname, sizeof(relname), sym_name);
                         type = ELF32_R_TYPE(rel->r_info);
                         addend = rel->r_addend;
                         reloc_offset = rel->r_offset - start_offset;
                         switch(type) {
                         case R_390_32:
-                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    reloc_offset, name, addend);
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    reloc_offset, relname, addend);
                             break;
                         case R_390_16:
-                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    reloc_offset, name, addend);
+                            fprintf(outfile, "    *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    reloc_offset, relname, addend);
                             break;
                         case R_390_8:
-                            fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    reloc_offset, name, addend);
+                            fprintf(outfile, "    *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    reloc_offset, relname, addend);
                             break;
                         default:
                             error("unsupported s390 relocation (%d)", type);
@@ -2151,7 +2186,7 @@
             {
 		unsigned long sym_idx;
 		long code_offset;
-                char name[256];
+                char relname[256];
                 int type;
                 long addend;
 
@@ -2174,7 +2209,7 @@
 				n, code_offset);
 			continue;
 		    }
-		    get_reloc_expr(name, sizeof(name), sym_name);
+		    get_reloc_expr(relname, sizeof(relname), sym_name);
 		    type = ELF64_R_TYPE(rel->r_info);
 		    addend = rel->r_addend;
 		    switch(type) {
@@ -2182,19 +2217,19 @@
 			  fprintf(outfile,
 				  "    ia64_imm64(gen_code_ptr + %ld, "
 				  "%s + %ld);\n",
-				  code_offset, name, addend);
+				  code_offset, relname, addend);
 			  break;
 		      case R_IA64_LTOFF22X:
 		      case R_IA64_LTOFF22:
 			  fprintf(outfile, "    IA64_LTOFF(gen_code_ptr + %ld,"
 				  " %s + %ld, %d);\n",
-				  code_offset, name, addend,
+				  code_offset, relname, addend,
 				  (type == R_IA64_LTOFF22X));
 			  break;
 		      case R_IA64_LDXMOV:
 			  fprintf(outfile,
 				  "    ia64_ldxmov(gen_code_ptr + %ld,"
-				  " %s + %ld);\n", code_offset, name, addend);
+				  " %s + %ld);\n", code_offset, relname, addend);
 			  break;
 
 		      case R_IA64_PCREL21B:
@@ -2203,7 +2238,7 @@
 				      "    ia64_imm21b(gen_code_ptr + %ld,"
 				      " (long) (%s + %ld -\n\t\t"
 				      "((long) gen_code_ptr + %ld)) >> 4);\n",
-				      code_offset, name, addend,
+				      code_offset, relname, addend,
 				      code_offset & ~0xfUL);
 			  } else {
 			      fprintf(outfile,
@@ -2224,7 +2259,7 @@
             }
 #elif defined(HOST_SPARC)
             {
-                char name[256];
+                char relname[256];
                 int type;
                 int addend;
                 int reloc_offset;
@@ -2232,14 +2267,14 @@
                     if (rel->r_offset >= start_offset &&
 			rel->r_offset < start_offset + copy_size) {
                         sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
-                        get_reloc_expr(name, sizeof(name), sym_name);
+                        get_reloc_expr(relname, sizeof(relname), sym_name);
                         type = ELF32_R_TYPE(rel->r_info);
                         addend = rel->r_addend;
                         reloc_offset = rel->r_offset - start_offset;
                         switch(type) {
                         case R_SPARC_32:
-                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                    reloc_offset, name, addend);
+                            fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                    reloc_offset, relname, addend);
 			    break;
 			case R_SPARC_HI22:
                             fprintf(outfile,
@@ -2247,7 +2282,7 @@
 				    "((*(uint32_t *)(gen_code_ptr + %d)) "
 				    " & ~0x3fffff) "
 				    " | (((%s + %d) >> 10) & 0x3fffff);\n",
-                                    reloc_offset, reloc_offset, name, addend);
+                                    reloc_offset, reloc_offset, relname, addend);
 			    break;
 			case R_SPARC_LO10:
                             fprintf(outfile,
@@ -2255,7 +2290,7 @@
 				    "((*(uint32_t *)(gen_code_ptr + %d)) "
 				    " & ~0x3ff) "
 				    " | ((%s + %d) & 0x3ff);\n",
-                                    reloc_offset, reloc_offset, name, addend);
+                                    reloc_offset, reloc_offset, relname, addend);
 			    break;
 			case R_SPARC_WDISP30:
 			    fprintf(outfile,
@@ -2264,7 +2299,7 @@
 				    " & ~0x3fffffff) "
 				    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
 				    "    & 0x3fffffff);\n",
-				    reloc_offset, reloc_offset, name, addend,
+				    reloc_offset, reloc_offset, relname, addend,
 				    reloc_offset);
 			    break;
                         case R_SPARC_WDISP22:
@@ -2276,7 +2311,7 @@
                                     "    & 0x3fffff);\n",
                                     rel->r_offset - start_offset,
                                     rel->r_offset - start_offset,
-                                    name, addend,
+                                    relname, addend,
                                     rel->r_offset - start_offset);
                             break;
                         default:
@@ -2287,7 +2322,7 @@
             }
 #elif defined(HOST_SPARC64)
             {
-                char name[256];
+                char relname[256];
                 int type;
                 int addend;
                 int reloc_offset;
@@ -2295,14 +2330,14 @@
                     if (rel->r_offset >= start_offset &&
 			rel->r_offset < start_offset + copy_size) {
                         sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
-                        get_reloc_expr(name, sizeof(name), sym_name);
+                        get_reloc_expr(relname, sizeof(relname), sym_name);
                         type = ELF32_R_TYPE(rel->r_info);
                         addend = rel->r_addend;
                         reloc_offset = rel->r_offset - start_offset;
                         switch(type) {
                         case R_SPARC_32:
                             fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
-                                    reloc_offset, name, addend);
+                                    reloc_offset, relname, addend);
 			    break;
 			case R_SPARC_HI22:
                             fprintf(outfile,
@@ -2310,7 +2345,7 @@
 				    "((*(uint32_t *)(gen_code_ptr + %d)) "
 				    " & ~0x3fffff) "
 				    " | (((%s + %d) >> 10) & 0x3fffff);\n",
-                                    reloc_offset, reloc_offset, name, addend);
+                                    reloc_offset, reloc_offset, relname, addend);
 			    break;
 			case R_SPARC_LO10:
                             fprintf(outfile,
@@ -2318,7 +2353,7 @@
 				    "((*(uint32_t *)(gen_code_ptr + %d)) "
 				    " & ~0x3ff) "
 				    " | ((%s + %d) & 0x3ff);\n",
-                                    reloc_offset, reloc_offset, name, addend);
+                                    reloc_offset, reloc_offset, relname, addend);
 			    break;
                         case R_SPARC_OLO10:
                             addend += ELF64_R_TYPE_DATA (rel->r_info);
@@ -2327,7 +2362,7 @@
 				    "((*(uint32_t *)(gen_code_ptr + %d)) "
 				    " & ~0x3ff) "
 				    " | ((%s + %d) & 0x3ff);\n",
-                                    reloc_offset, reloc_offset, name, addend);
+                                    reloc_offset, reloc_offset, relname, addend);
 			    break;
 			case R_SPARC_WDISP30:
 			    fprintf(outfile,
@@ -2336,7 +2371,7 @@
 				    " & ~0x3fffffff) "
 				    " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
 				    "    & 0x3fffffff);\n",
-				    reloc_offset, reloc_offset, name, addend,
+				    reloc_offset, reloc_offset, relname, addend,
 				    reloc_offset);
 			    break;
                         case R_SPARC_WDISP22:
@@ -2346,18 +2381,45 @@
                                     " & ~0x3fffff) "
                                     " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
                                     "    & 0x3fffff);\n",
-                                    reloc_offset, reloc_offset, name, addend,
+                                    reloc_offset, reloc_offset, relname, addend,
 				    reloc_offset);
                             break;
+                        case R_SPARC_HH22:
+                            fprintf(outfile,
+				    "    *(uint32_t *)(gen_code_ptr + %d) = "
+				    "((*(uint32_t *)(gen_code_ptr + %d)) "
+				    " & ~0x00000000) "
+				    " | (((%s + %d) >> 42) & 0x00000000);\n",
+                                    reloc_offset, reloc_offset, relname, addend);
+                             break;
+
+			case R_SPARC_LM22:
+                            fprintf(outfile,
+				    "    *(uint32_t *)(gen_code_ptr + %d) = "
+				    "((*(uint32_t *)(gen_code_ptr + %d)) "
+				    " & ~0x00000000) "
+				    " | (((%s + %d) >> 10) & 0x00000000);\n",
+                                    reloc_offset, reloc_offset, relname, addend);
+			    break;
+
+			case R_SPARC_HM10:
+                            fprintf(outfile,
+				    "    *(uint32_t *)(gen_code_ptr + %d) = "
+				    "((*(uint32_t *)(gen_code_ptr + %d)) "
+				    " & ~0x00000000) "
+				    " | ((((%s + %d) >> 32 & 0x3ff)) & 0x00000000);\n",
+                                    reloc_offset, reloc_offset, relname, addend);
+			    break;
+
                         default:
-			    error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
+			    error("unsupported sparc64 relocation (%d) for symbol %s", type, relname);
                         }
                     }
                 }
             }
 #elif defined(HOST_ARM)
             {
-                char name[256];
+                char relname[256];
                 int type;
                 int addend;
                 int reloc_offset;
@@ -2392,7 +2454,7 @@
                     fprintf(outfile,
                             "    *(uint32_t *)gen_code_ptr = 0x%x;\n", opcode);
                 }
-                arm_emit_ldr_info(name, start_offset, outfile, p_start, p_end,
+                arm_emit_ldr_info(relname, start_offset, outfile, p_start, p_end,
                                   relocs, nb_relocs);
 
                 for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
@@ -2402,20 +2464,20 @@
                     /* the compiler leave some unnecessary references to the code */
                     if (sym_name[0] == '\0')
                         continue;
-                    get_reloc_expr(name, sizeof(name), sym_name);
+                    get_reloc_expr(relname, sizeof(relname), sym_name);
                     type = ELF32_R_TYPE(rel->r_info);
                     addend = get32((uint32_t *)(text + rel->r_offset));
                     reloc_offset = rel->r_offset - start_offset;
                     switch(type) {
                     case R_ARM_ABS32:
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n", 
-                                reloc_offset, name, addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+                                reloc_offset, relname, addend);
                         break;
                     case R_ARM_PC24:
                     case R_ARM_JUMP24:
                     case R_ARM_CALL:
-                        fprintf(outfile, "    arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n", 
-                                reloc_offset, addend, name);
+                        fprintf(outfile, "    arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
+                                reloc_offset, addend, relname);
                         break;
                     default:
                         error("unsupported arm relocation (%d)", type);
@@ -2425,7 +2487,7 @@
             }
 #elif defined(HOST_M68K)
             {
-                char name[256];
+                char relname[256];
                 int type;
                 int addend;
                 int reloc_offset;
@@ -2435,20 +2497,20 @@
 		    rel->r_offset < start_offset + copy_size) {
 		    sym = &(symtab[ELFW(R_SYM)(rel->r_info)]);
                     sym_name = strtab + symtab[ELFW(R_SYM)(rel->r_info)].st_name;
-                    get_reloc_expr(name, sizeof(name), sym_name);
+                    get_reloc_expr(relname, sizeof(relname), sym_name);
                     type = ELF32_R_TYPE(rel->r_info);
                     addend = get32((uint32_t *)(text + rel->r_offset)) + rel->r_addend;
                     reloc_offset = rel->r_offset - start_offset;
                     switch(type) {
                     case R_68K_32:
 		        fprintf(outfile, "    /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n", 
-                                reloc_offset, name, addend );
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
+                                reloc_offset, relname, addend );
                         break;
                     case R_68K_PC32:
 		        fprintf(outfile, "    /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
-                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n", 
-                                reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
+                        fprintf(outfile, "    *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
+                                reloc_offset, relname, reloc_offset, /*sym->st_value+*/ addend);
                         break;
                     default:
                         error("unsupported m68k relocation (%d)", type);
@@ -2456,6 +2518,81 @@
                 }
                 }
             }
+#elif defined(HOST_MIPS) || defined(HOST_MIPS64)
+            {
+                for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
+		    if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
+                        char relname[256];
+                        int type;
+                        int addend;
+                        int reloc_offset;
+
+			sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+                        /* the compiler leave some unnecessary references to the code */
+                        if (sym_name[0] == '\0')
+                            continue;
+                        get_reloc_expr(relname, sizeof(relname), sym_name);
+			type = ELF32_R_TYPE(rel->r_info);
+                        addend = get32((uint32_t *)(text + rel->r_offset));
+                        reloc_offset = rel->r_offset - start_offset;
+			switch (type) {
+			case R_MIPS_26:
+                            fprintf(outfile, "    /* R_MIPS_26 RELOC, offset 0x%x, name %s */\n",
+				    rel->r_offset, sym_name);
+                            fprintf(outfile,
+				    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
+				    "(0x%x & ~0x3fffff) "
+				    "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) "
+				    "   & 0x3fffff);\n",
+                                    reloc_offset, addend, addend, relname, reloc_offset);
+			    break;
+			case R_MIPS_HI16:
+                            fprintf(outfile, "    /* R_MIPS_HI16 RELOC, offset 0x%x, name %s */\n",
+				    rel->r_offset, sym_name);
+                            fprintf(outfile,
+				    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
+				    "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
+				    " & ~0xffff) "
+				    " | (((%s - 0x8000) >> 16) & 0xffff);\n",
+                                    reloc_offset, reloc_offset, relname);
+			    break;
+			case R_MIPS_LO16:
+                            fprintf(outfile, "    /* R_MIPS_LO16 RELOC, offset 0x%x, name %s */\n",
+				    rel->r_offset, sym_name);
+                            fprintf(outfile,
+				    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
+				    "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
+				    " & ~0xffff) "
+				    " | (%s & 0xffff);\n",
+                                    reloc_offset, reloc_offset, relname);
+			    break;
+			case R_MIPS_PC16:
+                            fprintf(outfile, "    /* R_MIPS_PC16 RELOC, offset 0x%x, name %s */\n",
+				    rel->r_offset, sym_name);
+                            fprintf(outfile,
+				    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
+				    "(0x%x & ~0xffff) "
+				    "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) "
+				    "   & 0xffff);\n",
+                                    reloc_offset, addend, addend, relname, reloc_offset);
+			    break;
+			case R_MIPS_GOT16:
+			case R_MIPS_CALL16:
+                            fprintf(outfile, "    /* R_MIPS_GOT16 RELOC, offset 0x%x, name %s */\n",
+				    rel->r_offset, sym_name);
+                            fprintf(outfile,
+				    "    *(uint32_t *)(gen_code_ptr + 0x%x) = "
+				    "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
+				    " & ~0xffff) "
+				    " | (((%s - 0x8000) >> 16) & 0xffff);\n",
+                                    reloc_offset, reloc_offset, relname);
+			    break;
+			default:
+			    error("unsupported MIPS relocation (%d)", type);
+			}
+		    }
+                }
+            }
 #else
 #error unsupported CPU
 #endif
@@ -2515,7 +2652,7 @@
                 gen_code(name, sym->st_value, sym->st_size, outfile, 0);
             }
         }
-        
+
     } else {
         /* generate big code generation switch */
 
@@ -2558,7 +2695,7 @@
    eliminating the neeed to jump around the pool.
 
    We currently generate:
-   
+
    [ For this example we assume merging would move op1_pool out of range.
      In practice we should be able to combine many ops before the offset
      limits are reached. ]
@@ -2645,7 +2782,7 @@
 "    opc_ptr = opc_buf;\n"
 "    opparam_ptr = opparam_buf;\n");
 
-	/* Generate prologue, if needed. */ 
+	/* Generate prologue, if needed. */
 
 fprintf(outfile,
 "    for(;;) {\n");
@@ -2671,7 +2808,7 @@
             name = get_sym_name(sym);
             if (strstart(name, OP_PREFIX, NULL)) {
 #if 0
-                printf("%4d: %s pos=0x%08x len=%d\n", 
+                printf("%4d: %s pos=0x%08x len=%d\n",
                        i, name, sym->st_value, sym->st_size);
 #endif
 #if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
@@ -2713,7 +2850,7 @@
 	    "plt_target, plt_offset);\n    }\n");
 #endif
 
-/* generate some code patching */ 
+/* generate some code patching */
 #ifdef HOST_ARM
 fprintf(outfile,
 "if (arm_data_ptr != arm_data_table + ARM_LDR_TABLE_SIZE)\n"
diff --git a/dyngen.h b/dyngen.h
index 2a87c44..266b9e9 100644
--- a/dyngen.h
+++ b/dyngen.h
@@ -1,6 +1,6 @@
 /*
  * dyngen helpers
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -28,25 +28,11 @@
 #endif
 int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
 
-#ifdef __i386__
+#if defined(__i386__) || defined(__x86_64__) || defined(__s390__)
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
 }
-#endif
-
-#ifdef __x86_64__
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-}
-#endif
-
-#ifdef __s390__
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-}
-#endif
-
-#ifdef __ia64__
+#elif defined(__ia64__)
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
     while (start < stop) {
@@ -55,9 +41,7 @@
     }
     asm volatile (";;sync.i;;srlz.i;;");
 }
-#endif
-
-#ifdef __powerpc__
+#elif defined(__powerpc__)
 
 #define MIN_CACHE_LINE_SIZE 8 /* conservative value */
 
@@ -67,7 +51,7 @@
 
     start &= ~(MIN_CACHE_LINE_SIZE - 1);
     stop = (stop + MIN_CACHE_LINE_SIZE - 1) & ~(MIN_CACHE_LINE_SIZE - 1);
-    
+
     for (p = start; p < stop; p += MIN_CACHE_LINE_SIZE) {
         asm volatile ("dcbst 0,%0" : : "r"(p) : "memory");
     }
@@ -78,17 +62,12 @@
     asm volatile ("sync" : : : "memory");
     asm volatile ("isync" : : : "memory");
 }
-#endif
-
-#ifdef __alpha__
+#elif defined(__alpha__)
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
     asm ("imb");
 }
-#endif
-
-#ifdef __sparc__
-
+#elif defined(__sparc__)
 static void inline flush_icache_range(unsigned long start, unsigned long stop)
 {
 	unsigned long p;
@@ -99,10 +78,7 @@
 	for (; p < stop; p += 8)
 		__asm__ __volatile__("flush\t%0" : : "r" (p));
 }
-
-#endif
-
-#ifdef __arm__
+#elif defined(__arm__)
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
     register unsigned long _beg __asm ("a1") = start;
@@ -110,14 +86,22 @@
     register unsigned long _flg __asm ("a3") = 0;
     __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
 }
-#endif
+#elif defined(__mc68000)
 
-#ifdef __mc68000
-#include <asm/cachectl.h>
+# include <asm/cachectl.h>
 static inline void flush_icache_range(unsigned long start, unsigned long stop)
 {
     cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
 }
+#elif defined(__mips__)
+
+#include <sys/cachectl.h>
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+    _flush_cache ((void *)start, stop - start, BCACHE);
+}
+#else
+#error unsupported CPU
 #endif
 
 #ifdef __alpha__
@@ -164,8 +148,8 @@
 }
 
 static uint8_t *arm_flush_ldr(uint8_t *gen_code_ptr,
-                              LDREntry *ldr_start, LDREntry *ldr_end, 
-                              uint32_t *data_start, uint32_t *data_end, 
+                              LDREntry *ldr_start, LDREntry *ldr_end,
+                              uint32_t *data_start, uint32_t *data_end,
                               int gen_jmp)
 {
     LDREntry *le;
@@ -174,7 +158,7 @@
     uint8_t *data_ptr;
     uint32_t insn;
     uint32_t mask;
- 
+
     data_size = (data_end - data_start) << 2;
 
     if (gen_jmp) {
@@ -185,17 +169,17 @@
         arm_reloc_pc24((uint32_t *)gen_code_ptr, 0xeafffffe, target);
         gen_code_ptr += 4;
     }
-   
+
     /* copy the data */
     data_ptr = gen_code_ptr;
     memcpy(gen_code_ptr, data_start, data_size);
     gen_code_ptr += data_size;
-    
+
     /* patch the ldr to point to the data */
     for(le = ldr_start; le < ldr_end; le++) {
         ptr = (uint32_t *)le->ptr;
-        offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) + 
-            (unsigned long)data_ptr - 
+        offset = ((unsigned long)(le->data_ptr) - (unsigned long)data_start) +
+            (unsigned long)data_ptr -
             (unsigned long)ptr - 8;
         if (offset < 0) {
             fprintf(stderr, "Negative constant pool offset\n");
@@ -248,7 +232,6 @@
 
 #ifdef __ia64
 
-
 /* Patch instruction with "val" where "mask" has 1 bits. */
 static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
 {
@@ -409,7 +392,8 @@
 	0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,	/* nop 0; brl IP */
 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0
     };
-    uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start, *vp;
+    uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start;
+    uint64_t *vp;
     struct ia64_fixup *fixup;
     unsigned int offset = 0;
     struct fdesc {
@@ -446,12 +430,12 @@
     /* First, create the GOT: */
     for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
 	/* first check if we already have this value in the GOT: */
-	for (vp = got_start; vp < gen_code_ptr; ++vp)
-	    if (*(uint64_t *) vp == fixup->value)
+	for (vp = (uint64_t *) got_start; vp < (uint64_t *) gen_code_ptr; ++vp)
+	    if (*vp == fixup->value)
 		break;
-	if (vp == gen_code_ptr) {
+	if (vp == (uint64_t *) gen_code_ptr) {
 	    /* Nope, we need to put the value in the GOT: */
-	    *(uint64_t *) vp = fixup->value;
+	    *vp = fixup->value;
 	    gen_code_ptr += 8;
 	}
 	ia64_imm22(fixup->addr, (long) vp - gp);
diff --git a/elf.h b/elf.h
index 1825d50..0c03f03 100644
--- a/elf.h
+++ b/elf.h
@@ -328,6 +328,9 @@
 #define R_SPARC_11		31
 #define R_SPARC_64		32
 #define R_SPARC_OLO10           33
+#define R_SPARC_HH22            34
+#define R_SPARC_HM10            35
+#define R_SPARC_LM22            36
 #define R_SPARC_WDISP16		40
 #define R_SPARC_WDISP19		41
 #define R_SPARC_7		43
@@ -1042,7 +1045,7 @@
 #define SHN_COMMON	0xfff2
 #define SHN_HIRESERVE	0xffff
 #define SHN_MIPS_ACCOMON	0xff00
- 
+
 typedef struct elf32_shdr {
   Elf32_Word	sh_name;
   Elf32_Word	sh_type;
diff --git a/elf_ops.h b/elf_ops.h
index abcce09..173d12f 100644
--- a/elf_ops.h
+++ b/elf_ops.h
@@ -49,7 +49,7 @@
     bswap16s(&sym->st_shndx);
 }
 
-static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table, 
+static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
                                                int n, int type)
 {
     int i;
@@ -71,17 +71,17 @@
     int nsyms, i;
     char *str = NULL;
 
-    shdr_table = load_at(fd, ehdr->e_shoff, 
+    shdr_table = load_at(fd, ehdr->e_shoff,
                          sizeof(struct elf_shdr) * ehdr->e_shnum);
     if (!shdr_table)
         return -1;
-    
+
     if (must_swab) {
         for (i = 0; i < ehdr->e_shnum; i++) {
             glue(bswap_shdr, SZ)(shdr_table + i);
         }
     }
-        
+
     symtab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_SYMTAB);
     if (!symtab)
         goto fail;
@@ -139,12 +139,14 @@
 }
 
 int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
-                       int must_swab, uint64_t *pentry)
+                       int must_swab, uint64_t *pentry,
+                       uint64_t *lowaddr, uint64_t *highaddr)
 {
     struct elfhdr ehdr;
     struct elf_phdr *phdr = NULL, *ph;
     int size, i, total_size;
-    elf_word mem_size, addr;
+    elf_word mem_size;
+    uint64_t addr, low = 0, high = 0;
     uint8_t *data = NULL;
 
     if (read(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
@@ -174,7 +176,7 @@
             glue(bswap_phdr, SZ)(ph);
         }
     }
-    
+
     total_size = 0;
     for(i = 0; i < ehdr.e_phnum; i++) {
         ph = &phdr[i];
@@ -193,12 +195,20 @@
             cpu_physical_memory_write_rom(addr, data, mem_size);
 
             total_size += mem_size;
+            if (!low || addr < low)
+                low = addr;
+            if (!high || (addr + mem_size) > high)
+                high = addr + mem_size;
 
             qemu_free(data);
             data = NULL;
         }
     }
     qemu_free(phdr);
+    if (lowaddr)
+        *lowaddr = (uint64_t)low;
+    if (highaddr)
+        *highaddr = (uint64_t)high;
     return total_size;
  fail:
     qemu_free(data);
diff --git a/exec-all.h b/exec-all.h
index 82ef3ac..dc5a10d 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -1,6 +1,6 @@
 /*
  * internal execution defines for qemu
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -28,10 +28,23 @@
 #define tostring(s)	#s
 #endif
 
+#ifndef likely
 #if __GNUC__ < 3
 #define __builtin_expect(x, n) (x)
 #endif
 
+#define likely(x)   __builtin_expect(!!(x), 1)
+#define unlikely(x)   __builtin_expect(!!(x), 0)
+#endif
+
+#ifndef always_inline
+#if (__GNUC__ < 3) || defined(__APPLE__)
+#define always_inline inline
+#else
+#define always_inline __attribute__ (( always_inline )) inline
+#endif
+#endif
+
 #ifdef __i386__
 #define REGPARM(n) __attribute((regparm(n)))
 #else
@@ -68,7 +81,7 @@
 typedef void (GenOpFunc1)(long);
 typedef void (GenOpFunc2)(long, long);
 typedef void (GenOpFunc3)(long, long, long);
-                    
+
 #if defined(TARGET_I386)
 
 void optimize_flags_init(void);
@@ -78,32 +91,35 @@
 extern FILE *logfile;
 extern int loglevel;
 
+void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b);
+void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b);
+
 int gen_intermediate_code(CPUState *env, struct TranslationBlock *tb);
 int gen_intermediate_code_pc(CPUState *env, struct TranslationBlock *tb);
 void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf);
 int cpu_gen_code(CPUState *env, struct TranslationBlock *tb,
                  int max_code_size, int *gen_code_size_ptr);
-int cpu_restore_state(struct TranslationBlock *tb, 
+int cpu_restore_state(struct TranslationBlock *tb,
                       CPUState *env, unsigned long searched_pc,
                       void *puc);
 int cpu_gen_code_copy(CPUState *env, struct TranslationBlock *tb,
                       int max_code_size, int *gen_code_size_ptr);
-int cpu_restore_state_copy(struct TranslationBlock *tb, 
+int cpu_restore_state_copy(struct TranslationBlock *tb,
                            CPUState *env, unsigned long searched_pc,
                            void *puc);
 void cpu_resume_from_signal(CPUState *env1, void *puc);
 void cpu_exec_init(CPUState *env);
 int page_unprotect(target_ulong address, unsigned long pc, void *puc);
-void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, 
+void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
                                    int is_cpu_write_access);
 void tb_invalidate_page_range(target_ulong start, target_ulong end);
 void tlb_flush_page(CPUState *env, target_ulong addr);
 void tlb_flush(CPUState *env, int flush_global);
-int tlb_set_page_exec(CPUState *env, target_ulong vaddr, 
-                      target_phys_addr_t paddr, int prot, 
+int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
+                      target_phys_addr_t paddr, int prot,
                       int is_user, int is_softmmu);
-static inline int tlb_set_page(CPUState *env, target_ulong vaddr, 
-                               target_phys_addr_t paddr, int prot, 
+static inline int tlb_set_page(CPUState *env, target_ulong vaddr,
+                               target_phys_addr_t paddr, int prot,
                                int is_user, int is_softmmu)
 {
     if (prot & PAGE_READ)
@@ -153,7 +169,7 @@
 
 #define CODE_GEN_MAX_BLOCKS    (CODE_GEN_BUFFER_SIZE / CODE_GEN_AVG_BLOCK_SIZE)
 
-#if defined(__powerpc__) 
+#if defined(__powerpc__)
 #define USE_DIRECT_JUMP
 #endif
 #if defined(__i386__) && !defined(_WIN32)
@@ -163,7 +179,7 @@
 typedef struct TranslationBlock {
     target_ulong pc;   /* simulated PC corresponding to this block (EIP + CS base) */
     target_ulong cs_base; /* CS base for this block */
-    unsigned int flags; /* flags defining in which context the code was generated */
+    uint64_t flags; /* flags defining in which context the code was generated */
     uint16_t size;      /* size of target code for this block (1 <=
                            size <= TARGET_PAGE_SIZE) */
     uint16_t cflags;    /* compile flags */
@@ -174,11 +190,11 @@
 
     uint8_t *tc_ptr;    /* pointer to the translated code */
     /* next matching tb for physical address. */
-    struct TranslationBlock *phys_hash_next; 
+    struct TranslationBlock *phys_hash_next;
     /* first and second physical page containing code. The lower bit
        of the pointer tells the index in page_next[] */
-    struct TranslationBlock *page_next[2]; 
-    target_ulong page_addr[2]; 
+    struct TranslationBlock *page_next[2];
+    target_ulong page_addr[2];
 
     /* the following data are used to directly call another TB from
        the code of this one. */
@@ -192,7 +208,7 @@
        the two least significant bits of the pointers to tell what is
        the next pointer: 0 = jmp_next[0], 1 = jmp_next[1], 2 =
        jmp_first */
-    struct TranslationBlock *jmp_next[2]; 
+    struct TranslationBlock *jmp_next[2];
     struct TranslationBlock *jmp_first;
 } TranslationBlock;
 
@@ -218,7 +234,7 @@
 
 TranslationBlock *tb_alloc(target_ulong pc);
 void tb_flush(CPUState *env);
-void tb_link_phys(TranslationBlock *tb, 
+void tb_link_phys(TranslationBlock *tb,
                   target_ulong phys_pc, target_ulong phys_page2);
 
 extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
@@ -254,7 +270,7 @@
 }
 #endif
 
-static inline void tb_set_jmp_target(TranslationBlock *tb, 
+static inline void tb_set_jmp_target(TranslationBlock *tb,
                                      int n, unsigned long addr)
 {
     unsigned long offset;
@@ -269,7 +285,7 @@
 #else
 
 /* set the jump target */
-static inline void tb_set_jmp_target(TranslationBlock *tb, 
+static inline void tb_set_jmp_target(TranslationBlock *tb,
                                      int n, unsigned long addr)
 {
     tb->tb_next[n] = addr;
@@ -277,14 +293,14 @@
 
 #endif
 
-static inline void tb_add_jump(TranslationBlock *tb, int n, 
+static inline void tb_add_jump(TranslationBlock *tb, int n,
                                TranslationBlock *tb_next)
 {
     /* NOTE: this test is only needed for thread safety */
     if (!tb->jmp_next[n]) {
         /* patch the native jump address */
         tb_set_jmp_target(tb, n, (unsigned long)tb_next->tc_ptr);
-        
+
         /* add in TB jmp circular list */
         tb->jmp_next[n] = tb_next->jmp_first;
         tb_next->jmp_first = (TranslationBlock *)((long)(tb) | (n));
@@ -337,14 +353,32 @@
 		  "1:\n");\
 } while (0)
 
+#elif defined(__s390__)
+/* GCC spills R13, so we have to restore it before branching away */
+
+#define GOTO_TB(opname, tbparam, n)\
+do {\
+    static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\
+    static void __attribute__((used)) *__op_label ## n \
+        __asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\
+	__asm__ __volatile__ ( \
+		"l %%r13,52(%%r15)\n" \
+		"br %0\n" \
+	: : "r" (((TranslationBlock*)tbparam)->tb_next[n]));\
+	\
+	for(;*((int*)0);); /* just to keep GCC busy */ \
+label ## n: ;\
+dummy_label ## n: ;\
+} while(0)
+
 #else
 
 /* jump to next block operations (more portable code, does not need
    cache flushing, but slower because of indirect jump) */
 #define GOTO_TB(opname, tbparam, n)\
 do {\
-    static void __attribute__((unused)) *dummy ## n = &&dummy_label ## n;\
-    static void __attribute__((unused)) *__op_label ## n \
+    static void __attribute__((used)) *dummy ## n = &&dummy_label ## n;\
+    static void __attribute__((used)) *__op_label ## n \
         __asm__(ASM_OP_LABEL_NAME(n, opname)) = &&label ## n;\
     goto *(void *)(((TranslationBlock *)tbparam)->tb_next[n]);\
 label ## n: ;\
@@ -357,7 +391,7 @@
 extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
 extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 
-#ifdef __powerpc__
+#if defined(__powerpc__)
 static inline int testandset (int *p)
 {
     int ret;
@@ -373,35 +407,29 @@
                           : "cr0", "memory");
     return ret;
 }
-#endif
-
-#ifdef __i386__
+#elif defined(__i386__)
 static inline int testandset (int *p)
 {
     long int readval = 0;
-    
+
     __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
                           : "+m" (*p), "+a" (readval)
                           : "r" (1)
                           : "cc");
     return readval;
 }
-#endif
-
-#ifdef __x86_64__
+#elif defined(__x86_64__)
 static inline int testandset (int *p)
 {
     long int readval = 0;
-    
+
     __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
                           : "+m" (*p), "+a" (readval)
                           : "r" (1)
                           : "cc");
     return readval;
 }
-#endif
-
-#ifdef __s390__
+#elif defined(__s390__)
 static inline int testandset (int *p)
 {
     int ret;
@@ -409,13 +437,11 @@
     __asm__ __volatile__ ("0: cs    %0,%1,0(%2)\n"
 			  "   jl    0b"
 			  : "=&d" (ret)
-			  : "r" (1), "a" (p), "0" (*p) 
+			  : "r" (1), "a" (p), "0" (*p)
 			  : "cc", "memory" );
     return ret;
 }
-#endif
-
-#ifdef __alpha__
+#elif defined(__alpha__)
 static inline int testandset (int *p)
 {
     int ret;
@@ -432,9 +458,7 @@
 			  : "m" (*p));
     return ret;
 }
-#endif
-
-#ifdef __sparc__
+#elif defined(__sparc__)
 static inline int testandset (int *p)
 {
 	int ret;
@@ -446,21 +470,17 @@
 
 	return (ret ? 1 : 0);
 }
-#endif
-
-#ifdef __arm__
+#elif defined(__arm__)
 static inline int testandset (int *spinlock)
 {
     register unsigned int ret;
     __asm__ __volatile__("swp %0, %1, [%2]"
                          : "=r"(ret)
                          : "0"(1), "r"(spinlock));
-    
+
     return ret;
 }
-#endif
-
-#ifdef __mc68000
+#elif defined(__mc68000)
 static inline int testandset (int *p)
 {
     char ret;
@@ -470,15 +490,36 @@
                          : "cc","memory");
     return ret;
 }
-#endif
+#elif defined(__ia64)
 
-#ifdef __ia64
 #include <ia64intrin.h>
 
 static inline int testandset (int *p)
 {
     return __sync_lock_test_and_set (p, 1);
 }
+#elif defined(__mips__)
+static inline int testandset (int *p)
+{
+    int ret;
+
+    __asm__ __volatile__ (
+	"	.set push		\n"
+	"	.set noat		\n"
+	"	.set mips2		\n"
+	"1:	li	$1, 1		\n"
+	"	ll	%0, %1		\n"
+	"	sc	$1, %1		\n"
+	"	beqz	$1, 1b		\n"
+	"	.set pop		"
+	: "=r" (ret), "+R" (*p)
+	:
+	: "memory");
+
+    return ret;
+}
+#else
+#error unimplemented CPU support
 #endif
 
 typedef int spinlock_t;
@@ -521,7 +562,7 @@
 
 #if !defined(CONFIG_USER_ONLY)
 
-void tlb_fill(target_ulong addr, int is_write, int is_user, 
+void tlb_fill(target_ulong addr, int is_write, int is_user,
               void *retaddr);
 
 #define ACCESS_TYPE 3
@@ -572,22 +613,29 @@
     is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
 #elif defined (TARGET_SH4)
     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
-    if (__builtin_expect(env->tlb_table[is_user][index].addr_code != 
+    if (__builtin_expect(env->tlb_table[is_user][index].addr_code !=
                          (addr & TARGET_PAGE_MASK), 0)) {
         ldub_code(addr);
     }
     pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
     if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
-        cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
+#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;
 }
 #endif
 
-
 #ifdef USE_KQEMU
 #define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
 
@@ -603,11 +651,11 @@
 static inline int kqemu_is_ok(CPUState *env)
 {
     return(env->kqemu_enabled &&
-           (env->cr[0] & CR0_PE_MASK) && 
+           (env->cr[0] & CR0_PE_MASK) &&
            !(env->hflags & HF_INHIBIT_IRQ_MASK) &&
            (env->eflags & IF_MASK) &&
            !(env->eflags & VM_MASK) &&
-           (env->kqemu_enabled == 2 || 
+           (env->kqemu_enabled == 2 ||
             ((env->hflags & HF_CPL_MASK) == 3 &&
              (env->eflags & IOPL_MASK) != IOPL_MASK)));
 }
diff --git a/exec.c b/exec.c
index 21764bc..3e588d5 100644
--- a/exec.c
+++ b/exec.c
@@ -1,6 +1,6 @@
 /*
  *  virtual page mapping and translated block handling
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -47,8 +47,11 @@
 //#define DEBUG_UNASSIGNED
 
 /* make various TB consistency checks */
-//#define DEBUG_TB_CHECK 
-//#define DEBUG_TLB_CHECK 
+//#define DEBUG_TB_CHECK
+//#define DEBUG_TLB_CHECK
+
+//#define DEBUG_IOPORT
+//#define DEBUG_SUBPAGE
 
 #if !defined(CONFIG_USER_ONLY)
 /* TB consistency checks only implemented for usermode emulation.  */
@@ -65,6 +68,11 @@
 
 #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
 #elif defined(TARGET_PPC64)
 #define TARGET_PHYS_ADDR_SPACE_BITS 42
 #elif USE_KQEMU
@@ -96,11 +104,12 @@
 uint8_t *phys_ram_dirty;
 uint8_t *bios_mem;
 static int in_migration;
+static ram_addr_t phys_ram_alloc_offset = 0;
 
 CPUState *first_cpu;
 /* current CPU in the current thread. It is only valid inside
    cpu_exec() */
-CPUState *cpu_single_env; 
+CPUState *cpu_single_env;
 
 typedef struct PageDesc {
     /* list of TBs intersecting this ram page */
@@ -120,7 +129,15 @@
 } PhysPageDesc;
 
 #define L2_BITS 10
+#if defined(CONFIG_USER_ONLY) && defined(TARGET_VIRT_ADDR_SPACE_BITS)
+/* XXX: this is a temporary hack for alpha target.
+ *      In the future, this is to be replaced by a multi-level table
+ *      to actually be able to handle the complete 64 bits address space.
+ */
+#define L1_BITS (TARGET_VIRT_ADDR_SPACE_BITS - L2_BITS - TARGET_PAGE_BITS)
+#else
 #define L1_BITS (32 - L2_BITS - TARGET_PAGE_BITS)
+#endif
 
 #define L1_SIZE (1 << L1_BITS)
 #define L2_SIZE (1 << L2_BITS)
@@ -141,17 +158,29 @@
 CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
 void *io_mem_opaque[IO_MEM_NB_ENTRIES];
 static int io_mem_nb;
+#if defined(CONFIG_SOFTMMU)
+static int io_mem_watch;
+#endif
 
 /* log support */
 char *logfilename = "/tmp/qemu.log";
 FILE *logfile;
 int loglevel;
+static int log_append = 0;
 
 /* statistics */
 static int tlb_flush_count;
 static int tb_flush_count;
 static int tb_phys_invalidate_count;
 
+#define SUBPAGE_IDX(addr) ((addr) & ~TARGET_PAGE_MASK)
+typedef struct subpage_t {
+    target_phys_addr_t base;
+    CPUReadMemoryFunc **mem_read[TARGET_PAGE_SIZE];
+    CPUWriteMemoryFunc **mem_write[TARGET_PAGE_SIZE];
+    void *opaque[TARGET_PAGE_SIZE];
+} subpage_t;
+
 static void page_init(void)
 {
     /* NOTE: we can always suppose that qemu_host_page_size >=
@@ -160,10 +189,10 @@
     {
         SYSTEM_INFO system_info;
         DWORD old_protect;
-        
+
         GetSystemInfo(&system_info);
         qemu_real_host_page_size = system_info.dwPageSize;
-        
+
         VirtualProtect(code_gen_buffer, sizeof(code_gen_buffer),
                        PAGE_EXECUTE_READWRITE, &old_protect);
     }
@@ -174,12 +203,12 @@
 
         start = (unsigned long)code_gen_buffer;
         start &= ~(qemu_real_host_page_size - 1);
-        
+
         end = (unsigned long)code_gen_buffer + sizeof(code_gen_buffer);
         end += qemu_real_host_page_size - 1;
         end &= ~(qemu_real_host_page_size - 1);
-        
-        mprotect((void *)start, end - start, 
+
+        mprotect((void *)start, end - start,
                  PROT_READ | PROT_WRITE | PROT_EXEC);
     }
 #endif
@@ -265,7 +294,7 @@
 
 #if !defined(CONFIG_USER_ONLY)
 static void tlb_protect_code(ram_addr_t ram_addr);
-static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, 
+static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
                                     target_ulong vaddr);
 #endif
 
@@ -287,6 +316,7 @@
         cpu_index++;
     }
     env->cpu_index = cpu_index;
+    env->nb_watchpoints = 0;
     *penv = env;
 }
 
@@ -323,13 +353,13 @@
 {
     CPUState *env;
 #if defined(DEBUG_FLUSH)
-    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", 
-           code_gen_ptr - code_gen_buffer, 
-           nb_tbs, 
+    printf("qemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n",
+           code_gen_ptr - code_gen_buffer,
+           nb_tbs,
            nb_tbs > 0 ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0);
 #endif
     nb_tbs = 0;
-    
+
     for(env = first_cpu; env != NULL; env = env->next_cpu) {
         memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
     }
@@ -345,7 +375,7 @@
 
 #ifdef DEBUG_TB_CHECK
 
-static void tb_invalidate_check(unsigned long address)
+static void tb_invalidate_check(target_ulong address)
 {
     TranslationBlock *tb;
     int i;
@@ -366,7 +396,7 @@
 {
     TranslationBlock *tb;
     int i, flags1, flags2;
-    
+
     for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
         for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
             flags1 = page_get_flags(tb->pc);
@@ -475,11 +505,11 @@
     unsigned int h, n1;
     target_ulong phys_pc;
     TranslationBlock *tb1, *tb2;
-    
+
     /* remove the TB from the hash list */
     phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
     h = tb_phys_hash_func(phys_pc);
-    tb_remove(&tb_phys_hash[h], tb, 
+    tb_remove(&tb_phys_hash[h], tb,
               offsetof(TranslationBlock, phys_hash_next));
 
     /* remove the TB from the page list */
@@ -555,7 +585,7 @@
 {
     int n, tb_start, tb_end;
     TranslationBlock *tb;
-    
+
     p->code_bitmap = qemu_malloc(TARGET_PAGE_SIZE / 8);
     if (!p->code_bitmap)
         return;
@@ -584,7 +614,7 @@
 
 #ifdef TARGET_HAS_PRECISE_SMC
 
-static void tb_gen_code(CPUState *env, 
+static void tb_gen_code(CPUState *env,
                         target_ulong pc, target_ulong cs_base, int flags,
                         int cflags)
 {
@@ -608,7 +638,7 @@
     tb->cflags = cflags;
     cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
-    
+
     /* check next page if needed */
     virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
     phys_page2 = -1;
@@ -618,13 +648,13 @@
     tb_link_phys(tb, phys_pc, phys_page2);
 }
 #endif
-    
+
 /* invalidate all TBs which intersect with the target physical page
    starting in range [start;end[. NOTE: start and end must refer to
    the same physical page. 'is_cpu_write_access' should be true if called
    from a real cpu write access: the virtual CPU will exit the current
    TB if code is modified inside this TB. */
-void tb_invalidate_phys_page_range(target_ulong start, target_ulong end, 
+void tb_invalidate_phys_page_range(target_ulong start, target_ulong end,
                                    int is_cpu_write_access)
 {
     int n, current_tb_modified, current_tb_not_found, current_flags;
@@ -635,9 +665,9 @@
     target_ulong current_pc, current_cs_base;
 
     p = page_find(start >> TARGET_PAGE_BITS);
-    if (!p) 
+    if (!p)
         return;
-    if (!p->code_bitmap && 
+    if (!p->code_bitmap &&
         ++p->code_write_count >= SMC_BITMAP_USE_THRESHOLD &&
         is_cpu_write_access) {
         /* build code bitmap */
@@ -684,9 +714,9 @@
                 that the modification is after the current PC, but it
                 would require a specialized function to partially
                 restore the CPU state */
-                
+
                 current_tb_modified = 1;
-                cpu_restore_state(current_tb, env, 
+                cpu_restore_state(current_tb, env,
                                   env->mem_write_pc, NULL);
 #if defined(TARGET_I386)
                 current_flags = env->hflags;
@@ -729,7 +759,7 @@
            modifying the memory. It will ensure that it cannot modify
            itself */
         env->current_tb = NULL;
-        tb_gen_code(env, current_pc, current_cs_base, current_flags, 
+        tb_gen_code(env, current_pc, current_cs_base, current_flags,
                     CF_SINGLE_INSN);
         cpu_resume_from_signal(env, NULL);
     }
@@ -744,15 +774,15 @@
 #if 0
     if (1) {
         if (loglevel) {
-            fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n", 
-                   cpu_single_env->mem_write_vaddr, len, 
-                   cpu_single_env->eip, 
+            fprintf(logfile, "modifying code at 0x%x size=%d EIP=%x PC=%08x\n",
+                   cpu_single_env->mem_write_vaddr, len,
+                   cpu_single_env->eip,
                    cpu_single_env->eip + (long)cpu_single_env->segs[R_CS].base);
         }
     }
 #endif
     p = page_find(start >> TARGET_PAGE_BITS);
-    if (!p) 
+    if (!p)
         return;
     if (p->code_bitmap) {
         offset = start & ~TARGET_PAGE_MASK;
@@ -766,7 +796,7 @@
 }
 
 #if !defined(CONFIG_SOFTMMU)
-static void tb_invalidate_phys_page(target_ulong addr, 
+static void tb_invalidate_phys_page(target_ulong addr,
                                     unsigned long pc, void *puc)
 {
     int n, current_flags, current_tb_modified;
@@ -779,7 +809,7 @@
 
     addr &= TARGET_PAGE_MASK;
     p = page_find(addr >> TARGET_PAGE_BITS);
-    if (!p) 
+    if (!p)
         return;
     tb = p->first_tb;
     current_tb_modified = 0;
@@ -803,7 +833,7 @@
                    that the modification is after the current PC, but it
                    would require a specialized function to partially
                    restore the CPU state */
-            
+
             current_tb_modified = 1;
             cpu_restore_state(current_tb, env, pc, puc);
 #if defined(TARGET_I386)
@@ -826,7 +856,7 @@
            modifying the memory. It will ensure that it cannot modify
            itself */
         env->current_tb = NULL;
-        tb_gen_code(env, current_pc, current_cs_base, current_flags, 
+        tb_gen_code(env, current_pc, current_cs_base, current_flags,
                     CF_SINGLE_INSN);
         cpu_resume_from_signal(env, puc);
     }
@@ -835,7 +865,7 @@
 #endif
 
 /* add the tb in the target page and protect it if necessary */
-static inline void tb_alloc_page(TranslationBlock *tb, 
+static inline void tb_alloc_page(TranslationBlock *tb,
                                  unsigned int n, target_ulong page_addr)
 {
     PageDesc *p;
@@ -870,10 +900,10 @@
             p2->flags &= ~PAGE_WRITE;
             page_get_flags(addr);
           }
-        mprotect(g2h(page_addr), qemu_host_page_size, 
+        mprotect(g2h(page_addr), qemu_host_page_size,
                  (prot & PAGE_BITS) & ~PAGE_WRITE);
 #ifdef DEBUG_TB_INVALIDATE
-        printf("protecting code page: 0x%08lx\n", 
+        printf("protecting code page: 0x%08lx\n",
                page_addr);
 #endif
     }
@@ -895,7 +925,7 @@
 {
     TranslationBlock *tb;
 
-    if (nb_tbs >= CODE_GEN_MAX_BLOCKS || 
+    if (nb_tbs >= CODE_GEN_MAX_BLOCKS ||
         (code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE)
         return NULL;
     tb = &tbs[nb_tbs++];
@@ -906,7 +936,7 @@
 
 /* add a new TB and link it to the physical page tables. phys_page2 is
    (-1) to indicate that only one page contains the TB. */
-void tb_link_phys(TranslationBlock *tb, 
+void tb_link_phys(TranslationBlock *tb,
                   target_ulong phys_pc, target_ulong phys_page2)
 {
     unsigned int h;
@@ -972,7 +1002,7 @@
         } else {
             m_min = m + 1;
         }
-    } 
+    }
     return &tbs[m_max];
 }
 
@@ -1008,7 +1038,7 @@
         }
         *ptb = tb->jmp_next[n];
         tb->jmp_next[n] = NULL;
-        
+
         /* suppress the jump to next tb in generated code */
         tb_reset_jump(tb, n);
 
@@ -1026,7 +1056,8 @@
 #if defined(TARGET_HAS_ICE)
 static void breakpoint_invalidate(CPUState *env, target_ulong pc)
 {
-    target_ulong addr, pd;
+    target_phys_addr_t addr;
+    target_ulong pd;
     ram_addr_t ram_addr;
     PhysPageDesc *p;
 
@@ -1042,13 +1073,51 @@
 }
 #endif
 
+/* Add a watchpoint.  */
+int  cpu_watchpoint_insert(CPUState *env, target_ulong addr)
+{
+    int i;
+
+    for (i = 0; i < env->nb_watchpoints; i++) {
+        if (addr == env->watchpoint[i].vaddr)
+            return 0;
+    }
+    if (env->nb_watchpoints >= MAX_WATCHPOINTS)
+        return -1;
+
+    i = env->nb_watchpoints++;
+    env->watchpoint[i].vaddr = addr;
+    tlb_flush_page(env, addr);
+    /* FIXME: This flush is needed because of the hack to make memory ops
+       terminate the TB.  It can be removed once the proper IO trap and
+       re-execute bits are in.  */
+    tb_flush(env);
+    return i;
+}
+
+/* Remove a watchpoint.  */
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
+{
+    int i;
+
+    for (i = 0; i < env->nb_watchpoints; i++) {
+        if (addr == env->watchpoint[i].vaddr) {
+            env->nb_watchpoints--;
+            env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
+            tlb_flush_page(env, addr);
+            return 0;
+        }
+    }
+    return -1;
+}
+
 /* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
    breakpoint is reached */
 int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
 {
 #if defined(TARGET_HAS_ICE)
     int i;
-    
+
     for(i = 0; i < env->nb_breakpoints; i++) {
         if (env->breakpoints[i] == pc)
             return 0;
@@ -1062,7 +1131,7 @@
     if (kvm_allowed)
 	kvm_update_debugger(env);
 #endif
-    
+
     breakpoint_invalidate(env, pc);
     return 0;
 #else
@@ -1120,7 +1189,7 @@
 {
     loglevel = log_flags;
     if (loglevel && !logfile) {
-        logfile = fopen(logfilename, "w");
+        logfile = fopen(logfilename, log_append ? "a" : "w");
         if (!logfile) {
             perror(logfilename);
             _exit(1);
@@ -1134,12 +1203,22 @@
 #else
         setvbuf(logfile, NULL, _IOLBF, 0);
 #endif
+        log_append = 1;
+    }
+    if (!loglevel && logfile) {
+        fclose(logfile);
+        logfile = NULL;
     }
 }
 
 void cpu_set_log_filename(const char *filename)
 {
     logfilename = strdup(filename);
+    if (logfile) {
+        fclose(logfile);
+        logfile = NULL;
+    }
+    cpu_set_log(loglevel);
 }
 
 /* mask must never be zero, except for A20 change call */
@@ -1169,11 +1248,11 @@
 }
 
 CPULogItem cpu_log_items[] = {
-    { CPU_LOG_TB_OUT_ASM, "out_asm", 
+    { CPU_LOG_TB_OUT_ASM, "out_asm",
       "show generated host assembly code for each compiled TB" },
     { CPU_LOG_TB_IN_ASM, "in_asm",
       "show target assembly code for each compiled TB" },
-    { CPU_LOG_TB_OP, "op", 
+    { CPU_LOG_TB_OP, "op",
       "show micro ops for each compiled TB (only usable if 'in_asm' used)" },
 #ifdef TARGET_I386
     { CPU_LOG_TB_OP_OPT, "op_opt",
@@ -1184,7 +1263,7 @@
     { CPU_LOG_EXEC, "exec",
       "show trace before each executed TB (lots of logs)" },
     { CPU_LOG_TB_CPU, "cpu",
-      "show CPU state before bloc translation" },
+      "show CPU state before block translation" },
 #ifdef TARGET_I386
     { CPU_LOG_PCALL, "pcall",
       "show protected mode far calls/returns/exceptions" },
@@ -1202,7 +1281,7 @@
         return 0;
     return memcmp(s1, s2, n) == 0;
 }
-      
+
 /* takes a comma separated list of log masks. Return 0 if error. */
 int cpu_str_to_log_mask(const char *str)
 {
@@ -1245,14 +1324,43 @@
     vfprintf(stderr, fmt, ap);
     fprintf(stderr, "\n");
 #ifdef TARGET_I386
+    if(env->intercept & INTERCEPT_SVM_MASK) {
+	/* most probably the virtual machine should not
+	   be shut down but rather caught by the VMM */
+        vmexit(SVM_EXIT_SHUTDOWN, 0);
+    }
     cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
 #else
     cpu_dump_state(env, stderr, fprintf, 0);
 #endif
+    if (logfile) {
+        fprintf(logfile, "qemu: fatal: ");
+        vfprintf(logfile, fmt, ap);
+        fprintf(logfile, "\n");
+#ifdef TARGET_I386
+        cpu_dump_state(env, logfile, fprintf, X86_DUMP_FPU | X86_DUMP_CCOP);
+#else
+        cpu_dump_state(env, logfile, fprintf, 0);
+#endif
+        fflush(logfile);
+        fclose(logfile);
+    }
     va_end(ap);
     abort();
 }
 
+CPUState *cpu_copy(CPUState *env)
+{
+    CPUState *new_env = cpu_init();
+    /* preserve chaining and index */
+    CPUState *next_cpu = new_env->next_cpu;
+    int cpu_index = new_env->cpu_index;
+    memcpy(new_env, env, sizeof(CPUState));
+    new_env->next_cpu = next_cpu;
+    new_env->cpu_index = cpu_index;
+    return new_env;
+}
+
 #if !defined(CONFIG_USER_ONLY)
 
 /* NOTE: if flush_global is true, also flush global entries (not
@@ -1275,6 +1383,16 @@
         env->tlb_table[1][i].addr_read = -1;
         env->tlb_table[1][i].addr_write = -1;
         env->tlb_table[1][i].addr_code = -1;
+#if (NB_MMU_MODES >= 3)
+        env->tlb_table[2][i].addr_read = -1;
+        env->tlb_table[2][i].addr_write = -1;
+        env->tlb_table[2][i].addr_code = -1;
+#if (NB_MMU_MODES == 4)
+        env->tlb_table[3][i].addr_read = -1;
+        env->tlb_table[3][i].addr_write = -1;
+        env->tlb_table[3][i].addr_code = -1;
+#endif
+#endif
     }
 
     memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
@@ -1292,11 +1410,11 @@
 
 static inline void tlb_flush_entry(CPUTLBEntry *tlb_entry, target_ulong addr)
 {
-    if (addr == (tlb_entry->addr_read & 
+    if (addr == (tlb_entry->addr_read &
                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
-        addr == (tlb_entry->addr_write & 
+        addr == (tlb_entry->addr_write &
                  (TARGET_PAGE_MASK | TLB_INVALID_MASK)) ||
-        addr == (tlb_entry->addr_code & 
+        addr == (tlb_entry->addr_code &
                  (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
         tlb_entry->addr_read = -1;
         tlb_entry->addr_write = -1;
@@ -1320,6 +1438,12 @@
     i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     tlb_flush_entry(&env->tlb_table[0][i], addr);
     tlb_flush_entry(&env->tlb_table[1][i], addr);
+#if (NB_MMU_MODES >= 3)
+    tlb_flush_entry(&env->tlb_table[2][i], addr);
+#if (NB_MMU_MODES == 4)
+    tlb_flush_entry(&env->tlb_table[3][i], addr);
+#endif
+#endif
 
     /* Discard jump cache entries for any tb which might potentially
        overlap the flushed page.  */
@@ -1344,20 +1468,20 @@
    can be detected */
 static void tlb_protect_code(ram_addr_t ram_addr)
 {
-    cpu_physical_memory_reset_dirty(ram_addr, 
+    cpu_physical_memory_reset_dirty(ram_addr,
                                     ram_addr + TARGET_PAGE_SIZE,
                                     CODE_DIRTY_FLAG);
 }
 
 /* update the TLB so that writes in physical page 'phys_addr' are no longer
    tested for self modifying code */
-static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr, 
+static void tlb_unprotect_code_phys(CPUState *env, ram_addr_t ram_addr,
                                     target_ulong vaddr)
 {
     phys_ram_dirty[ram_addr >> TARGET_PAGE_BITS] |= CODE_DIRTY_FLAG;
 }
 
-static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry, 
+static inline void tlb_reset_dirty_range(CPUTLBEntry *tlb_entry,
                                          unsigned long start, unsigned long length)
 {
     unsigned long addr;
@@ -1409,6 +1533,14 @@
             tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
         for(i = 0; i < CPU_TLB_SIZE; i++)
             tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
+#if (NB_MMU_MODES >= 3)
+        for(i = 0; i < CPU_TLB_SIZE; i++)
+            tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
+#if (NB_MMU_MODES == 4)
+        for(i = 0; i < CPU_TLB_SIZE; i++)
+            tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
+#endif
+#endif
     }
 
 #if !defined(CONFIG_SOFTMMU)
@@ -1427,7 +1559,7 @@
                         p->phys_addr >= start && p->phys_addr < end &&
                         (p->prot & PROT_WRITE)) {
                         if (addr < MMAP_AREA_END) {
-                            mprotect((void *)addr, TARGET_PAGE_SIZE, 
+                            mprotect((void *)addr, TARGET_PAGE_SIZE,
                                      p->prot & ~PROT_WRITE);
                         }
                     }
@@ -1461,7 +1593,7 @@
     ram_addr_t ram_addr;
 
     if ((tlb_entry->addr_write & ~TARGET_PAGE_MASK) == IO_MEM_RAM) {
-        ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) + 
+        ram_addr = (tlb_entry->addr_write & TARGET_PAGE_MASK) +
             tlb_entry->addend - (unsigned long)phys_ram_base;
         if (!cpu_physical_memory_is_dirty(ram_addr)) {
             tlb_entry->addr_write |= IO_MEM_NOTDIRTY;
@@ -1477,9 +1609,17 @@
         tlb_update_dirty(&env->tlb_table[0][i]);
     for(i = 0; i < CPU_TLB_SIZE; i++)
         tlb_update_dirty(&env->tlb_table[1][i]);
+#if (NB_MMU_MODES >= 3)
+    for(i = 0; i < CPU_TLB_SIZE; i++)
+        tlb_update_dirty(&env->tlb_table[2][i]);
+#if (NB_MMU_MODES == 4)
+    for(i = 0; i < CPU_TLB_SIZE; i++)
+        tlb_update_dirty(&env->tlb_table[3][i]);
+#endif
+#endif
 }
 
-static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry, 
+static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
                                   unsigned long start)
 {
     unsigned long addr;
@@ -1502,14 +1642,20 @@
     i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     tlb_set_dirty1(&env->tlb_table[0][i], addr);
     tlb_set_dirty1(&env->tlb_table[1][i], addr);
+#if (NB_MMU_MODES >= 3)
+    tlb_set_dirty1(&env->tlb_table[2][i], addr);
+#if (NB_MMU_MODES == 4)
+    tlb_set_dirty1(&env->tlb_table[3][i], addr);
+#endif
+#endif
 }
 
 /* add a new TLB entry. At most one entry for a given virtual address
    is permitted. Return 0 if OK or 2 if the page could not be mapped
    (can only happen in non SOFTMMU mode for I/O pages or pages
    conflicting with the host address space). */
-int tlb_set_page_exec(CPUState *env, target_ulong vaddr, 
-                      target_phys_addr_t paddr, int prot, 
+int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
+                      target_phys_addr_t paddr, int prot,
                       int is_user, int is_softmmu)
 {
     PhysPageDesc *p;
@@ -1519,6 +1665,7 @@
     target_phys_addr_t addend;
     int ret;
     CPUTLBEntry *te;
+    int i;
 
     p = phys_page_find(paddr >> TARGET_PAGE_BITS);
     if (!p) {
@@ -1533,7 +1680,7 @@
 
     ret = 0;
 #if !defined(CONFIG_SOFTMMU)
-    if (is_softmmu) 
+    if (is_softmmu)
 #endif
     {
         if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
@@ -1545,7 +1692,24 @@
             address = vaddr;
             addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
         }
-        
+
+        /* Make accesses to pages with watchpoints go via the
+           watchpoint trap routines.  */
+        for (i = 0; i < env->nb_watchpoints; i++) {
+            if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
+                if (address & ~TARGET_PAGE_MASK) {
+                    env->watchpoint[i].addend = 0;
+                    address = vaddr | io_mem_watch;
+                } else {
+                    env->watchpoint[i].addend = pd - paddr +
+                        (unsigned long) phys_ram_base;
+                    /* TODO: Figure out how to make read watchpoints coexist
+                       with code.  */
+                    pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
+                }
+            }
+        }
+
         index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
         addend -= vaddr;
         te = &env->tlb_table[is_user][index];
@@ -1561,12 +1725,12 @@
             te->addr_code = -1;
         }
         if (prot & PAGE_WRITE) {
-            if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || 
+            if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
                 (pd & IO_MEM_ROMD)) {
                 /* write access calls the I/O callback */
-                te->addr_write = vaddr | 
+                te->addr_write = vaddr |
                     (pd & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
-            } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 
+            } else if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
                        !cpu_physical_memory_is_dirty(pd)) {
                 te->addr_write = vaddr | IO_MEM_NOTDIRTY;
             } else {
@@ -1590,17 +1754,17 @@
                 ret = 2;
             } else {
                 if (prot & PROT_WRITE) {
-                    if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM || 
+                    if ((pd & ~TARGET_PAGE_MASK) == IO_MEM_ROM ||
 #if defined(TARGET_HAS_SMC) || 1
                         first_tb ||
 #endif
-                        ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM && 
+                        ((pd & ~TARGET_PAGE_MASK) == IO_MEM_RAM &&
                          !cpu_physical_memory_is_dirty(pd))) {
                         /* ROM: we do as if code was inside */
                         /* if code is present, we only map as read only and save the
                            original mapping */
                         VirtPageDesc *vp;
-                        
+
                         vp = virt_page_find_alloc(vaddr >> TARGET_PAGE_BITS, 1);
                         vp->phys_addr = pd;
                         vp->prot = prot;
@@ -1608,7 +1772,7 @@
                         prot &= ~PAGE_WRITE;
                     }
                 }
-                map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot, 
+                map_addr = mmap((void *)vaddr, TARGET_PAGE_SIZE, prot,
                                 MAP_SHARED | MAP_FIXED, phys_ram_fd, (pd & TARGET_PAGE_MASK));
                 if (map_addr == MAP_FAILED) {
                     cpu_abort(env, "mmap failed when mapped physical address 0x%08x to virtual address 0x%08x\n",
@@ -1646,7 +1810,7 @@
     if (!(vp->prot & PAGE_WRITE))
         return 0;
 #if defined(DEBUG_TLB)
-    printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n", 
+    printf("page_unprotect: addr=0x%08x phys_addr=0x%08x prot=%x\n",
            addr, vp->phys_addr, vp->prot);
 #endif
     if (mprotect((void *)addr, TARGET_PAGE_SIZE, vp->prot) < 0)
@@ -1672,8 +1836,8 @@
 {
 }
 
-int tlb_set_page_exec(CPUState *env, target_ulong vaddr, 
-                      target_phys_addr_t paddr, int prot, 
+int tlb_set_page_exec(CPUState *env, target_ulong vaddr,
+                      target_phys_addr_t paddr, int prot,
                       int is_user, int is_softmmu)
 {
     return 0;
@@ -1705,7 +1869,7 @@
                 end = (i << (32 - L1_BITS)) | (j << TARGET_PAGE_BITS);
                 if (start != -1) {
                     fprintf(f, "%08lx-%08lx %08lx %c%c%c\n",
-                            start, end, end - start, 
+                            start, end, end - start,
                             prot & PAGE_READ ? 'r' : '-',
                             prot & PAGE_WRITE ? 'w' : '-',
                             prot & PAGE_EXEC ? 'x' : '-');
@@ -1749,7 +1913,7 @@
         p = page_find_alloc(addr >> TARGET_PAGE_BITS);
         /* if the write protection is set, then we invalidate the code
            inside */
-        if (!(p->flags & PAGE_WRITE) && 
+        if (!(p->flags & PAGE_WRITE) &&
             (flags & PAGE_WRITE) &&
             p->first_tb) {
             tb_invalidate_phys_page(addr, 0, NULL);
@@ -1784,7 +1948,7 @@
     if (prot & PAGE_WRITE_ORG) {
         pindex = (address - host_start) >> TARGET_PAGE_BITS;
         if (!(p1[pindex].flags & PAGE_WRITE)) {
-            mprotect((void *)g2h(host_start), qemu_host_page_size, 
+            mprotect((void *)g2h(host_start), qemu_host_page_size,
                      (prot & PAGE_BITS) | PAGE_WRITE);
             p1[pindex].flags |= PAGE_WRITE;
             /* and since the content will be modified, we must invalidate
@@ -1820,27 +1984,92 @@
 }
 #endif /* defined(CONFIG_USER_ONLY) */
 
+static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
+                             int memory);
+static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
+                           int orig_memory);
+#define CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2, \
+                      need_subpage)                                     \
+    do {                                                                \
+        if (addr > start_addr)                                          \
+            start_addr2 = 0;                                            \
+        else {                                                          \
+            start_addr2 = start_addr & ~TARGET_PAGE_MASK;               \
+            if (start_addr2 > 0)                                        \
+                need_subpage = 1;                                       \
+        }                                                               \
+                                                                        \
+        if ((start_addr + orig_size) - addr >= TARGET_PAGE_SIZE)        \
+            end_addr2 = TARGET_PAGE_SIZE - 1;                           \
+        else {                                                          \
+            end_addr2 = (start_addr + orig_size - 1) & ~TARGET_PAGE_MASK; \
+            if (end_addr2 < TARGET_PAGE_SIZE - 1)                       \
+                need_subpage = 1;                                       \
+        }                                                               \
+    } while (0)
+
 /* register physical memory. 'size' must be a multiple of the target
    page size. If (phys_offset & ~TARGET_PAGE_MASK) != 0, then it is an
    io memory page */
-void cpu_register_physical_memory(target_phys_addr_t start_addr, 
+void cpu_register_physical_memory(target_phys_addr_t start_addr,
                                   unsigned long size,
                                   unsigned long phys_offset)
 {
     target_phys_addr_t addr, end_addr;
     PhysPageDesc *p;
     CPUState *env;
+    unsigned long orig_size = size;
+    void *subpage;
 
     size = (size + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK;
-    end_addr = start_addr + size;
+    end_addr = start_addr + (target_phys_addr_t)size;
     for(addr = start_addr; addr != end_addr; addr += TARGET_PAGE_SIZE) {
-        p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
-        p->phys_offset = phys_offset;
-        if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
-            (phys_offset & IO_MEM_ROMD))
-            phys_offset += TARGET_PAGE_SIZE;
+        p = phys_page_find(addr >> TARGET_PAGE_BITS);
+        if (p && p->phys_offset != IO_MEM_UNASSIGNED) {
+            unsigned long orig_memory = p->phys_offset;
+            target_phys_addr_t start_addr2, end_addr2;
+            int need_subpage = 0;
+
+            CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr, end_addr2,
+                          need_subpage);
+            if (need_subpage) {
+                if (!(orig_memory & IO_MEM_SUBPAGE)) {
+                    subpage = subpage_init((addr & TARGET_PAGE_MASK),
+                                           &p->phys_offset, orig_memory);
+                } else {
+                    subpage = io_mem_opaque[(orig_memory & ~TARGET_PAGE_MASK)
+                                            >> IO_MEM_SHIFT];
+                }
+                subpage_register(subpage, start_addr2, end_addr2, phys_offset);
+            } else {
+                p->phys_offset = phys_offset;
+                if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
+                    (phys_offset & IO_MEM_ROMD))
+                    phys_offset += TARGET_PAGE_SIZE;
+            }
+        } else {
+            p = phys_page_find_alloc(addr >> TARGET_PAGE_BITS, 1);
+            p->phys_offset = phys_offset;
+            if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM ||
+                (phys_offset & IO_MEM_ROMD))
+                phys_offset += TARGET_PAGE_SIZE;
+            else {
+                target_phys_addr_t start_addr2, end_addr2;
+                int need_subpage = 0;
+
+                CHECK_SUBPAGE(addr, start_addr, start_addr2, end_addr,
+                              end_addr2, need_subpage);
+
+                if (need_subpage) {
+                    subpage = subpage_init((addr & TARGET_PAGE_MASK),
+                                           &p->phys_offset, IO_MEM_UNASSIGNED);
+                    subpage_register(subpage, start_addr2, end_addr2,
+                                     phys_offset);
+                }
+            }
+        }
     }
-    
+
     /* since each CPU stores ram addresses in its TLB cache, we must
        reset the modified entries */
     /* XXX: slow ! */
@@ -1860,10 +2089,31 @@
     return p->phys_offset;
 }
 
+/* XXX: better than nothing */
+ram_addr_t qemu_ram_alloc(unsigned int size)
+{
+    ram_addr_t addr;
+    if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
+        fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
+                size, phys_ram_size);
+        abort();
+    }
+    addr = phys_ram_alloc_offset;
+    phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
+    return addr;
+}
+
+void qemu_ram_free(ram_addr_t addr)
+{
+}
+
 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
+    do_unassigned_access(addr, 0, 0, 0);
 #endif
     return 0;
 }
@@ -1871,7 +2121,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
+    do_unassigned_access(addr, 1, 0, 0);
 #endif
 }
 
@@ -1977,6 +2230,227 @@
     notdirty_mem_writel,
 };
 
+#if defined(CONFIG_SOFTMMU)
+/* Watchpoint access routines.  Watchpoints are inserted using TLB tricks,
+   so these check for a hit then pass through to the normal out-of-line
+   phys routines.  */
+static uint32_t watch_mem_readb(void *opaque, target_phys_addr_t addr)
+{
+    return ldub_phys(addr);
+}
+
+static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    return lduw_phys(addr);
+}
+
+static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+    return ldl_phys(addr);
+}
+
+/* Generate a debug exception if a watchpoint has been hit.
+   Returns the real physical address of the access.  addr will be a host
+   address in case of a RAM location.  */
+static target_ulong check_watchpoint(target_phys_addr_t addr)
+{
+    CPUState *env = cpu_single_env;
+    target_ulong watch;
+    target_ulong retaddr;
+    int i;
+
+    retaddr = addr;
+    for (i = 0; i < env->nb_watchpoints; i++) {
+        watch = env->watchpoint[i].vaddr;
+        if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
+            retaddr = addr - env->watchpoint[i].addend;
+            if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
+                cpu_single_env->watchpoint_hit = i + 1;
+                cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
+                break;
+            }
+        }
+    }
+    return retaddr;
+}
+
+static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    addr = check_watchpoint(addr);
+    stb_phys(addr, val);
+}
+
+static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    addr = check_watchpoint(addr);
+    stw_phys(addr, val);
+}
+
+static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+    addr = check_watchpoint(addr);
+    stl_phys(addr, val);
+}
+
+static CPUReadMemoryFunc *watch_mem_read[3] = {
+    watch_mem_readb,
+    watch_mem_readw,
+    watch_mem_readl,
+};
+
+static CPUWriteMemoryFunc *watch_mem_write[3] = {
+    watch_mem_writeb,
+    watch_mem_writew,
+    watch_mem_writel,
+};
+#endif
+
+static inline uint32_t subpage_readlen (subpage_t *mmio, target_phys_addr_t addr,
+                                 unsigned int len)
+{
+    CPUReadMemoryFunc **mem_read;
+    uint32_t ret;
+    unsigned int idx;
+
+    idx = SUBPAGE_IDX(addr - mmio->base);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d\n", __func__,
+           mmio, len, addr, idx);
+#endif
+    mem_read = mmio->mem_read[idx];
+    ret = (*mem_read[len])(mmio->opaque[idx], addr);
+
+    return ret;
+}
+
+static inline void subpage_writelen (subpage_t *mmio, target_phys_addr_t addr,
+                              uint32_t value, unsigned int len)
+{
+    CPUWriteMemoryFunc **mem_write;
+    unsigned int idx;
+
+    idx = SUBPAGE_IDX(addr - mmio->base);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: subpage %p len %d addr " TARGET_FMT_plx " idx %d value %08x\n", __func__,
+           mmio, len, addr, idx, value);
+#endif
+    mem_write = mmio->mem_write[idx];
+    (*mem_write[len])(mmio->opaque[idx], addr, value);
+}
+
+static uint32_t subpage_readb (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return subpage_readlen(opaque, addr, 0);
+}
+
+static void subpage_writeb (void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
+#endif
+    subpage_writelen(opaque, addr, value, 0);
+}
+
+static uint32_t subpage_readw (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return subpage_readlen(opaque, addr, 1);
+}
+
+static void subpage_writew (void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
+#endif
+    subpage_writelen(opaque, addr, value, 1);
+}
+
+static uint32_t subpage_readl (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
+#endif
+
+    return subpage_readlen(opaque, addr, 2);
+}
+
+static void subpage_writel (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: addr " TARGET_FMT_plx " val %08x\n", __func__, addr, value);
+#endif
+    subpage_writelen(opaque, addr, value, 2);
+}
+
+static CPUReadMemoryFunc *subpage_read[] = {
+    &subpage_readb,
+    &subpage_readw,
+    &subpage_readl,
+};
+
+static CPUWriteMemoryFunc *subpage_write[] = {
+    &subpage_writeb,
+    &subpage_writew,
+    &subpage_writel,
+};
+
+static int subpage_register (subpage_t *mmio, uint32_t start, uint32_t end,
+                             int memory)
+{
+    int idx, eidx;
+
+    if (start >= TARGET_PAGE_SIZE || end >= TARGET_PAGE_SIZE)
+        return -1;
+    idx = SUBPAGE_IDX(start);
+    eidx = SUBPAGE_IDX(end);
+#if defined(DEBUG_SUBPAGE)
+    printf("%s: %p start %08x end %08x idx %08x eidx %08x mem %d\n", __func__,
+           mmio, start, end, idx, eidx, memory);
+#endif
+    memory >>= IO_MEM_SHIFT;
+    for (; idx <= eidx; idx++) {
+        mmio->mem_read[idx] = io_mem_read[memory];
+        mmio->mem_write[idx] = io_mem_write[memory];
+        mmio->opaque[idx] = io_mem_opaque[memory];
+    }
+
+    return 0;
+}
+
+static void *subpage_init (target_phys_addr_t base, uint32_t *phys,
+                           int orig_memory)
+{
+    subpage_t *mmio;
+    int subpage_memory;
+
+    mmio = qemu_mallocz(sizeof(subpage_t));
+    if (mmio != NULL) {
+        mmio->base = base;
+        subpage_memory = cpu_register_io_memory(0, subpage_read, subpage_write, mmio);
+#if defined(DEBUG_SUBPAGE)
+        printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
+               mmio, base, TARGET_PAGE_SIZE, subpage_memory);
+#endif
+        *phys = subpage_memory | IO_MEM_SUBPAGE;
+        subpage_register(mmio, 0, TARGET_PAGE_SIZE - 1, orig_memory);
+    }
+
+    return mmio;
+}
+
 static void io_mem_init(void)
 {
     cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
@@ -1984,6 +2458,10 @@
     cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
     io_mem_nb = 5;
 
+#if defined(CONFIG_SOFTMMU)
+    io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
+                                          watch_mem_write, NULL);
+#endif
     /* alloc dirty bits array */
     phys_ram_dirty = qemu_vmalloc(phys_ram_size >> TARGET_PAGE_BITS);
     memset(phys_ram_dirty, 0xff, phys_ram_size >> TARGET_PAGE_BITS);
@@ -2031,7 +2509,7 @@
 
 /* physical memory access (slow version, mainly for debug) */
 #if defined(CONFIG_USER_ONLY)
-void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write)
 {
     int l, flags;
@@ -2066,7 +2544,7 @@
 }
 
 #else
-void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf, 
+void cpu_physical_memory_rw(target_phys_addr_t addr, uint8_t *buf,
                             int len, int is_write)
 {
     int l, io_index;
@@ -2075,7 +2553,7 @@
     target_phys_addr_t page;
     unsigned long pd;
     PhysPageDesc *p;
-    
+
     while (len > 0) {
         page = addr & TARGET_PAGE_MASK;
         l = (page + TARGET_PAGE_SIZE) - addr;
@@ -2087,7 +2565,7 @@
         } else {
             pd = p->phys_offset;
         }
-        
+
         if (is_write) {
             if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
@@ -2119,12 +2597,12 @@
                     /* invalidate code */
                     tb_invalidate_phys_page_range(addr1, addr1 + l, 0);
                     /* set dirty bit */
-                    phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |= 
+                    phys_ram_dirty[addr1 >> TARGET_PAGE_BITS] |=
                         (0xff & ~CODE_DIRTY_FLAG);
                 }
             }
         } else {
-            if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 
+            if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
                 !(pd & IO_MEM_ROMD)) {
                 /* I/O case */
                 io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
@@ -2146,7 +2624,7 @@
                 }
             } else {
                 /* RAM case */
-                ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
+                ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
                     (addr & ~TARGET_PAGE_MASK);
                 memcpy(buf, ptr, l);
             }
@@ -2158,7 +2636,7 @@
 }
 
 /* used for ROM loading : can write in RAM and ROM */
-void cpu_physical_memory_write_rom(target_phys_addr_t addr, 
+void cpu_physical_memory_write_rom(target_phys_addr_t addr,
                                    const uint8_t *buf, int len)
 {
     int l;
@@ -2166,7 +2644,7 @@
     target_phys_addr_t page;
     unsigned long pd;
     PhysPageDesc *p;
-    
+
     while (len > 0) {
         page = addr & TARGET_PAGE_MASK;
         l = (page + TARGET_PAGE_SIZE) - addr;
@@ -2178,7 +2656,7 @@
         } else {
             pd = p->phys_offset;
         }
-        
+
         if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM &&
             (pd & ~TARGET_PAGE_MASK) != IO_MEM_ROM &&
             !(pd & IO_MEM_ROMD)) {
@@ -2212,15 +2690,15 @@
     } else {
         pd = p->phys_offset;
     }
-        
-    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM && 
+
+    if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
         !(pd & IO_MEM_ROMD)) {
         /* I/O case */
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
     } else {
         /* RAM case */
-        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
+        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
         val = ldl_p(ptr);
     }
@@ -2242,7 +2720,7 @@
     } else {
         pd = p->phys_offset;
     }
-        
+
     if ((pd & ~TARGET_PAGE_MASK) > IO_MEM_ROM &&
         !(pd & IO_MEM_ROMD)) {
         /* I/O case */
@@ -2256,7 +2734,7 @@
 #endif
     } else {
         /* RAM case */
-        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) + 
+        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
             (addr & ~TARGET_PAGE_MASK);
         val = ldq_p(ptr);
     }
@@ -2303,14 +2781,12 @@
     } else {
         pd = p->phys_offset;
     }
-        
+
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
     } else {
-        unsigned long addr1;
-        addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
-
+	unsigned long addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
         ptr = phys_ram_base + addr1;
         stl_p(ptr, val);
 
@@ -2326,6 +2802,36 @@
     }
 }
 
+void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
+{
+    int io_index;
+    uint8_t *ptr;
+    unsigned long pd;
+    PhysPageDesc *p;
+
+    p = phys_page_find(addr >> TARGET_PAGE_BITS);
+    if (!p) {
+        pd = IO_MEM_UNASSIGNED;
+    } else {
+        pd = p->phys_offset;
+    }
+
+    if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
+        io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
+#ifdef TARGET_WORDS_BIGENDIAN
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val >> 32);
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val);
+#else
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
+        io_mem_write[io_index][2](io_mem_opaque[io_index], addr + 4, val >> 32);
+#endif
+    } else {
+        ptr = phys_ram_base + (pd & TARGET_PAGE_MASK) +
+            (addr & ~TARGET_PAGE_MASK);
+        stq_p(ptr, val);
+    }
+}
+
 /* warning: addr must be aligned */
 void stl_phys(target_phys_addr_t addr, uint32_t val)
 {
@@ -2340,7 +2846,7 @@
     } else {
         pd = p->phys_offset;
     }
-        
+
     if ((pd & ~TARGET_PAGE_MASK) != IO_MEM_RAM) {
         io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
         io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
@@ -2384,11 +2890,12 @@
 #endif
 
 /* virtual memory access for debug */
-int cpu_memory_rw_debug(CPUState *env, target_ulong addr, 
+int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
                         uint8_t *buf, int len, int is_write)
 {
     int l;
-    target_ulong page, phys_addr;
+    target_phys_addr_t phys_addr;
+    target_ulong page;
 
     while (len > 0) {
         page = addr & TARGET_PAGE_MASK;
@@ -2399,7 +2906,7 @@
         l = (page + TARGET_PAGE_SIZE) - addr;
         if (l > len)
             l = len;
-        cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK), 
+        cpu_physical_memory_rw(phys_addr + (addr & ~TARGET_PAGE_MASK),
                                buf, l, is_write);
         len -= l;
         buf += l;
@@ -2414,7 +2921,7 @@
     int i, target_code_size, max_target_code_size;
     int direct_jmp_count, direct_jmp2_count, cross_page;
     TranslationBlock *tb;
-    
+
     target_code_size = 0;
     max_target_code_size = 0;
     cross_page = 0;
@@ -2436,17 +2943,17 @@
     }
     /* XXX: avoid using doubles ? */
     cpu_fprintf(f, "TB count            %d\n", nb_tbs);
-    cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n", 
+    cpu_fprintf(f, "TB avg target size  %d max=%d bytes\n",
                 nb_tbs ? target_code_size / nb_tbs : 0,
                 max_target_code_size);
-    cpu_fprintf(f, "TB avg host size    %d bytes (expansion ratio: %0.1f)\n", 
+    cpu_fprintf(f, "TB avg host size    %d bytes (expansion ratio: %0.1f)\n",
                 nb_tbs ? (code_gen_ptr - code_gen_buffer) / nb_tbs : 0,
                 target_code_size ? (double) (code_gen_ptr - code_gen_buffer) / target_code_size : 0);
-    cpu_fprintf(f, "cross page TB count %d (%d%%)\n", 
-            cross_page, 
+    cpu_fprintf(f, "cross page TB count %d (%d%%)\n",
+            cross_page,
             nb_tbs ? (cross_page * 100) / nb_tbs : 0);
     cpu_fprintf(f, "direct jump count   %d (%d%%) (2 jumps=%d %d%%)\n",
-                direct_jmp_count, 
+                direct_jmp_count,
                 nb_tbs ? (direct_jmp_count * 100) / nb_tbs : 0,
                 direct_jmp2_count,
                 nb_tbs ? (direct_jmp2_count * 100) / nb_tbs : 0);
@@ -2455,7 +2962,7 @@
     cpu_fprintf(f, "TLB flush count     %d\n", tlb_flush_count);
 }
 
-#if !defined(CONFIG_USER_ONLY) 
+#if !defined(CONFIG_USER_ONLY)
 
 #define MMUSUFFIX _cmmu
 #define GETPC() NULL
diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c
index f20d5c4..e58551f 100644
--- a/fpu/softfloat-native.c
+++ b/fpu/softfloat-native.c
@@ -30,6 +30,25 @@
 #define sqrtf(f)		((float)sqrt(f))
 #define remainderf(fa, fb)	((float)remainder(fa, fb))
 #define rintf(f)		((float)rint(f))
+#if !defined(__sparc__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10
+extern long double rintl(long double);
+extern long double scalbnl(long double, int);
+
+long long
+llrintl(long double x) {
+	return ((long long) rintl(x));
+}
+
+long
+lrintl(long double x) {
+	return ((long) rintl(x));
+}
+
+long double
+ldexpl(long double x, int n) {
+	return (scalbnl(x, n));
+}
+#endif
 #endif
 
 #if defined(__powerpc__)
@@ -40,7 +59,7 @@
     double y = 4503599627370496.0;
     if (fabs(x) >= y)
         return x;
-    if (x < 0) 
+    if (x < 0)
         y = -y;
     y = (x + y) - y;
     if (y == 0.0)
@@ -59,11 +78,21 @@
     return (float32)v;
 }
 
+float32 uint32_to_float32(unsigned int v STATUS_PARAM)
+{
+    return (float32)v;
+}
+
 float64 int32_to_float64(int v STATUS_PARAM)
 {
     return (float64)v;
 }
 
+float64 uint32_to_float64(unsigned int v STATUS_PARAM)
+{
+    return (float64)v;
+}
+
 #ifdef FLOATX80
 floatx80 int32_to_floatx80(int v STATUS_PARAM)
 {
@@ -74,10 +103,18 @@
 {
     return (float32)v;
 }
+float32 uint64_to_float32( uint64_t v STATUS_PARAM)
+{
+    return (float32)v;
+}
 float64 int64_to_float64( int64_t v STATUS_PARAM)
 {
     return (float64)v;
 }
+float64 uint64_to_float64( uint64_t v STATUS_PARAM)
+{
+    return (float64)v;
+}
 #ifdef FLOATX80
 floatx80 int64_to_floatx80( int64_t v STATUS_PARAM)
 {
@@ -94,7 +131,7 @@
 #else
 static inline int long_to_int32(long a)
 {
-    if (a != (int32_t)a) 
+    if (a != (int32_t)a)
         a = 0x80000000;
     return a;
 }
@@ -132,6 +169,37 @@
 }
 #endif
 
+unsigned int float32_to_uint32( float32 a STATUS_PARAM)
+{
+    int64_t v;
+    unsigned int res;
+
+    v = llrintf(a);
+    if (v < 0) {
+        res = 0;
+    } else if (v > 0xffffffff) {
+        res = 0xffffffff;
+    } else {
+        res = v;
+    }
+    return res;
+}
+unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM)
+{
+    int64_t v;
+    unsigned int res;
+
+    v = (int64_t)a;
+    if (v < 0) {
+        res = 0;
+    } else if (v > 0xffffffff) {
+        res = 0xffffffff;
+    } else {
+        res = v;
+    }
+    return res;
+}
+
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE single-precision operations.
 *----------------------------------------------------------------------------*/
@@ -218,9 +286,62 @@
 }
 #endif
 
+unsigned int float64_to_uint32( float64 a STATUS_PARAM)
+{
+    int64_t v;
+    unsigned int res;
+
+    v = llrint(a);
+    if (v < 0) {
+        res = 0;
+    } else if (v > 0xffffffff) {
+        res = 0xffffffff;
+    } else {
+        res = v;
+    }
+    return res;
+}
+unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM)
+{
+    int64_t v;
+    unsigned int res;
+
+    v = (int64_t)a;
+    if (v < 0) {
+        res = 0;
+    } else if (v > 0xffffffff) {
+        res = 0xffffffff;
+    } else {
+        res = v;
+    }
+    return res;
+}
+uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
+{
+    int64_t v;
+
+    v = llrint(a + (float64)INT64_MIN);
+
+    return v - INT64_MIN;
+}
+uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
+{
+    int64_t v;
+
+    v = (int64_t)(a + (float64)INT64_MIN);
+
+    return v - INT64_MIN;
+}
+
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE double-precision operations.
 *----------------------------------------------------------------------------*/
+#if defined(__sun__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 10
+static inline float64 trunc(float64 x)
+{
+    return x < 0 ? -floor(-x) : floor(x);
+}
+#endif
 float64 float64_trunc_to_int( float64 a STATUS_PARAM )
 {
     return trunc(a);
diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h
index 8c27708..2977717 100644
--- a/fpu/softfloat-native.h
+++ b/fpu/softfloat-native.h
@@ -15,7 +15,7 @@
  *   Solaris 10 with GCC4 does not need these macros as they
  *   are defined in <iso/math_c99.h> with a compiler directive
  */
-#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ( ( HOST_SOLARIS >= 10 ) && ( __GNUC__ <= 4) ))
+#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) && (__GNUC__ <= 4)))
 /*
  * C99 7.12.3 classification macros
  * and
@@ -33,6 +33,29 @@
 #define isunordered(x,y)        unordered(x, y)
 #endif
 
+#if defined(__sun__) && !defined(NEED_LIBSUNMATH)
+
+#ifndef isnan
+# define isnan(x) \
+    (sizeof (x) == sizeof (long double) ? isnan_ld (x) \
+     : sizeof (x) == sizeof (double) ? isnan_d (x) \
+     : isnan_f (x))
+static inline int isnan_f  (float       x) { return x != x; }
+static inline int isnan_d  (double      x) { return x != x; }
+static inline int isnan_ld (long double x) { return x != x; }
+#endif
+
+#ifndef isinf
+# define isinf(x) \
+    (sizeof (x) == sizeof (long double) ? isinf_ld (x) \
+     : sizeof (x) == sizeof (double) ? isinf_d (x) \
+     : isinf_f (x))
+static inline int isinf_f  (float       x) { return isnan (x - x); }
+static inline int isinf_d  (double      x) { return isnan (x - x); }
+static inline int isinf_ld (long double x) { return isnan (x - x); }
+#endif
+#endif
+
 typedef float float32;
 typedef double float64;
 #ifdef FLOATX80
@@ -99,7 +122,9 @@
 | Software IEC/IEEE integer-to-floating-point conversion routines.
 *----------------------------------------------------------------------------*/
 float32 int32_to_float32( int STATUS_PARAM);
+float32 uint32_to_float32( unsigned int STATUS_PARAM);
 float64 int32_to_float64( int STATUS_PARAM);
+float64 uint32_to_float64( unsigned int STATUS_PARAM);
 #ifdef FLOATX80
 floatx80 int32_to_floatx80( int STATUS_PARAM);
 #endif
@@ -107,7 +132,9 @@
 float128 int32_to_float128( int STATUS_PARAM);
 #endif
 float32 int64_to_float32( int64_t STATUS_PARAM);
+float32 uint64_to_float32( uint64_t STATUS_PARAM);
 float64 int64_to_float64( int64_t STATUS_PARAM);
+float64 uint64_to_float64( uint64_t v STATUS_PARAM);
 #ifdef FLOATX80
 floatx80 int64_to_floatx80( int64_t STATUS_PARAM);
 #endif
@@ -120,6 +147,8 @@
 *----------------------------------------------------------------------------*/
 int float32_to_int32( float32  STATUS_PARAM);
 int float32_to_int32_round_to_zero( float32  STATUS_PARAM);
+unsigned int float32_to_uint32( float32 a STATUS_PARAM);
+unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM);
 int64_t float32_to_int64( float32  STATUS_PARAM);
 int64_t float32_to_int64_round_to_zero( float32  STATUS_PARAM);
 float64 float32_to_float64( float32  STATUS_PARAM);
@@ -200,8 +229,12 @@
 *----------------------------------------------------------------------------*/
 int float64_to_int32( float64 STATUS_PARAM );
 int float64_to_int32_round_to_zero( float64 STATUS_PARAM );
+unsigned int float64_to_uint32( float64 STATUS_PARAM );
+unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
 int64_t float64_to_int64( float64 STATUS_PARAM );
 int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM );
+uint64_t float64_to_uint64( float64 STATUS_PARAM );
+uint64_t float64_to_uint64_round_to_zero( float64 STATUS_PARAM );
 float32 float64_to_float32( float64 STATUS_PARAM );
 #ifdef FLOATX80
 floatx80 float64_to_floatx80( float64 STATUS_PARAM );
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index f9b6f0c..2802eaa 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -61,7 +61,11 @@
 /*----------------------------------------------------------------------------
 | The pattern for a default generated single-precision NaN.
 *----------------------------------------------------------------------------*/
+#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+#define float32_default_nan 0xFF800000
+#else
 #define float32_default_nan 0xFFC00000
+#endif
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the single-precision floating-point value `a' is a NaN;
@@ -70,9 +74,11 @@
 
 int float32_is_nan( float32 a )
 {
-
-    return ( 0xFF000000 < (bits32) ( a<<1 ) );
-
+#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+    return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
+#else
+    return ( 0xFF800000 <= (bits32) ( a<<1 ) );
+#endif
 }
 
 /*----------------------------------------------------------------------------
@@ -82,9 +88,11 @@
 
 int float32_is_signaling_nan( float32 a )
 {
-
+#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+    return ( 0xFF800000 <= (bits32) ( a<<1 ) );
+#else
     return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF );
-
+#endif
 }
 
 /*----------------------------------------------------------------------------
@@ -131,8 +139,13 @@
     aIsSignalingNaN = float32_is_signaling_nan( a );
     bIsNaN = float32_is_nan( b );
     bIsSignalingNaN = float32_is_signaling_nan( b );
+#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+    a &= ~0x00400000;
+    b &= ~0x00400000;
+#else
     a |= 0x00400000;
     b |= 0x00400000;
+#endif
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
     if ( aIsSignalingNaN ) {
         if ( bIsSignalingNaN ) goto returnLargerSignificand;
@@ -154,7 +167,11 @@
 /*----------------------------------------------------------------------------
 | The pattern for a default generated double-precision NaN.
 *----------------------------------------------------------------------------*/
+#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+#define float64_default_nan LIT64( 0xFFF0000000000000 )
+#else
 #define float64_default_nan LIT64( 0xFFF8000000000000 )
+#endif
 
 /*----------------------------------------------------------------------------
 | Returns 1 if the double-precision floating-point value `a' is a NaN;
@@ -163,9 +180,13 @@
 
 int float64_is_nan( float64 a )
 {
-
-    return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) );
-
+#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+    return
+           ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
+        && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
+#else
+    return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) );
+#endif
 }
 
 /*----------------------------------------------------------------------------
@@ -175,11 +196,13 @@
 
 int float64_is_signaling_nan( float64 a )
 {
-
+#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+    return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) );
+#else
     return
            ( ( ( a>>51 ) & 0xFFF ) == 0xFFE )
         && ( a & LIT64( 0x0007FFFFFFFFFFFF ) );
-
+#endif
 }
 
 /*----------------------------------------------------------------------------
@@ -229,8 +252,13 @@
     aIsSignalingNaN = float64_is_signaling_nan( a );
     bIsNaN = float64_is_nan( b );
     bIsSignalingNaN = float64_is_signaling_nan( b );
+#if defined(TARGET_MIPS) || defined(TARGET_HPPA)
+    a &= ~LIT64( 0x0008000000000000 );
+    b &= ~LIT64( 0x0008000000000000 );
+#else
     a |= LIT64( 0x0008000000000000 );
     b |= LIT64( 0x0008000000000000 );
+#endif
     if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);
     if ( aIsSignalingNaN ) {
         if ( bIsSignalingNaN ) goto returnLargerSignificand;
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 5dbfa81..6db6cf1 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -1164,6 +1164,27 @@
 
 }
 
+float32 uint64_to_float32( uint64 a STATUS_PARAM )
+{
+    int8 shiftCount;
+
+    if ( a == 0 ) return 0;
+    shiftCount = countLeadingZeros64( a ) - 40;
+    if ( 0 <= shiftCount ) {
+        return packFloat32( 1 > 0, 0x95 - shiftCount, a<<shiftCount );
+    }
+    else {
+        shiftCount += 7;
+        if ( shiftCount < 0 ) {
+            shift64RightJamming( a, - shiftCount, &a );
+        }
+        else {
+            a <<= shiftCount;
+        }
+        return roundAndPackFloat32( 1 > 0, 0x9C - shiftCount, a STATUS_VAR );
+    }
+}
+
 /*----------------------------------------------------------------------------
 | Returns the result of converting the 64-bit two's complement integer `a'
 | to the double-precision floating-point format.  The conversion is performed
@@ -1183,6 +1204,13 @@
 
 }
 
+float64 uint64_to_float64( uint64 a STATUS_PARAM )
+{
+    if ( a == 0 ) return 0;
+    return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR );
+
+}
+
 #ifdef FLOATX80
 
 /*----------------------------------------------------------------------------
@@ -5282,6 +5310,26 @@
     return res;
 }
 
+uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
+{
+    int64_t v;
+
+    v = int64_to_float64(INT64_MIN STATUS_VAR);
+    v = float64_to_int64((a + v) STATUS_VAR);
+
+    return v - INT64_MIN;
+}
+
+uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
+{
+    int64_t v;
+
+    v = int64_to_float64(INT64_MIN STATUS_VAR);
+    v = float64_to_int64_round_to_zero((a + v) STATUS_VAR);
+
+    return v - INT64_MIN;
+}
+
 #define COMPARE(s, nan_exp)                                                  \
 INLINE int float ## s ## _compare_internal( float ## s a, float ## s b,      \
                                       int is_quiet STATUS_PARAM )            \
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index a326af8..f344d2e 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -32,6 +32,10 @@
 #ifndef SOFTFLOAT_H
 #define SOFTFLOAT_H
 
+#if defined(HOST_SOLARIS) && defined(NEEDS_LIBSUNMATH)
+#include <sunmath.h>
+#endif
+
 #include <inttypes.h>
 #include "config.h"
 
@@ -193,7 +197,9 @@
 float128 int32_to_float128( int STATUS_PARAM );
 #endif
 float32 int64_to_float32( int64_t STATUS_PARAM );
+float32 uint64_to_float32( uint64_t STATUS_PARAM );
 float64 int64_to_float64( int64_t STATUS_PARAM );
+float64 uint64_to_float64( uint64_t STATUS_PARAM );
 #ifdef FLOATX80
 floatx80 int64_to_floatx80( int64_t STATUS_PARAM );
 #endif
@@ -236,8 +242,8 @@
 int float32_lt_quiet( float32, float32 STATUS_PARAM );
 int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
+int float32_is_nan( float32 );
 int float32_is_signaling_nan( float32 );
-int float64_is_nan( float64 a );
 
 INLINE float32 float32_abs(float32 a)
 {
@@ -258,6 +264,8 @@
 unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM );
 int64_t float64_to_int64( float64 STATUS_PARAM );
 int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM );
+uint64_t float64_to_uint64 (float64 a STATUS_PARAM);
+uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM);
 float32 float64_to_float32( float64 STATUS_PARAM );
 #ifdef FLOATX80
 floatx80 float64_to_floatx80( float64 STATUS_PARAM );
@@ -285,6 +293,7 @@
 int float64_lt_quiet( float64, float64 STATUS_PARAM );
 int float64_compare( float64, float64 STATUS_PARAM );
 int float64_compare_quiet( float64, float64 STATUS_PARAM );
+int float64_is_nan( float64 a );
 int float64_is_signaling_nan( float64 );
 
 INLINE float64 float64_abs(float64 a)
@@ -328,6 +337,7 @@
 int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
 int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_is_nan( floatx80 );
 int floatx80_is_signaling_nan( floatx80 );
 
 INLINE floatx80 floatx80_abs(floatx80 a)
@@ -375,6 +385,7 @@
 int float128_eq_signaling( float128, float128 STATUS_PARAM );
 int float128_le_quiet( float128, float128 STATUS_PARAM );
 int float128_lt_quiet( float128, float128 STATUS_PARAM );
+int float128_is_nan( float128 );
 int float128_is_signaling_nan( float128 );
 
 INLINE float128 float128_abs(float128 a)
diff --git a/gdbstub.c b/gdbstub.c
index a3b82af..bdd2c04 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1,6 +1,6 @@
 /*
  * gdb server stub
- * 
+ *
  * Copyright (c) 2003-2005 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -387,7 +387,7 @@
     registers[41] = 0; /* foseg */
     registers[42] = 0; /* fooff */
     registers[43] = 0; /* fop */
-    
+
     for(i = 0; i < 16; i++)
         tswapls(&registers[i]);
     for(i = 36; i < 44; i++)
@@ -442,7 +442,7 @@
     registers[98] = tswapl(tmp);
     registers[99] = tswapl(env->lr);
     registers[100] = tswapl(env->ctr);
-    registers[101] = tswapl(do_load_xer(env));
+    registers[101] = tswapl(ppc_load_xer(env));
     registers[102] = 0;
 
     return 103 * 4;
@@ -470,7 +470,7 @@
         env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
     env->lr = tswapl(registers[99]);
     env->ctr = tswapl(registers[100]);
-    do_store_xer(env, tswapl(registers[101]));
+    ppc_store_xer(env, tswapl(registers[101]));
 }
 #elif defined (TARGET_SPARC)
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
@@ -512,13 +512,16 @@
     for (i = 0; i < 64; i += 2) {
 	uint64_t tmp;
 
-        tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32;
-        tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1]));
-        registers[i/2 + 32] = tmp;
+        tmp = ((uint64_t)*(uint32_t *)&env->fpr[i]) << 32;
+        tmp |= *(uint32_t *)&env->fpr[i + 1];
+        registers[i / 2 + 32] = tswap64(tmp);
     }
     registers[64] = tswapl(env->pc);
     registers[65] = tswapl(env->npc);
-    registers[66] = tswapl(env->tstate[env->tl]);
+    registers[66] = tswapl(((uint64_t)GET_CCR(env) << 32) |
+                           ((env->asi & 0xff) << 24) |
+                           ((env->pstate & 0xfff) << 8) |
+                           GET_CWP64(env));
     registers[67] = tswapl(env->fsr);
     registers[68] = tswapl(env->fprs);
     registers[69] = tswapl(env->y);
@@ -554,12 +557,22 @@
     env->fsr = tswapl(registers[70]);
 #else
     for (i = 0; i < 64; i += 2) {
-	*((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32);
-	*((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 0xffffffff);
+        uint64_t tmp;
+
+        tmp = tswap64(registers[i / 2 + 32]);
+	*((uint32_t *)&env->fpr[i]) = tmp >> 32;
+	*((uint32_t *)&env->fpr[i + 1]) = tmp & 0xffffffff;
     }
     env->pc = tswapl(registers[64]);
     env->npc = tswapl(registers[65]);
-    env->tstate[env->tl] = tswapl(registers[66]);
+    {
+        uint64_t tmp = tswapl(registers[66]);
+
+        PUT_CCR(env, tmp >> 32);
+        env->asi = (tmp >> 24) & 0xff;
+        env->pstate = (tmp >> 8) & 0xfff;
+        PUT_CWP64(env, tmp & 0xff);
+    }
     env->fsr = tswapl(registers[67]);
     env->fprs = tswapl(registers[68]);
     env->y = tswapl(registers[69]);
@@ -665,7 +678,7 @@
     /* F0-F7.  The 68881/68040 have 12-bit extended precision registers.
        ColdFire has 8-bit double precision registers.  */
     for (i = 0; i < 8; i++) {
-        u.l.upper = tswap32(*(uint32_t *)ptr); 
+        u.l.upper = tswap32(*(uint32_t *)ptr);
         u.l.lower = tswap32(*(uint32_t *)ptr);
         env->fregs[i] = u.d;
     }
@@ -681,42 +694,43 @@
     ptr = mem_buf;
     for (i = 0; i < 32; i++)
       {
-        *(uint32_t *)ptr = tswapl(env->gpr[i]);
-        ptr += 4;
+        *(target_ulong *)ptr = tswapl(env->gpr[i][env->current_tc]);
+        ptr += sizeof(target_ulong);
       }
 
-    *(uint32_t *)ptr = tswapl(env->CP0_Status);
-    ptr += 4;
+    *(target_ulong *)ptr = tswapl(env->CP0_Status);
+    ptr += sizeof(target_ulong);
 
-    *(uint32_t *)ptr = tswapl(env->LO);
-    ptr += 4;
+    *(target_ulong *)ptr = tswapl(env->LO[0][env->current_tc]);
+    ptr += sizeof(target_ulong);
 
-    *(uint32_t *)ptr = tswapl(env->HI);
-    ptr += 4;
+    *(target_ulong *)ptr = tswapl(env->HI[0][env->current_tc]);
+    ptr += sizeof(target_ulong);
 
-    *(uint32_t *)ptr = tswapl(env->CP0_BadVAddr);
-    ptr += 4;
+    *(target_ulong *)ptr = tswapl(env->CP0_BadVAddr);
+    ptr += sizeof(target_ulong);
 
-    *(uint32_t *)ptr = tswapl(env->CP0_Cause);
-    ptr += 4;
+    *(target_ulong *)ptr = tswapl(env->CP0_Cause);
+    ptr += sizeof(target_ulong);
 
-    *(uint32_t *)ptr = tswapl(env->PC);
-    ptr += 4;
+    *(target_ulong *)ptr = tswapl(env->PC[env->current_tc]);
+    ptr += sizeof(target_ulong);
 
-#ifdef MIPS_USES_FPU
-    for (i = 0; i < 32; i++)
+    if (env->CP0_Config1 & (1 << CP0C1_FP))
       {
-        *(uint32_t *)ptr = tswapl(FPR_W (env, i));
-        ptr += 4;
+        for (i = 0; i < 32; i++)
+          {
+            *(target_ulong *)ptr = tswapl(env->fpu->fpr[i].fs[FP_ENDIAN_IDX]);
+            ptr += sizeof(target_ulong);
+          }
+
+        *(target_ulong *)ptr = tswapl(env->fpu->fcr31);
+        ptr += sizeof(target_ulong);
+
+        *(target_ulong *)ptr = tswapl(env->fpu->fcr0);
+        ptr += sizeof(target_ulong);
       }
 
-    *(uint32_t *)ptr = tswapl(env->fcr31);
-    ptr += 4;
-
-    *(uint32_t *)ptr = tswapl(env->fcr0);
-    ptr += 4;
-#endif
-
     /* 32 FP registers, fsr, fir, fp.  Not yet implemented.  */
     /* what's 'fp' mean here?  */
 
@@ -732,7 +746,7 @@
     float_round_down
   };
 #define RESTORE_ROUNDING_MODE \
-    set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
+    set_float_rounding_mode(ieee_rm[env->fpu->fcr31 & 3], &env->fpu->fp_status)
 
 static void cpu_gdb_write_registers(CPUState *env, uint8_t *mem_buf, int size)
 {
@@ -742,51 +756,55 @@
     ptr = mem_buf;
     for (i = 0; i < 32; i++)
       {
-        env->gpr[i] = tswapl(*(uint32_t *)ptr);
-        ptr += 4;
+        env->gpr[i][env->current_tc] = tswapl(*(target_ulong *)ptr);
+        ptr += sizeof(target_ulong);
       }
 
-    env->CP0_Status = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
+    env->CP0_Status = tswapl(*(target_ulong *)ptr);
+    ptr += sizeof(target_ulong);
 
-    env->LO = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
+    env->LO[0][env->current_tc] = tswapl(*(target_ulong *)ptr);
+    ptr += sizeof(target_ulong);
 
-    env->HI = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
+    env->HI[0][env->current_tc] = tswapl(*(target_ulong *)ptr);
+    ptr += sizeof(target_ulong);
 
-    env->CP0_BadVAddr = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
+    env->CP0_BadVAddr = tswapl(*(target_ulong *)ptr);
+    ptr += sizeof(target_ulong);
 
-    env->CP0_Cause = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
+    env->CP0_Cause = tswapl(*(target_ulong *)ptr);
+    ptr += sizeof(target_ulong);
 
-    env->PC = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
+    env->PC[env->current_tc] = tswapl(*(target_ulong *)ptr);
+    ptr += sizeof(target_ulong);
 
-#ifdef MIPS_USES_FPU
-    for (i = 0; i < 32; i++)
+    if (env->CP0_Config1 & (1 << CP0C1_FP))
       {
-	FPR_W (env, i) = tswapl(*(uint32_t *)ptr);
-        ptr += 4;
-      }
+        for (i = 0; i < 32; i++)
+          {
+            env->fpu->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(target_ulong *)ptr);
+            ptr += sizeof(target_ulong);
+          }
 
-    env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF;
-    ptr += 4;
+        env->fpu->fcr31 = tswapl(*(target_ulong *)ptr) & 0x0183FFFF;
+        ptr += sizeof(target_ulong);
 
-    env->fcr0 = tswapl(*(uint32_t *)ptr);
-    ptr += 4;
+        env->fpu->fcr0 = tswapl(*(target_ulong *)ptr);
+        ptr += sizeof(target_ulong);
 
-    /* set rounding mode */
-    RESTORE_ROUNDING_MODE;
+        /* set rounding mode */
+        RESTORE_ROUNDING_MODE;
 
 #ifndef CONFIG_SOFTFLOAT
-    /* no floating point exception for native float */
-    SET_FP_ENABLE(env->fcr31, 0);
+        /* no floating point exception for native float */
+        SET_FP_ENABLE(env->fcr31, 0);
 #endif
-#endif
+      }
 }
 #elif defined (TARGET_SH4)
+
+/* Hint: Use "set architecture sh4" in GDB to see fpu registers */
+
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
 {
   uint32_t *ptr = (uint32_t *)mem_buf;
@@ -806,12 +824,14 @@
   SAVE (env->mach);
   SAVE (env->macl);
   SAVE (env->sr);
-  SAVE (0); /* TICKS */
-  SAVE (0); /* STALLS */
-  SAVE (0); /* CYCLES */
-  SAVE (0); /* INSTS */
-  SAVE (0); /* PLR */
-
+  SAVE (env->fpul);
+  SAVE (env->fpscr);
+  for (i = 0; i < 16; i++)
+      SAVE(env->fregs[i + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
+  SAVE (env->ssr);
+  SAVE (env->spc);
+  for (i = 0; i < 8; i++) SAVE(env->gregs[i]);
+  for (i = 0; i < 8; i++) SAVE(env->gregs[i + 16]);
   return ((uint8_t *)ptr - mem_buf);
 }
 
@@ -834,6 +854,14 @@
   LOAD (env->mach);
   LOAD (env->macl);
   LOAD (env->sr);
+  LOAD (env->fpul);
+  LOAD (env->fpscr);
+  for (i = 0; i < 16; i++)
+      LOAD(env->fregs[i + ((env->fpscr & FPSCR_FR) ? 16 : 0)]);
+  LOAD (env->ssr);
+  LOAD (env->spc);
+  for (i = 0; i < 8; i++) LOAD(env->gregs[i]);
+  for (i = 0; i < 8; i++) LOAD(env->gregs[i + 16]);
 }
 #else
 static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
@@ -855,7 +883,7 @@
     uint8_t mem_buf[2000];
     uint32_t *registers;
     target_ulong addr, len;
-    
+
 #ifdef DEBUG_GDB
     printf("command='%s'\n", line_buf);
 #endif
@@ -883,7 +911,9 @@
 #elif defined (TARGET_ARM)
             env->regs[15] = addr;
 #elif defined (TARGET_SH4)
-	    env->pc = addr;
+            env->pc = addr;
+#elif defined (TARGET_MIPS)
+            env->PC[env->current_tc] = addr;
 #endif
         }
 #ifdef CONFIG_USER_ONLY
@@ -894,7 +924,7 @@
 	return RS_IDLE;
     case 's':
         if (*p != '\0') {
-            addr = strtoul(p, (char **)&p, 16);
+            addr = strtoull(p, (char **)&p, 16);
 #if defined(TARGET_I386)
             env->eip = addr;
 #ifdef USE_KVM
@@ -908,7 +938,9 @@
 #elif defined (TARGET_ARM)
             env->regs[15] = addr;
 #elif defined (TARGET_SH4)
-	    env->pc = addr;
+            env->pc = addr;
+#elif defined (TARGET_MIPS)
+            env->PC[env->current_tc] = addr;
 #endif
         }
         cpu_single_step(env, 1);
@@ -1001,6 +1033,12 @@
             if (cpu_breakpoint_insert(env, addr) < 0)
                 goto breakpoint_error;
             put_packet(s, "OK");
+#ifndef CONFIG_USER_ONLY
+        } else if (type == 2) {
+            if (cpu_watchpoint_insert(env, addr) < 0)
+                goto breakpoint_error;
+            put_packet(s, "OK");
+#endif
         } else {
         breakpoint_error:
             put_packet(s, "E22");
@@ -1017,6 +1055,11 @@
         if (type == 0 || type == 1) {
             cpu_breakpoint_remove(env, addr);
             put_packet(s, "OK");
+#ifndef CONFIG_USER_ONLY
+        } else if (type == 2) {
+            cpu_watchpoint_remove(env, addr);
+            put_packet(s, "OK");
+#endif
         } else {
             goto breakpoint_error;
         }
@@ -1026,8 +1069,11 @@
         if (strncmp(p, "Offsets", 7) == 0) {
             TaskState *ts = env->opaque;
 
-            sprintf(buf, "Text=%x;Data=%x;Bss=%x", ts->info->code_offset,
-                ts->info->data_offset, ts->info->data_offset);
+            sprintf(buf,
+                    "Text=" TARGET_FMT_lx ";Data=" TARGET_FMT_lx ";Bss=" TARGET_FMT_lx,
+                    ts->info->code_offset,
+                    ts->info->data_offset,
+                    ts->info->data_offset);
             put_packet(s, buf);
             break;
         }
@@ -1059,6 +1105,14 @@
     cpu_single_step(s->env, 0);
 
     if (reason == EXCP_DEBUG) {
+        if (s->env->watchpoint_hit) {
+            snprintf(buf, sizeof(buf), "T%02xwatch:" TARGET_FMT_lx ";",
+                     SIGTRAP,
+                     s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr);
+            put_packet(s, buf);
+            s->env->watchpoint_hit = 0;
+            return;
+        }
 	tb_flush(s->env);
         ret = SIGTRAP;
     } else if (reason == EXCP_INTERRUPT) {
@@ -1073,14 +1127,16 @@
 
 /* Send a gdb syscall request.
    This accepts limited printf-style format specifiers, specifically:
-    %x - target_ulong argument printed in hex.
-    %s - string pointer (target_ulong) and length (int) pair.  */
+    %x  - target_ulong argument printed in hex.
+    %lx - 64-bit argument printed in hex.
+    %s  - string pointer (target_ulong) and length (int) pair.  */
 void gdb_do_syscall(gdb_syscall_complete_cb cb, char *fmt, ...)
 {
     va_list va;
     char buf[256];
     char *p;
     target_ulong addr;
+    uint64_t i64;
     GDBState *s;
 
     s = gdb_syscall_state;
@@ -1103,11 +1159,18 @@
                 addr = va_arg(va, target_ulong);
                 p += sprintf(p, TARGET_FMT_lx, addr);
                 break;
+            case 'l':
+                if (*(fmt++) != 'x')
+                    goto bad_format;
+                i64 = va_arg(va, uint64_t);
+                p += sprintf(p, "%" PRIx64, i64);
+                break;
             case 's':
                 addr = va_arg(va, target_ulong);
                 p += sprintf(p, TARGET_FMT_lx "/%x", addr, va_arg(va, int));
                 break;
             default:
+            bad_format:
                 fprintf(stderr, "gdbstub: Bad syscall format string '%s'\n",
                         fmt - 1);
                 break;
@@ -1116,6 +1179,7 @@
             *(p++) = *(fmt++);
         }
     }
+    *p = 0;
     va_end(va);
     put_packet(s, buf);
 #ifdef CONFIG_USER_ONLY
@@ -1156,7 +1220,7 @@
         /* when the CPU is running, we cannot do anything except stop
            it when receiving a char */
         vm_stop(EXCP_INTERRUPT);
-    } else 
+    } else
 #endif
     {
         switch(s->state) {
@@ -1284,7 +1348,7 @@
     /* set short latency */
     val = 1;
     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
-    
+
     s = &gdbserver_state;
     memset (s, 0, sizeof (GDBState));
     s->env = first_cpu; /* XXX: allow to change CPU */
@@ -1336,12 +1400,12 @@
     return 0;
 }
 #else
-static int gdb_chr_can_recieve(void *opaque)
+static int gdb_chr_can_receive(void *opaque)
 {
   return 1;
 }
 
-static void gdb_chr_recieve(void *opaque, const uint8_t *buf, int size)
+static void gdb_chr_receive(void *opaque, const uint8_t *buf, int size)
 {
     GDBState *s = opaque;
     int i;
@@ -1363,10 +1427,26 @@
     }
 }
 
-int gdbserver_start(CharDriverState *chr)
+int gdbserver_start(const char *port)
 {
     GDBState *s;
+    char gdbstub_port_name[128];
+    int port_num;
+    char *p;
+    CharDriverState *chr;
 
+    if (!port || !*port)
+      return -1;
+
+    port_num = strtol(port, &p, 10);
+    if (*p == 0) {
+        /* A numeric value is interpreted as a port number.  */
+        snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
+                 "tcp::%d,nowait,nodelay,server", port_num);
+        port = gdbstub_port_name;
+    }
+
+    chr = qemu_chr_open(port);
     if (!chr)
         return -1;
 
@@ -1376,23 +1456,9 @@
     }
     s->env = first_cpu; /* XXX: allow to change CPU */
     s->chr = chr;
-    qemu_chr_add_handlers(chr, gdb_chr_can_recieve, gdb_chr_recieve,
+    qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive,
                           gdb_chr_event, s);
     qemu_add_vm_stop_handler(gdb_vm_stopped, s);
     return 0;
 }
-
-int gdbserver_start_port(int port)
-{
-    CharDriverState *chr;
-    char gdbstub_port_name[128];
-
-    snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
-             "tcp::%d,nowait,nodelay,server", port);
-    chr = qemu_chr_open(gdbstub_port_name);
-    if (!chr) 
-        return -EIO;
-    return gdbserver_start(chr);
-}
-
 #endif
diff --git a/gdbstub.h b/gdbstub.h
index 41ffc6d..e1c9efb 100644
--- a/gdbstub.h
+++ b/gdbstub.h
@@ -1,7 +1,7 @@
 #ifndef GDBSTUB_H
 #define GDBSTUB_H
 
-#define DEFAULT_GDBSTUB_PORT 1234
+#define DEFAULT_GDBSTUB_PORT "1234"
 
 typedef void (*gdb_syscall_complete_cb)(CPUState *env,
                                         target_ulong ret, target_ulong err);
@@ -13,8 +13,7 @@
 void gdb_exit(CPUState *, int);
 int gdbserver_start(int);
 #else
-int gdbserver_start(CharDriverState *chr);
-int gdbserver_start_port(int port);
+int gdbserver_start(const char *port);
 #endif
 
 #endif
diff --git a/host-utils.c b/host-utils.c
new file mode 100644
index 0000000..1034106
--- /dev/null
+++ b/host-utils.c
@@ -0,0 +1,75 @@
+/*
+ * Utility compute operations used by translated code.
+ *
+ * Copyright (c) 2007 Aurelien Jarno
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+
+/* Signed 64x64 -> 128 multiplication */
+
+void muls64(int64_t *phigh, int64_t *plow, int64_t a, int64_t b)
+{
+#if defined(__x86_64__)
+    __asm__ ("imul %0\n\t"
+             : "=d" (*phigh), "=a" (*plow)
+             : "a" (a), "0" (b)
+             );
+#else
+    int64_t ph;
+    uint64_t pm1, pm2, pl;
+
+    pl = (uint64_t)((uint32_t)a) * (uint64_t)((uint32_t)b);
+    pm1 = (a >> 32) * (uint32_t)b;
+    pm2 = (uint32_t)a * (b >> 32);
+    ph = (a >> 32) * (b >> 32);
+
+    ph += (int64_t)pm1 >> 32;
+    pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32);
+
+    *phigh = ph + ((int64_t)pm1 >> 32);
+    *plow = (pm1 << 32) + (uint32_t)pl;
+#endif
+}
+
+/* Unsigned 64x64 -> 128 multiplication */
+void mulu64(uint64_t *phigh, uint64_t *plow, uint64_t a, uint64_t b)
+{
+#if defined(__x86_64__)
+    __asm__ ("mul %0\n\t"
+             : "=d" (*phigh), "=a" (*plow)
+             : "a" (a), "0" (b)
+            );
+#else
+    uint64_t ph, pm1, pm2, pl;
+
+    pl = (uint64_t)((uint32_t)a) * (uint64_t)((uint32_t)b);
+    pm1 = (a >> 32) * (uint32_t)b;
+    pm2 = (uint32_t)a * (b >> 32);
+    ph = (a >> 32) * (b >> 32);
+
+    ph += pm1 >> 32;
+    pm1 = (uint64_t)((uint32_t)pm1) + pm2 + (pl >> 32);
+
+    *phigh = ph + (pm1 >> 32);
+    *plow = (pm1 << 32) + (uint32_t)pl;
+#endif
+}
diff --git a/hpet.h b/hpet.h
new file mode 100644
index 0000000..754051a
--- /dev/null
+++ b/hpet.h
@@ -0,0 +1,22 @@
+#ifndef	__HPET__
+#define	__HPET__ 1
+
+
+
+struct hpet_info {
+	unsigned long hi_ireqfreq;	/* Hz */
+	unsigned long hi_flags;	/* information */
+	unsigned short hi_hpet;
+	unsigned short hi_timer;
+};
+
+#define	HPET_INFO_PERIODIC	0x0001	/* timer is periodic */
+
+#define	HPET_IE_ON	_IO('h', 0x01)	/* interrupt on */
+#define	HPET_IE_OFF	_IO('h', 0x02)	/* interrupt off */
+#define	HPET_INFO	_IOR('h', 0x03, struct hpet_info)
+#define	HPET_EPI	_IO('h', 0x04)	/* enable periodic */
+#define	HPET_DPI	_IO('h', 0x05)	/* disable periodic */
+#define	HPET_IRQFREQ	_IOW('h', 0x6, unsigned long)	/* IRQFREQ usec */
+
+#endif				/* !__HPET__ */
diff --git a/hw/acpi.c b/hw/acpi.c
index 78c4fea..37fadaa 100644
--- a/hw/acpi.c
+++ b/hw/acpi.c
@@ -1,8 +1,8 @@
 /*
  * ACPI implementation
- * 
+ *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License version 2 as published by the Free Software Foundation.
@@ -24,7 +24,6 @@
 #define PM_FREQ 3579545
 
 #define ACPI_DBG_IO_ADDR  0xb044
-#define SMB_IO_BASE       0xb100
 
 typedef struct PIIX4PMState {
     PCIDevice dev;
@@ -35,7 +34,7 @@
     uint8_t apms;
     QEMUTimer *tmr_timer;
     int64_t tmr_overflow_time;
-    SMBusDevice *smb_dev[128];
+    i2c_bus *smbus;
     uint8_t smb_stat;
     uint8_t smb_ctl;
     uint8_t smb_cmd;
@@ -55,6 +54,9 @@
 
 #define SUS_EN (1 << 13)
 
+#define ACPI_ENABLE 0xf1
+#define ACPI_DISABLE 0xf0
+
 #define SMBHSTSTS 0x00
 #define SMBHSTCNT 0x02
 #define SMBHSTCMD 0x03
@@ -63,9 +65,6 @@
 #define SMBHSTDAT1 0x06
 #define SMBBLKDAT 0x07
 
-/* Note: only used for piix4_smbus_register_device */
-static PIIX4PMState *piix4_pm_state;
-
 static uint32_t get_pmtmr(PIIX4PMState *s)
 {
     uint32_t d;
@@ -88,11 +87,11 @@
 {
     int sci_level, pmsts;
     int64_t expire_time;
-    
+
     pmsts = get_pmsts(s);
-    sci_level = (((pmsts & s->pmen) & 
+    sci_level = (((pmsts & s->pmen) &
                   (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
-    pci_set_irq(&s->dev, 0, sci_level);
+    qemu_set_irq(s->dev.irq[0], sci_level);
     /* schedule a timer interruption if needed */
     if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
         expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
@@ -220,6 +219,14 @@
 #endif
     if (addr == 0) {
         s->apmc = val;
+
+        /* ACPI specs 3.0, 4.7.2.5 */
+        if (val == ACPI_ENABLE) {
+            s->pmcntrl |= SCI_EN;
+        } else if (val == ACPI_DISABLE) {
+            s->pmcntrl &= ~SCI_EN;
+        }
+
         if (s->dev.config[0x5b] & (1 << 1)) {
             cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI);
         }
@@ -232,7 +239,7 @@
 {
     PIIX4PMState *s = opaque;
     uint32_t val;
-    
+
     addr &= 1;
     if (addr == 0) {
         val = s->apmc;
@@ -258,59 +265,44 @@
     uint8_t read = s->smb_addr & 0x01;
     uint8_t cmd = s->smb_cmd;
     uint8_t addr = s->smb_addr >> 1;
-    SMBusDevice *dev = s->smb_dev[addr];
+    i2c_bus *bus = s->smbus;
 
 #ifdef DEBUG
     printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
 #endif
-    if (!dev) goto error;
-
     switch(prot) {
     case 0x0:
-        if (!dev->quick_cmd) goto error;
-        (*dev->quick_cmd)(dev, read);
+        smbus_quick_command(bus, addr, read);
         break;
     case 0x1:
         if (read) {
-            if (!dev->receive_byte) goto error;
-            s->smb_data0 = (*dev->receive_byte)(dev);
-        }
-        else {
-            if (!dev->send_byte) goto error;
-            (*dev->send_byte)(dev, cmd);
+            s->smb_data0 = smbus_receive_byte(bus, addr);
+        } else {
+            smbus_send_byte(bus, addr, cmd);
         }
         break;
     case 0x2:
         if (read) {
-            if (!dev->read_byte) goto error;
-            s->smb_data0 = (*dev->read_byte)(dev, cmd);
-        }
-        else {
-            if (!dev->write_byte) goto error;
-            (*dev->write_byte)(dev, cmd, s->smb_data0);
+            s->smb_data0 = smbus_read_byte(bus, addr, cmd);
+        } else {
+            smbus_write_byte(bus, addr, cmd, s->smb_data0);
         }
         break;
     case 0x3:
         if (read) {
             uint16_t val;
-            if (!dev->read_word) goto error;
-            val = (*dev->read_word)(dev, cmd);
+            val = smbus_read_word(bus, addr, cmd);
             s->smb_data0 = val;
             s->smb_data1 = val >> 8;
-        }
-        else {
-            if (!dev->write_word) goto error;
-            (*dev->write_word)(dev, cmd, (s->smb_data1 << 8) | s->smb_data0);
+        } else {
+            smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
         }
         break;
     case 0x5:
         if (read) {
-            if (!dev->read_block) goto error;
-            s->smb_data0 = (*dev->read_block)(dev, cmd, s->smb_data);
-        }
-        else {
-            if (!dev->write_block) goto error;
-            (*dev->write_block)(dev, cmd, s->smb_data0, s->smb_data);
+            s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
+        } else {
+            smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
         }
         break;
     default:
@@ -421,7 +413,7 @@
     }
 }
 
-static void pm_write_config(PCIDevice *d, 
+static void pm_write_config(PCIDevice *d,
                             uint32_t address, uint32_t val, int len)
 {
     pci_default_write_config(d, address, val, len);
@@ -469,11 +461,10 @@
     return 0;
 }
 
-void piix4_pm_init(PCIBus *bus, int devfn)
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base)
 {
     PIIX4PMState *s;
     uint8_t *pci_conf;
-    uint32_t pm_io_base, smb_io_base;
 
     s = (PIIX4PMState *)pci_register_device(bus,
                                          "PM", sizeof(PIIX4PMState),
@@ -489,9 +480,9 @@
     pci_conf[0x0b] = 0x06; // bridge device
     pci_conf[0x0e] = 0x00; // header_type
     pci_conf[0x3d] = 0x01; // interrupt pin 1
-    
+
     pci_conf[0x40] = 0x01; /* PM io base read only bit */
-    
+
     register_ioport_write(0xb2, 2, 1, pm_smi_writeb, s);
     register_ioport_read(0xb2, 2, 1, pm_smi_readb, s);
 
@@ -504,7 +495,6 @@
     pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
 	(serial_hds[1] != NULL ? 0x90 : 0);
 
-    smb_io_base = SMB_IO_BASE;
     pci_conf[0x90] = smb_io_base | 1;
     pci_conf[0x91] = smb_io_base >> 8;
     pci_conf[0xd2] = 0x09;
@@ -514,10 +504,7 @@
     s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
 
     register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
-    piix4_pm_state = s;
-}
 
-void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr)
-{
-    piix4_pm_state->smb_dev[addr] = dev;
+    s->smbus = i2c_init_bus();
+    return s->smbus;
 }
diff --git a/hw/adb.c b/hw/adb.c
index 3f664a9..1e43792 100644
--- a/hw/adb.c
+++ b/hw/adb.c
@@ -1,8 +1,8 @@
 /*
  * QEMU ADB support
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -96,9 +96,9 @@
     return olen;
 }
 
-ADBDevice *adb_register_device(ADBBusState *s, int devaddr, 
-                               ADBDeviceRequest *devreq, 
-                               ADBDeviceReset *devreset, 
+ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
+                               ADBDeviceRequest *devreq,
+                               ADBDeviceReset *devreset,
                                void *opaque)
 {
     ADBDevice *d;
@@ -299,31 +299,31 @@
     if (s->last_buttons_state == s->buttons_state &&
         s->dx == 0 && s->dy == 0)
         return 0;
-        
+
     dx = s->dx;
     if (dx < -63)
         dx = -63;
     else if (dx > 63)
         dx = 63;
-    
+
     dy = s->dy;
     if (dy < -63)
         dy = -63;
     else if (dy > 63)
         dy = 63;
-    
+
     s->dx -= dx;
     s->dy -= dy;
     s->last_buttons_state = s->buttons_state;
-    
+
     dx &= 0x7f;
     dy &= 0x7f;
-    
+
     if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
         dy |= 0x80;
     if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
         dx |= 0x80;
-    
+
     obuf[0] = dy;
     obuf[1] = dx;
     return 2;
@@ -334,7 +334,7 @@
 {
     MouseState *s = d->opaque;
     int cmd, reg, olen;
-    
+
     if ((buf[0] & 0x0f) == ADB_FLUSH) {
         /* flush mouse fifo */
         s->buttons_state = s->last_buttons_state;
diff --git a/hw/adlib.c b/hw/adlib.c
index b47bc3e..805365e 100644
--- a/hw/adlib.c
+++ b/hw/adlib.c
@@ -267,7 +267,7 @@
     AUD_remove_card (&s->card);
 }
 
-int Adlib_init (AudioState *audio)
+int Adlib_init (AudioState *audio, qemu_irq *pic)
 {
     AdlibState *s = &glob_adlib;
     audsettings_t as;
diff --git a/hw/ads7846.c b/hw/ads7846.c
new file mode 100644
index 0000000..2f891b1
--- /dev/null
+++ b/hw/ads7846.c
@@ -0,0 +1,167 @@
+/*
+ * TI ADS7846 chip emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include <vl.h>
+
+struct ads7846_state_s {
+    qemu_irq interrupt;
+
+    int input[8];
+    int pressure;
+    int noise;
+
+    int cycle;
+    int output;
+};
+
+/* Control-byte bitfields */
+#define CB_PD0		(1 << 0)
+#define CB_PD1		(1 << 1)
+#define CB_SER		(1 << 2)
+#define CB_MODE		(1 << 3)
+#define CB_A0		(1 << 4)
+#define CB_A1		(1 << 5)
+#define CB_A2		(1 << 6)
+#define CB_START	(1 << 7)
+
+#define X_AXIS_DMAX	3470
+#define X_AXIS_MIN	290
+#define Y_AXIS_DMAX	3450
+#define Y_AXIS_MIN	200
+
+#define ADS_VBAT	2000
+#define ADS_VAUX	2000
+#define ADS_TEMP0	2000
+#define ADS_TEMP1	3000
+#define ADS_XPOS(x, y)	(X_AXIS_MIN + ((X_AXIS_DMAX * (x)) >> 15))
+#define ADS_YPOS(x, y)	(Y_AXIS_MIN + ((Y_AXIS_DMAX * (y)) >> 15))
+#define ADS_Z1POS(x, y)	600
+#define ADS_Z2POS(x, y)	(600 + 6000 / ADS_XPOS(x, y))
+
+static void ads7846_int_update(struct ads7846_state_s *s)
+{
+    if (s->interrupt)
+        qemu_set_irq(s->interrupt, s->pressure == 0);
+}
+
+uint32_t ads7846_read(void *opaque)
+{
+    struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
+
+    return s->output;
+}
+
+void ads7846_write(void *opaque, uint32_t value)
+{
+    struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
+
+    switch (s->cycle ++) {
+    case 0:
+        if (!(value & CB_START)) {
+            s->cycle = 0;
+            break;
+        }
+
+        s->output = s->input[(value >> 4) & 7];
+
+        /* Imitate the ADC noise, some drivers expect this.  */
+        s->noise = (s->noise + 3) & 7;
+        switch ((value >> 4) & 7) {
+        case 1: s->output += s->noise ^ 2; break;
+        case 3: s->output += s->noise ^ 0; break;
+        case 4: s->output += s->noise ^ 7; break;
+        case 5: s->output += s->noise ^ 5; break;
+        }
+
+        if (value & CB_MODE)
+            s->output >>= 4;	/* 8 bits instead of 12 */
+
+        break;
+    case 1:
+        s->cycle = 0;
+        break;
+    }
+}
+
+static void ads7846_ts_event(void *opaque,
+                int x, int y, int z, int buttons_state)
+{
+    struct ads7846_state_s *s = opaque;
+
+    if (buttons_state) {
+        x = 0x7fff - x;
+        s->input[1] = ADS_XPOS(x, y);
+        s->input[3] = ADS_Z1POS(x, y);
+        s->input[4] = ADS_Z2POS(x, y);
+        s->input[5] = ADS_YPOS(x, y);
+    }
+
+    if (s->pressure == !buttons_state) {
+        s->pressure = !!buttons_state;
+
+        ads7846_int_update(s);
+    }
+}
+
+static void ads7846_save(QEMUFile *f, void *opaque)
+{
+    struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 8; i ++)
+        qemu_put_be32(f, s->input[i]);
+    qemu_put_be32(f, s->noise);
+    qemu_put_be32(f, s->cycle);
+    qemu_put_be32(f, s->output);
+}
+
+static int ads7846_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct ads7846_state_s *s = (struct ads7846_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 8; i ++)
+        s->input[i] = qemu_get_be32(f);
+    s->noise = qemu_get_be32(f);
+    s->cycle = qemu_get_be32(f);
+    s->output = qemu_get_be32(f);
+
+    s->pressure = 0;
+    ads7846_int_update(s);
+
+    return 0;
+}
+
+static int ads7846_iid = 0;
+
+struct ads7846_state_s *ads7846_init(qemu_irq penirq)
+{
+    struct ads7846_state_s *s;
+    s = (struct ads7846_state_s *)
+            qemu_mallocz(sizeof(struct ads7846_state_s));
+    memset(s, 0, sizeof(struct ads7846_state_s));
+
+    s->interrupt = penirq;
+
+    s->input[0] = ADS_TEMP0;	/* TEMP0 */
+    s->input[2] = ADS_VBAT;	/* VBAT */
+    s->input[6] = ADS_VAUX;	/* VAUX */
+    s->input[7] = ADS_TEMP1;	/* TEMP1 */
+
+    /* We want absolute coordinates */
+    qemu_add_mouse_event_handler(ads7846_ts_event, s, 1,
+                    "QEMU ADS7846-driven Touchscreen");
+
+    ads7846_int_update(s);
+
+    register_savevm("ads7846", ads7846_iid ++, 0,
+                    ads7846_save, ads7846_load, s);
+
+    return s;
+}
diff --git a/hw/alpha_palcode.c b/hw/alpha_palcode.c
new file mode 100644
index 0000000..da2d9ad
--- /dev/null
+++ b/hw/alpha_palcode.c
@@ -0,0 +1,1099 @@
+/*
+ *  Alpha emulation - PALcode emulation for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "qemu.h"
+#include "cpu.h"
+#include "exec-all.h"
+
+#if !defined (CONFIG_USER_ONLY)
+/* Shared handlers */
+static void pal_reset (CPUState *env);
+/* Console handlers */
+static void pal_console_call (CPUState *env, uint32_t palcode);
+/* OpenVMS handlers */
+static void pal_openvms_call (CPUState *env, uint32_t palcode);
+/* UNIX / Linux handlers */
+static void pal_unix_call (CPUState *env, uint32_t palcode);
+
+pal_handler_t pal_handlers[] = {
+    /* Console handler */
+    {
+        .reset = &pal_reset,
+        .call_pal = &pal_console_call,
+    },
+    /* OpenVMS handler */
+    {
+        .reset = &pal_reset,
+        .call_pal = &pal_openvms_call,
+    },
+    /* UNIX / Linux handler */
+    {
+        .reset = &pal_reset,
+        .call_pal = &pal_unix_call,
+    },
+};
+
+#if 0
+/* One must explicitely check that the TB is valid and the FOE bit is reset */
+static void update_itb ()
+{
+    /* This writes into a temp register, not the actual one */
+    mtpr(TB_TAG);
+    mtpr(TB_CTL);
+    /* This commits the TB update */
+    mtpr(ITB_PTE);
+}
+
+static void update_dtb ();
+{
+    mtpr(TB_CTL);
+    /* This write into a temp register, not the actual one */
+    mtpr(TB_TAG);
+    /* This commits the TB update */
+    mtpr(DTB_PTE);
+}
+#endif
+
+static void pal_reset (CPUState *env)
+{
+}
+
+static void do_swappal (CPUState *env, uint64_t palid)
+{
+    pal_handler_t *pal_handler;
+    int status;
+
+    status = 0;
+    switch (palid) {
+    case 0 ... 2:
+        pal_handler = &pal_handlers[palid];
+        env->pal_handler = pal_handler;
+        env->ipr[IPR_PAL_BASE] = -1ULL;
+        (*pal_handler->reset)(env);
+        break;
+    case 3 ... 255:
+        /* Unknown identifier */
+        env->ir[0] = 1;
+        return;
+    default:
+        /* We were given the entry point address */
+        env->pal_handler = NULL;
+        env->ipr[IPR_PAL_BASE] = palid;
+        env->pc = env->ipr[IPR_PAL_BASE];
+        cpu_loop_exit();
+    }
+}
+
+static void pal_console_call (CPUState *env, uint32_t palcode)
+{
+    uint64_t palid;
+
+    if (palcode < 0x00000080) {
+        /* Privileged palcodes */
+        if (!(env->ps >> 3)) {
+            /* TODO: generate privilege exception */
+        }
+    }
+    switch (palcode) {
+    case 0x00000000:
+        /* HALT */
+        /* REQUIRED */
+        break;
+    case 0x00000001:
+        /* CFLUSH */
+        break;
+    case 0x00000002:
+        /* DRAINA */
+        /* REQUIRED */
+        /* Implemented as no-op */
+        break;
+    case 0x00000009:
+        /* CSERVE */
+        /* REQUIRED */
+        break;
+    case 0x0000000A:
+        /* SWPPAL */
+        /* REQUIRED */
+        palid = env->ir[16];
+        do_swappal(env, palid);
+        break;
+    case 0x00000080:
+        /* BPT */
+        /* REQUIRED */
+        break;
+    case 0x00000081:
+        /* BUGCHK */
+        /* REQUIRED */
+        break;
+    case 0x00000086:
+        /* IMB */
+        /* REQUIRED */
+        /* Implemented as no-op */
+        break;
+    case 0x0000009E:
+        /* RDUNIQUE */
+        /* REQUIRED */
+        break;
+    case 0x0000009F:
+        /* WRUNIQUE */
+        /* REQUIRED */
+        break;
+    case 0x000000AA:
+        /* GENTRAP */
+        /* REQUIRED */
+        break;
+    default:
+        break;
+    }
+}
+
+static void pal_openvms_call (CPUState *env, uint32_t palcode)
+{
+    uint64_t palid, val, oldval;
+
+    if (palcode < 0x00000080) {
+        /* Privileged palcodes */
+        if (!(env->ps >> 3)) {
+            /* TODO: generate privilege exception */
+        }
+    }
+    switch (palcode) {
+    case 0x00000000:
+        /* HALT */
+        /* REQUIRED */
+        break;
+    case 0x00000001:
+        /* CFLUSH */
+        break;
+    case 0x00000002:
+        /* DRAINA */
+        /* REQUIRED */
+        /* Implemented as no-op */
+        break;
+    case 0x00000003:
+        /* LDQP */
+        break;
+    case 0x00000004:
+        /* STQP */
+        break;
+    case 0x00000005:
+        /* SWPCTX */
+        break;
+    case 0x00000006:
+        /* MFPR_ASN */
+        if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000007:
+        /* MTPR_ASTEN */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000008:
+        /* MTPR_ASTSR */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000009:
+        /* CSERVE */
+        /* REQUIRED */
+        break;
+    case 0x0000000A:
+        /* SWPPAL */
+        /* REQUIRED */
+        palid = env->ir[16];
+        do_swappal(env, palid);
+        break;
+    case 0x0000000B:
+        /* MFPR_FEN */
+        if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x0000000C:
+        /* MTPR_FEN */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000000D:
+        /* MTPR_IPIR */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000000E:
+        /* MFPR_IPL */
+        if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x0000000F:
+        /* MTPR_IPL */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000010:
+        /* MFPR_MCES */
+        if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000011:
+        /* MTPR_MCES */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000012:
+        /* MFPR_PCBB */
+        if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000013:
+        /* MFPR_PRBR */
+        if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000014:
+        /* MTPR_PRBR */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000015:
+        /* MFPR_PTBR */
+        if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000016:
+        /* MFPR_SCBB */
+        if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000017:
+        /* MTPR_SCBB */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000018:
+        /* MTPR_SIRR */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000019:
+        /* MFPR_SISR */
+        if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x0000001A:
+        /* MFPR_TBCHK */
+        if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x0000001B:
+        /* MTPR_TBIA */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000001C:
+        /* MTPR_TBIAP */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000001D:
+        /* MTPR_TBIS */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000001E:
+        /* MFPR_ESP */
+        if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x0000001F:
+        /* MTPR_ESP */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000020:
+        /* MFPR_SSP */
+        if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000021:
+        /* MTPR_SSP */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000022:
+        /* MFPR_USP */
+        if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000023:
+        /* MTPR_USP */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000024:
+        /* MTPR_TBISD */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000025:
+        /* MTPR_TBISI */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000026:
+        /* MFPR_ASTEN */
+        if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000027:
+        /* MFPR_ASTSR */
+        if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000029:
+        /* MFPR_VPTB */
+        if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x0000002A:
+        /* MTPR_VPTB */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000002B:
+        /* MTPR_PERFMON */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000002E:
+        /* MTPR_DATFX */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000003E:
+        /* WTINT */
+        break;
+    case 0x0000003F:
+        /* MFPR_WHAMI */
+        if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000080:
+        /* BPT */
+        /* REQUIRED */
+        break;
+    case 0x00000081:
+        /* BUGCHK */
+        /* REQUIRED */
+        break;
+    case 0x00000082:
+        /* CHME */
+        break;
+    case 0x00000083:
+        /* CHMK */
+        break;
+    case 0x00000084:
+        /* CHMS */
+        break;
+    case 0x00000085:
+        /* CHMU */
+        break;
+    case 0x00000086:
+        /* IMB */
+        /* REQUIRED */
+        /* Implemented as no-op */
+        break;
+    case 0x00000087:
+        /* INSQHIL */
+        break;
+    case 0x00000088:
+        /* INSQTIL */
+        break;
+    case 0x00000089:
+        /* INSQHIQ */
+        break;
+    case 0x0000008A:
+        /* INSQTIQ */
+        break;
+    case 0x0000008B:
+        /* INSQUEL */
+        break;
+    case 0x0000008C:
+        /* INSQUEQ */
+        break;
+    case 0x0000008D:
+        /* INSQUEL/D */
+        break;
+    case 0x0000008E:
+        /* INSQUEQ/D */
+        break;
+    case 0x0000008F:
+        /* PROBER */
+        break;
+    case 0x00000090:
+        /* PROBEW */
+        break;
+    case 0x00000091:
+        /* RD_PS */
+        break;
+    case 0x00000092:
+        /* REI */
+        break;
+    case 0x00000093:
+        /* REMQHIL */
+        break;
+    case 0x00000094:
+        /* REMQTIL */
+        break;
+    case 0x00000095:
+        /* REMQHIQ */
+        break;
+    case 0x00000096:
+        /* REMQTIQ */
+        break;
+    case 0x00000097:
+        /* REMQUEL */
+        break;
+    case 0x00000098:
+        /* REMQUEQ */
+        break;
+    case 0x00000099:
+        /* REMQUEL/D */
+        break;
+    case 0x0000009A:
+        /* REMQUEQ/D */
+        break;
+    case 0x0000009B:
+        /* SWASTEN */
+        break;
+    case 0x0000009C:
+        /* WR_PS_SW */
+        break;
+    case 0x0000009D:
+        /* RSCC */
+        break;
+    case 0x0000009E:
+        /* READ_UNQ */
+        /* REQUIRED */
+        break;
+    case 0x0000009F:
+        /* WRITE_UNQ */
+        /* REQUIRED */
+        break;
+    case 0x000000A0:
+        /* AMOVRR */
+        break;
+    case 0x000000A1:
+        /* AMOVRM */
+        break;
+    case 0x000000A2:
+        /* INSQHILR */
+        break;
+    case 0x000000A3:
+        /* INSQTILR */
+        break;
+    case 0x000000A4:
+        /* INSQHIQR */
+        break;
+    case 0x000000A5:
+        /* INSQTIQR */
+        break;
+    case 0x000000A6:
+        /* REMQHILR */
+        break;
+    case 0x000000A7:
+        /* REMQTILR */
+        break;
+    case 0x000000A8:
+        /* REMQHIQR */
+        break;
+    case 0x000000A9:
+        /* REMQTIQR */
+        break;
+    case 0x000000AA:
+        /* GENTRAP */
+        /* REQUIRED */
+        break;
+    case 0x000000AE:
+        /* CLRFEN */
+        break;
+    default:
+        break;
+    }
+}
+
+static void pal_unix_call (CPUState *env, uint32_t palcode)
+{
+    uint64_t palid, val, oldval;
+
+    if (palcode < 0x00000080) {
+        /* Privileged palcodes */
+        if (!(env->ps >> 3)) {
+            /* TODO: generate privilege exception */
+        }
+    }
+    switch (palcode) {
+    case 0x00000000:
+        /* HALT */
+        /* REQUIRED */
+        break;
+    case 0x00000001:
+        /* CFLUSH */
+        break;
+    case 0x00000002:
+        /* DRAINA */
+        /* REQUIRED */
+        /* Implemented as no-op */
+        break;
+    case 0x00000009:
+        /* CSERVE */
+        /* REQUIRED */
+        break;
+    case 0x0000000A:
+        /* SWPPAL */
+        /* REQUIRED */
+        palid = env->ir[16];
+        do_swappal(env, palid);
+        break;
+    case 0x0000000D:
+        /* WRIPIR */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000010:
+        /* RDMCES */
+        if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000011:
+        /* WRMCES */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000002B:
+        /* WRFEN */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000002D:
+        /* WRVPTPTR */
+        break;
+    case 0x00000030:
+        /* SWPCTX */
+        break;
+    case 0x00000031:
+        /* WRVAL */
+        break;
+    case 0x00000032:
+        /* RDVAL */
+        break;
+    case 0x00000033:
+        /* TBI */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000034:
+        /* WRENT */
+        break;
+    case 0x00000035:
+        /* SWPIPL */
+        break;
+    case 0x00000036:
+        /* RDPS */
+        break;
+    case 0x00000037:
+        /* WRKGP */
+        break;
+    case 0x00000038:
+        /* WRUSP */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x00000039:
+        /* WRPERFMON */
+        val = env->ir[16];
+        if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
+            env->ir[0] = val;
+        break;
+    case 0x0000003A:
+        /* RDUSP */
+        if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x0000003C:
+        /* WHAMI */
+        if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x0000003D:
+        /* RETSYS */
+        break;
+    case 0x0000003E:
+        /* WTINT */
+        break;
+    case 0x0000003F:
+        /* RTI */
+        if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
+            env->ir[0] = val;
+        break;
+    case 0x00000080:
+        /* BPT */
+        /* REQUIRED */
+        break;
+    case 0x00000081:
+        /* BUGCHK */
+        /* REQUIRED */
+        break;
+    case 0x00000083:
+        /* CALLSYS */
+        break;
+    case 0x00000086:
+        /* IMB */
+        /* REQUIRED */
+        /* Implemented as no-op */
+        break;
+    case 0x00000092:
+        /* URTI */
+        break;
+    case 0x0000009E:
+        /* RDUNIQUE */
+        /* REQUIRED */
+        break;
+    case 0x0000009F:
+        /* WRUNIQUE */
+        /* REQUIRED */
+        break;
+    case 0x000000AA:
+        /* GENTRAP */
+        /* REQUIRED */
+        break;
+    case 0x000000AE:
+        /* CLRFEN */
+        break;
+    default:
+        break;
+    }
+}
+
+void call_pal (CPUState *env)
+{
+    pal_handler_t *pal_handler = env->pal_handler;
+
+    switch (env->exception_index) {
+    case EXCP_RESET:
+        (*pal_handler->reset)(env);
+        break;
+    case EXCP_MCHK:
+        (*pal_handler->machine_check)(env);
+        break;
+    case EXCP_ARITH:
+        (*pal_handler->arithmetic)(env);
+        break;
+    case EXCP_INTERRUPT:
+        (*pal_handler->interrupt)(env);
+        break;
+    case EXCP_DFAULT:
+        (*pal_handler->dfault)(env);
+        break;
+    case EXCP_DTB_MISS_PAL:
+        (*pal_handler->dtb_miss_pal)(env);
+        break;
+    case EXCP_DTB_MISS_NATIVE:
+        (*pal_handler->dtb_miss_native)(env);
+        break;
+    case EXCP_UNALIGN:
+        (*pal_handler->unalign)(env);
+        break;
+    case EXCP_ITB_MISS:
+        (*pal_handler->itb_miss)(env);
+        break;
+    case EXCP_ITB_ACV:
+        (*pal_handler->itb_acv)(env);
+        break;
+    case EXCP_OPCDEC:
+        (*pal_handler->opcdec)(env);
+        break;
+    case EXCP_FEN:
+        (*pal_handler->fen)(env);
+        break;
+    default:
+        if (env->exception_index >= EXCP_CALL_PAL &&
+            env->exception_index < EXCP_CALL_PALP) {
+            /* Unprivileged PAL call */
+            (*pal_handler->call_pal)
+                (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
+        } else if (env->exception_index >= EXCP_CALL_PALP &&
+                   env->exception_index < EXCP_CALL_PALE) {
+            /* Privileged PAL call */
+            (*pal_handler->call_pal)
+                (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
+        } else {
+            /* Should never happen */
+        }
+        break;
+    }
+    env->ipr[IPR_EXC_ADDR] &= ~1;
+}
+
+void pal_init (CPUState *env)
+{
+    do_swappal(env, 0);
+}
+
+#if 0
+static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
+{
+    uint64_t virbnd, ptbr;
+
+    if ((env->features & FEATURE_VIRBND)) {
+        cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
+        if (vaddr >= virbnd)
+            cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
+        else
+            cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
+    } else {
+        cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
+    }
+
+    return ptbr;
+}
+
+static int get_page_bits (CPUState *env)
+{
+    /* XXX */
+    return 13;
+}
+
+static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
+                    uint64_t ptebase, int page_bits, uint64_t level,
+                    int is_user, int rw)
+{
+    uint64_t pteaddr, pte, pfn;
+    uint8_t gh;
+    int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar;
+
+    pteaddr = (ptebase << page_bits) + (8 * level);
+    pte = ldq_raw(pteaddr);
+    /* Decode all interresting PTE fields */
+    pfn = pte >> 32;
+    uwe = (pte >> 13) & 1;
+    kwe = (pte >> 12) & 1;
+    ure = (pte >> 9) & 1;
+    kre = (pte >> 8) & 1;
+    gh = (pte >> 5) & 3;
+    foE = (pte >> 3) & 1;
+    foW = (pte >> 2) & 1;
+    foR = (pte >> 1) & 1;
+    v = pte & 1;
+    ret = 0;
+    if (!v)
+        ret = 0x1;
+    /* Check access rights */
+    ar = 0;
+    if (is_user) {
+        if (ure)
+            ar |= PAGE_READ;
+        if (uwe)
+            ar |= PAGE_WRITE;
+        if (rw == 1 && !uwe)
+            ret |= 0x2;
+        if (rw != 1 && !ure)
+            ret |= 0x2;
+    } else {
+        if (kre)
+            ar |= PAGE_READ;
+        if (kwe)
+            ar |= PAGE_WRITE;
+        if (rw == 1 && !kwe)
+            ret |= 0x2;
+        if (rw != 1 && !kre)
+            ret |= 0x2;
+    }
+    if (rw == 0 && foR)
+        ret |= 0x4;
+    if (rw == 2 && foE)
+        ret |= 0x8;
+    if (rw == 1 && foW)
+        ret |= 0xC;
+    *pfnp = pfn;
+    if (zbitsp != NULL)
+        *zbitsp = page_bits + (3 * gh);
+    if (protp != NULL)
+        *protp = ar;
+
+    return ret;
+}
+
+static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
+                           uint64_t ptebase, int page_bits,
+                           uint64_t vaddr, int is_user, int rw)
+{
+    uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
+    int lvl_bits, ret;
+
+    page_mask = (1ULL << page_bits) - 1ULL;
+    lvl_bits = page_bits - 3;
+    lvl_mask = (1ULL << lvl_bits) - 1ULL;
+    level3 = (vaddr >> page_bits) & lvl_mask;
+    level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
+    level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
+    /* Level 1 PTE */
+    ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
+    switch (ret) {
+    case 3:
+        /* Access violation */
+        return 2;
+    case 2:
+        /* translation not valid */
+        return 1;
+    default:
+        /* OK */
+        break;
+    }
+    /* Level 2 PTE */
+    ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
+    switch (ret) {
+    case 3:
+        /* Access violation */
+        return 2;
+    case 2:
+        /* translation not valid */
+        return 1;
+    default:
+        /* OK */
+        break;
+    }
+    /* Level 3 PTE */
+    ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, is_user, rw);
+    if (ret & 0x1) {
+        /* Translation not valid */
+        ret = 1;
+    } else if (ret & 2) {
+        /* Access violation */
+        ret = 2;
+    } else {
+        switch (ret & 0xC) {
+        case 0:
+            /* OK */
+            ret = 0;
+            break;
+        case 0x4:
+            /* Fault on read */
+            ret = 3;
+            break;
+        case 0x8:
+            /* Fault on execute */
+            ret = 4;
+            break;
+        case 0xC:
+            /* Fault on write */
+            ret = 5;
+            break;
+        }
+    }
+    *paddr = (pfn << page_bits) | (vaddr & page_mask);
+
+    return 0;
+}
+
+static int virtual_to_physical (CPUState *env, uint64_t *physp,
+                                int *zbitsp, int *protp,
+                                uint64_t virtual, int is_user, int rw)
+{
+    uint64_t sva, ptebase;
+    int seg, page_bits, ret;
+
+    sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
+    if (sva != virtual)
+        seg = -1;
+    else
+        seg = sva >> (VA_BITS - 2);
+    virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
+    ptebase = get_ptebase(env, virtual);
+    page_bits = get_page_bits(env);
+    ret = 0;
+    switch (seg) {
+    case 0:
+        /* seg1: 3 levels of PTE */
+        ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
+                             virtual, is_user, rw);
+        break;
+    case 1:
+        /* seg1: 2 levels of PTE */
+        ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
+                             virtual, is_user, rw);
+        break;
+    case 2:
+        /* kernel segment */
+        if (is_user) {
+            ret = 2;
+        } else {
+            *physp = virtual;
+        }
+        break;
+    case 3:
+        /* seg1: TB mapped */
+        ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
+                             virtual, is_user, rw);
+        break;
+    default:
+        ret = 1;
+        break;
+    }
+
+    return ret;
+}
+
+/* XXX: code provision */
+int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+                              int is_user, int is_softmmu)
+{
+    uint64_t physical, page_size, end;
+    int prot, zbits, ret;
+
+    if (env->user_mode_only) {
+        ret = 2;
+    } else {
+        ret = virtual_to_physical(env, &physical, &zbits, &prot,
+                                  address, is_user, rw);
+    }
+    switch (ret) {
+    case 0:
+        /* No fault */
+        page_size = 1ULL << zbits;
+        address &= ~(page_size - 1);
+        for (end = physical + page_size; physical < end; physical += 0x1000) {
+            ret = tlb_set_page(env, address, physical, prot,
+                               is_user, is_softmmu);
+            address += 0x1000;
+        }
+        break;
+#if 0
+    case 1:
+        env->exception_index = EXCP_DFAULT;
+        env->ipr[IPR_EXC_ADDR] = address;
+        ret = 1;
+        break;
+    case 2:
+        env->exception_index = EXCP_ACCESS_VIOLATION;
+        env->ipr[IPR_EXC_ADDR] = address;
+        ret = 1;
+        break;
+    case 3:
+        env->exception_index = EXCP_FAULT_ON_READ;
+        env->ipr[IPR_EXC_ADDR] = address;
+        ret = 1;
+        break;
+    case 4:
+        env->exception_index = EXCP_FAULT_ON_EXECUTE;
+        env->ipr[IPR_EXC_ADDR] = address;
+        ret = 1;
+    case 5:
+        env->exception_index = EXCP_FAULT_ON_WRITE;
+        env->ipr[IPR_EXC_ADDR] = address;
+        ret = 1;
+#endif
+    default:
+        /* Should never happen */
+        env->exception_index = EXCP_MCHK;
+        env->ipr[IPR_EXC_ADDR] = address;
+        ret = 1;
+        break;
+    }
+
+    return ret;
+}
+#endif
+
+#else /* !defined (CONFIG_USER_ONLY) */
+void pal_init (CPUState *env)
+{
+}
+
+void call_pal (CPUState *env, int palcode)
+{
+    target_ulong ret;
+
+    printf("%s: palcode %02x\n", __func__, palcode);
+    if (logfile != NULL)
+        fprintf(logfile, "%s: palcode %02x\n", __func__, palcode);
+    switch (palcode) {
+    case 0x83:
+        /* CALLSYS */
+        printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
+        if (logfile != NULL)
+            fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
+        ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
+                         env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
+                         env->ir[IR_A5]);
+        env->ir[IR_A3] = ret;
+        if (ret > (target_ulong)(-515)) {
+            env->ir[IR_V0] = 1;
+        } else {
+            env->ir[IR_V0] = 0;
+        }
+        break;
+    case 0x9E:
+        /* RDUNIQUE */
+        env->ir[IR_V0] = env->unique;
+        printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
+        break;
+    case 0x9F:
+        /* WRUNIQUE */
+        env->unique = env->ir[IR_A0];
+        printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
+        break;
+    default:
+        printf("%s: unhandled palcode %02x\n", __func__, palcode);
+        if (logfile != NULL)
+            fprintf(logfile, "%s: unhandled palcode %02x\n",
+                    __func__, palcode);
+        exit(1);
+    }
+}
+#endif
diff --git a/hw/an5206.c b/hw/an5206.c
new file mode 100644
index 0000000..94ecccb
--- /dev/null
+++ b/hw/an5206.c
@@ -0,0 +1,91 @@
+/*
+ * 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";
+    if (cpu_m68k_set_model(env, cpu_model)) {
+        cpu_abort(env, "Unable to find m68k CPU definition\n");
+    }
+
+    /* 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,
+};
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index a5fe9b9..1de3353 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -2,7 +2,7 @@
  * QEMU Ultrasparc APB PCI host
  *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -200,19 +200,19 @@
     return bus_offset + irq_num;
 }
 
-static void pci_apb_set_irq(void *pic, int irq_num, int level)
+static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level)
 {
     /* PCI IRQ map onto the first 32 INO.  */
-    pic_set_irq_new(pic, irq_num, level);
+    qemu_set_irq(pic[irq_num], level);
 }
 
-PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
-                     void *pic)
+PCIBus *pci_apb_init(target_phys_addr_t special_base,
+                     target_phys_addr_t mem_base,
+                     qemu_irq *pic)
 {
     APBState *s;
     PCIDevice *d;
     int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
-    PCIDevice *apb;
     PCIBus *secondary;
 
     s = qemu_mallocz(sizeof(APBState));
@@ -233,7 +233,7 @@
     cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
     cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
 
-    d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice), 
+    d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
                             0, NULL, NULL);
     d->config[0x00] = 0x8e; // vendor_id : Sun
     d->config[0x01] = 0x10;
diff --git a/hw/apic.c b/hw/apic.c
index f479061..62bd2ea 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -1,6 +1,6 @@
 /*
  *  APIC support
- * 
+ *
  *  Copyright (c) 2004-2005 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -189,7 +189,7 @@
     }\
 }
 
-static void apic_bus_deliver(const uint32_t *deliver_bitmask, 
+static void apic_bus_deliver(const uint32_t *deliver_bitmask,
                              uint8_t delivery_mode,
                              uint8_t vector_num, uint8_t polarity,
                              uint8_t trigger_mode)
@@ -226,10 +226,10 @@
 
         case APIC_DM_INIT:
             /* normal INIT IPI sent to processors */
-            foreach_apic(apic_iter, deliver_bitmask, 
+            foreach_apic(apic_iter, deliver_bitmask,
                          apic_init_ipi(apic_iter) );
             return;
-    
+
         case APIC_DM_EXTINT:
             /* handled in I/O APIC code */
             break;
@@ -238,7 +238,7 @@
             return;
     }
 
-    foreach_apic(apic_iter, deliver_bitmask, 
+    foreach_apic(apic_iter, deliver_bitmask,
                  apic_set_irq(apic_iter, vector_num, trigger_mode) );
 }
 
@@ -248,7 +248,7 @@
 #ifdef DEBUG_APIC
     printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
 #endif
-    s->apicbase = (val & 0xfffff000) | 
+    s->apicbase = (val & 0xfffff000) |
         (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
     /* if disabled, cannot be enabled again */
     if (!(val & MSR_IA32_APICBASE_ENABLE)) {
@@ -419,7 +419,7 @@
     if (!(env->hflags & HF_HALTED_MASK))
         return;
     env->eip = 0;
-    cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12, 
+    cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
                            0xffff, 0);
     env->hflags &= ~HF_HALTED_MASK;
 #if USE_KVM
@@ -459,7 +459,7 @@
                 int trig_mode = (s->icr[0] >> 15) & 1;
                 int level = (s->icr[0] >> 14) & 1;
                 if (level == 0 && trig_mode == 1) {
-                    foreach_apic(apic_iter, deliver_bitmask, 
+                    foreach_apic(apic_iter, deliver_bitmask,
                                  apic_iter->arb_id = apic_iter->id );
                     return;
                 }
@@ -467,7 +467,7 @@
             break;
 
         case APIC_DM_SIPI:
-            foreach_apic(apic_iter, deliver_bitmask, 
+            foreach_apic(apic_iter, deliver_bitmask,
                          apic_startup(apic_iter, vector_num) );
             return;
     }
@@ -487,7 +487,7 @@
         return -1;
     if (!(s->spurious_vec & APIC_SV_ENABLE))
         return -1;
-    
+
     /* XXX: spurious IRQ handling */
     intno = get_highest_priority_int(s->irr);
     if (intno < 0)
@@ -523,7 +523,7 @@
 {
     int64_t d;
     uint32_t val;
-    d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >> 
+    d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
         s->count_shift;
     if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
         /* periodic */
@@ -540,9 +540,9 @@
 static void apic_timer_update(APICState *s, int64_t current_time)
 {
     int64_t next_time, d;
-    
+
     if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
-        d = (current_time - s->initial_count_load_time) >> 
+        d = (current_time - s->initial_count_load_time) >>
             s->count_shift;
         if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
             d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
@@ -946,8 +946,9 @@
     env->apic_state = s;
     apic_init_ipi(s);
     s->id = last_apic_id++;
+    env->cpuid_apic_id = s->id;
     s->cpu_env = env;
-    s->apicbase = 0xfee00000 | 
+    s->apicbase = 0xfee00000 |
         (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
 
     /*
@@ -961,7 +962,7 @@
     if (apic_io_memory == 0) {
         /* NOTE: the APIC is directly connected to the CPU - it is not
            on the global memory bus. */
-        apic_io_memory = cpu_register_io_memory(0, apic_mem_read, 
+        apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
                                                 apic_mem_write, NULL);
         cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
                                      apic_io_memory);
@@ -970,7 +971,7 @@
 
     register_savevm("apic", s->id, 2, apic_save, apic_load, s);
     qemu_register_reset(apic_reset, s);
-    
+
     local_apics[s->id] = s;
     return 0;
 }
@@ -1004,9 +1005,9 @@
                     vector = pic_read_irq(isa_pic);
                 else
                     vector = entry & 0xff;
-                
+
                 apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
-                apic_bus_deliver(deliver_bitmask, delivery_mode, 
+                apic_bus_deliver(deliver_bitmask, delivery_mode,
                                  vector, polarity, trig_mode);
             }
         }
@@ -1222,12 +1223,12 @@
     ioapic_reset(s);
     s->id = last_apic_id++;
 
-    io_memory = cpu_register_io_memory(0, ioapic_mem_read, 
+    io_memory = cpu_register_io_memory(0, ioapic_mem_read,
                                        ioapic_mem_write, s);
     cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
 
     register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
     qemu_register_reset(ioapic_reset, s);
-    
+
     return s;
 }
diff --git a/hw/arm_boot.c b/hw/arm_boot.c
index 28f6a92..7a99b41 100644
--- a/hw/arm_boot.c
+++ b/hw/arm_boot.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * ARM kernel loader.
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -24,8 +24,20 @@
   0  /* Kernel entry point.  Set by integratorcp_init.  */
 };
 
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_reset(env);
+    if (env->kernel_filename)
+        arm_load_kernel(env, env->ram_size, env->kernel_filename,
+                        env->kernel_cmdline, env->initrd_filename,
+                        env->board_id, env->loader_start);
+}
+
 static void set_kernel_args(uint32_t ram_size, int initrd_size,
-                            const char *kernel_cmdline)
+                            const char *kernel_cmdline,
+                            target_phys_addr_t loader_start)
 {
     uint32_t *p;
 
@@ -40,12 +52,12 @@
     stl_raw(p++, 4);
     stl_raw(p++, 0x54410002);
     stl_raw(p++, ram_size);
-    stl_raw(p++, 0);
+    stl_raw(p++, loader_start);
     if (initrd_size) {
         /* ATAG_INITRD2 */
         stl_raw(p++, 4);
         stl_raw(p++, 0x54420005);
-        stl_raw(p++, INITRD_LOAD_ADDR);
+        stl_raw(p++, loader_start + INITRD_LOAD_ADDR);
         stl_raw(p++, initrd_size);
     }
     if (kernel_cmdline && *kernel_cmdline) {
@@ -64,14 +76,87 @@
     stl_raw(p++, 0);
 }
 
+static void set_kernel_args_old(uint32_t ram_size, int initrd_size,
+                                const char *kernel_cmdline,
+                                target_phys_addr_t loader_start)
+{
+    uint32_t *p;
+    unsigned char *s;
+
+    /* see linux/include/asm-arm/setup.h */
+    p = (uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR);
+    /* page_size */
+    stl_raw(p++, 4096);
+    /* nr_pages */
+    stl_raw(p++, ram_size / 4096);
+    /* ramdisk_size */
+    stl_raw(p++, 0);
+#define FLAG_READONLY	1
+#define FLAG_RDLOAD	4
+#define FLAG_RDPROMPT	8
+    /* flags */
+    stl_raw(p++, FLAG_READONLY | FLAG_RDLOAD | FLAG_RDPROMPT);
+    /* rootdev */
+    stl_raw(p++, (31 << 8) | 0);	/* /dev/mtdblock0 */
+    /* video_num_cols */
+    stl_raw(p++, 0);
+    /* video_num_rows */
+    stl_raw(p++, 0);
+    /* video_x */
+    stl_raw(p++, 0);
+    /* video_y */
+    stl_raw(p++, 0);
+    /* memc_control_reg */
+    stl_raw(p++, 0);
+    /* unsigned char sounddefault */
+    /* unsigned char adfsdrives */
+    /* unsigned char bytes_per_char_h */
+    /* unsigned char bytes_per_char_v */
+    stl_raw(p++, 0);
+    /* pages_in_bank[4] */
+    stl_raw(p++, 0);
+    stl_raw(p++, 0);
+    stl_raw(p++, 0);
+    stl_raw(p++, 0);
+    /* pages_in_vram */
+    stl_raw(p++, 0);
+    /* initrd_start */
+    if (initrd_size)
+        stl_raw(p++, loader_start + INITRD_LOAD_ADDR);
+    else
+        stl_raw(p++, 0);
+    /* initrd_size */
+    stl_raw(p++, initrd_size);
+    /* rd_start */
+    stl_raw(p++, 0);
+    /* system_rev */
+    stl_raw(p++, 0);
+    /* system_serial_low */
+    stl_raw(p++, 0);
+    /* system_serial_high */
+    stl_raw(p++, 0);
+    /* mem_fclk_21285 */
+    stl_raw(p++, 0);
+    /* zero unused fields */
+    memset(p, 0, 256 + 1024 -
+           (p - ((uint32_t *)(phys_ram_base + KERNEL_ARGS_ADDR))));
+    s = phys_ram_base + KERNEL_ARGS_ADDR + 256 + 1024;
+    if (kernel_cmdline)
+        strcpy (s, kernel_cmdline);
+    else
+        stb_raw(s, 0);
+}
+
 void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
                      const char *kernel_cmdline, const char *initrd_filename,
-                     int board_id)
+                     int board_id, target_phys_addr_t loader_start)
 {
     int kernel_size;
     int initrd_size;
     int n;
-    uint64_t entry;
+    int is_linux = 0;
+    uint64_t elf_entry;
+    target_ulong entry;
 
     /* Load the kernel.  */
     if (!kernel_filename) {
@@ -79,19 +164,36 @@
         exit(1);
     }
 
-    kernel_size = load_elf(kernel_filename, 0, &entry);
-    if (kernel_size >= 0) {
-        /* An ELF image.  Jump to the entry point.  */
+    if (!env->kernel_filename) {
+        env->ram_size = ram_size;
+        env->kernel_filename = kernel_filename;
+        env->kernel_cmdline = kernel_cmdline;
+        env->initrd_filename = initrd_filename;
+        env->board_id = board_id;
+        env->loader_start = loader_start;
+        qemu_register_reset(main_cpu_reset, env);
+    }
+    /* Assume that raw images are linux kernels, and ELF images are not.  */
+    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, &is_linux);
+    }
+    if (kernel_size < 0) {
+        kernel_size = load_image(kernel_filename,
+                                 phys_ram_base + KERNEL_LOAD_ADDR);
+        entry = loader_start + KERNEL_LOAD_ADDR;
+        is_linux = 1;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+        exit(1);
+    }
+    if (!is_linux) {
+        /* Jump to the entry point.  */
         env->regs[15] = entry & 0xfffffffe;
         env->thumb = entry & 1;
     } else {
-        /* Raw binary image. Assume it is a Linux zImage.  */
-        kernel_size = load_image(kernel_filename,
-                                 phys_ram_base + KERNEL_LOAD_ADDR);
-        if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
-            exit(1);
-        }
         if (initrd_filename) {
             initrd_size = load_image(initrd_filename,
                                      phys_ram_base + INITRD_LOAD_ADDR);
@@ -105,11 +207,15 @@
         }
         bootloader[1] |= board_id & 0xff;
         bootloader[2] |= (board_id >> 8) & 0xff;
-        bootloader[5] = KERNEL_ARGS_ADDR;
-        bootloader[6] = KERNEL_LOAD_ADDR;
+        bootloader[5] = loader_start + KERNEL_ARGS_ADDR;
+        bootloader[6] = entry;
         for (n = 0; n < sizeof(bootloader) / 4; n++)
             stl_raw(phys_ram_base + (n * 4), bootloader[n]);
-        set_kernel_args(ram_size, initrd_size, kernel_cmdline);
+        if (old_param)
+            set_kernel_args_old(ram_size, initrd_size,
+                                kernel_cmdline, loader_start);
+        else
+            set_kernel_args(ram_size, initrd_size,
+                            kernel_cmdline, loader_start);
     }
 }
-
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 2901f34..8cd7182 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * ARM AMBA Generic/Distributed Interrupt Controller
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -60,10 +60,8 @@
 
 typedef struct gic_state
 {
-    arm_pic_handler handler;
     uint32_t base;
-    void *parent;
-    int parent_irq;
+    qemu_irq parent_irq;
     int enabled;
     int cpu_enabled;
 
@@ -88,7 +86,7 @@
 
     s->current_pending = 1023;
     if (!s->enabled || !s->cpu_enabled) {
-        pic_set_irq_new(s->parent, s->parent_irq, 0);
+        qemu_irq_lower(s->parent_irq);
         return;
     }
     best_prio = 0x100;
@@ -102,12 +100,12 @@
         }
     }
     if (best_prio > s->priority_mask) {
-        pic_set_irq_new(s->parent, s->parent_irq, 0);
+        qemu_irq_lower(s->parent_irq);
     } else {
         s->current_pending = best_irq;
         if (best_prio < s->running_priority) {
             DPRINTF("Raised pending IRQ %d\n", best_irq);
-            pic_set_irq_new(s->parent, s->parent_irq, 1);
+            qemu_irq_raise(s->parent_irq);
         }
     }
 }
@@ -117,7 +115,7 @@
     gic_state *s = (gic_state *)opaque;
     /* The first external input line is internal interrupt 32.  */
     irq += 32;
-    if (level == GIC_TEST_LEVEL(irq)) 
+    if (level == GIC_TEST_LEVEL(irq))
         return;
 
     if (level) {
@@ -150,7 +148,7 @@
         DPRINTF("ACK no pending IRQ\n");
         return 1023;
     }
-    pic_set_irq_new(s->parent, s->parent_irq, 0);
+    qemu_irq_lower(s->parent_irq);
     s->last_active[new_irq] = s->running_irq;
     /* For level triggered interrupts we clear the pending bit while
        the interrupt is active.  */
@@ -462,7 +460,7 @@
     case 0x18: /* Highest Pending Interrupt */
         return s->current_pending;
     default:
-        cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
+        cpu_abort (cpu_single_env, "gic_cpu_read: Bad offset %x\n", offset);
         return 0;
     }
 }
@@ -486,7 +484,7 @@
     case 0x10: /* End Of Interrupt */
         return gic_complete_irq(s, value & 0x3ff);
     default:
-        cpu_abort (cpu_single_env, "gic_cpu_writeb: Bad offset %x\n", offset);
+        cpu_abort (cpu_single_env, "gic_cpu_write: Bad offset %x\n", offset);
         return;
     }
     gic_update(s);
@@ -520,28 +518,28 @@
     s->cpu_enabled = 0;
 }
 
-void *arm_gic_init(uint32_t base, void *parent, int parent_irq)
+qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq)
 {
     gic_state *s;
+    qemu_irq *qi;
     int iomemtype;
 
     s = (gic_state *)qemu_mallocz(sizeof(gic_state));
     if (!s)
         return NULL;
-    s->handler = gic_set_irq;
-    s->parent = parent;
+    qi = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ);
     s->parent_irq = parent_irq;
     if (base != 0xffffffff) {
         iomemtype = cpu_register_io_memory(0, gic_cpu_readfn,
                                            gic_cpu_writefn, s);
-        cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+        cpu_register_physical_memory(base, 0x00001000, iomemtype);
         iomemtype = cpu_register_io_memory(0, gic_dist_readfn,
                                            gic_dist_writefn, s);
-        cpu_register_physical_memory(base + 0x1000, 0x00000fff, iomemtype);
+        cpu_register_physical_memory(base + 0x1000, 0x00001000, iomemtype);
         s->base = base;
     } else {
         s->base = 0;
     }
     gic_reset(s);
-    return s;
+    return qi;
 }
diff --git a/hw/arm_pic.c b/hw/arm_pic.c
index fbc2d67..7f4a694 100644
--- a/hw/arm_pic.c
+++ b/hw/arm_pic.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Generic ARM Programmable Interrupt Controller support.
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -11,11 +11,6 @@
 #include "arm_pic.h"
 
 /* Stub functions for hardware that doesn't exist.  */
-void pic_set_irq(int irq, int level)
-{
-    cpu_abort(cpu_single_env, "pic_set_irq");
-}
-
 void pic_info(void)
 {
 }
@@ -25,49 +20,29 @@
 }
 
 
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
-    arm_pic_handler *p = (arm_pic_handler *)opaque;
-    /* Call the real handler.  */
-    (*p)(opaque, irq, level);
-}
-
-/* Model the IRQ/FIQ CPU interrupt lines as a two input interrupt controller.
-   Input 0 is IRQ and input 1 is FIQ.  */
-typedef struct
-{
-    arm_pic_handler handler;
-    CPUState *cpu_env;
-} arm_pic_cpu_state;
-
+/* Input 0 is IRQ and input 1 is FIQ.  */
 static void arm_pic_cpu_handler(void *opaque, int irq, int level)
 {
-    arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque;
+    CPUState *env = (CPUState *)opaque;
     switch (irq) {
     case ARM_PIC_CPU_IRQ:
         if (level)
-            cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+            cpu_interrupt(env, CPU_INTERRUPT_HARD);
         else
-            cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
         break;
     case ARM_PIC_CPU_FIQ:
         if (level)
-            cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+            cpu_interrupt(env, CPU_INTERRUPT_FIQ);
         else
-            cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+            cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
         break;
     default:
-        cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n",
-                  irq);
+        cpu_abort(env, "arm_pic_cpu_handler: Bad interrput line %d\n", irq);
     }
 }
 
-void *arm_pic_init_cpu(CPUState *env)
+qemu_irq *arm_pic_init_cpu(CPUState *env)
 {
-    arm_pic_cpu_state *s;
-    
-    s = (arm_pic_cpu_state *)malloc(sizeof(arm_pic_cpu_state));
-    s->handler = arm_pic_cpu_handler;
-    s->cpu_env = env;
-    return s;
+    return qemu_allocate_irqs(arm_pic_cpu_handler, env, 2);
 }
diff --git a/hw/arm_pic.h b/hw/arm_pic.h
index b299149..1eba2ba 100644
--- a/hw/arm_pic.h
+++ b/hw/arm_pic.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * Generic ARM Programmable Interrupt Controller support.
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -14,14 +14,10 @@
 #ifndef ARM_INTERRUPT_H
 #define ARM_INTERRUPT_H 1
 
-/* The first element of an individual PIC state structures should
-   be a pointer to the handler routine.  */
-typedef void (*arm_pic_handler)(void *opaque, int irq, int level);
-
 /* The CPU is also modeled as an interrupt controller.  */
 #define ARM_PIC_CPU_IRQ 0
 #define ARM_PIC_CPU_FIQ 1
-void *arm_pic_init_cpu(CPUState *env);
+qemu_irq *arm_pic_init_cpu(CPUState *env);
 
 #endif /* !ARM_INTERRUPT_H */
 
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index e9de998..468a494 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Status and system control registers for ARM RealView/Versatile boards.
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -149,7 +149,7 @@
         if (s->lockval == LOCK_VALUE) {
             s->resetlevel = val;
             if (val & 0x100)
-                cpu_abort(cpu_single_env, "Board reset\n");
+                qemu_system_reset_request ();
         }
         break;
     case 0x44: /* PCICTL */
@@ -202,7 +202,7 @@
     s->sys_id = sys_id;
     iomemtype = cpu_register_io_memory(0, arm_sysctl_readfn,
                                        arm_sysctl_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
     /* ??? Save/restore.  */
 }
 
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index c8864f1..3df386a 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * ARM PrimeCell Timer modules.
  *
  * Copyright (c) 2005-2006 CodeSourcery.
@@ -22,115 +22,24 @@
 #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;
-    void *pic;
-    int irq;
+    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)) {
-        pic_set_irq_new(s->pic, s->irq, 1);
+        qemu_irq_raise(s->irq);
     } else {
-        pic_set_irq_new(s->pic, s->irq, 0);
+        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)
@@ -142,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 */
@@ -152,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.
@@ -180,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 */
@@ -200,59 +126,57 @@
         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, void *pic, int irq)
+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->pic = pic;
     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;
 }
 
 /* ARM PrimeCell SP804 dual timer module.
    Docs for this device don't seem to be publicly available.  This
-   implementation is based on gueswork, the linux kernel sources and the
+   implementation is based on guesswork, the linux kernel sources and the
    Integrator/CP timer modules.  */
 
 typedef struct {
-    /* Include a pseudo-PIC device to merge the two interrupt sources.  */
-    arm_pic_handler handler;
     void *timer[2];
     int level[2];
     uint32_t base;
-    /* The output PIC device.  */
-    void *pic;
-    int irq;
+    qemu_irq irq;
 } sp804_state;
 
+/* Merge the IRQs from the two component devices.  */
 static void sp804_set_irq(void *opaque, int irq, int level)
 {
     sp804_state *s = (sp804_state *)opaque;
 
     s->level[irq] = level;
-    pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]);
+    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
 }
 
 static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
@@ -293,23 +217,23 @@
    sp804_write
 };
 
-void sp804_init(uint32_t base, void *pic, int irq)
+void sp804_init(uint32_t base, qemu_irq irq)
 {
     int iomemtype;
     sp804_state *s;
+    qemu_irq *qi;
 
     s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
-    s->handler = sp804_set_irq;
+    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     /* ??? The timers are actually configurable between 32kHz and 1MHz, but
        we don't implement that.  */
-    s->timer[0] = arm_timer_init(1000000, s, 0);
-    s->timer[1] = arm_timer_init(1000000, s, 1);
+    s->timer[0] = arm_timer_init(1000000, qi[0]);
+    s->timer[1] = arm_timer_init(1000000, qi[1]);
     iomemtype = cpu_register_io_memory(0, sp804_readfn,
                                        sp804_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
     /* ??? Save/restore.  */
 }
 
@@ -362,7 +286,7 @@
    icp_pit_write
 };
 
-void icp_pit_init(uint32_t base, void *pic, int irq)
+void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
 {
     int iomemtype;
     icp_pit_state *s;
@@ -370,14 +294,14 @@
     s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
     s->base = base;
     /* Timer 0 runs at the system clock speed (40MHz).  */
-    s->timer[0] = arm_timer_init(40000000, pic, irq);
+    s->timer[0] = arm_timer_init(40000000, pic[irq]);
     /* The other two timers run at 1MHz.  */
-    s->timer[1] = arm_timer_init(1000000, pic, irq + 1);
-    s->timer[2] = arm_timer_init(1000000, pic, irq + 2);
+    s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
+    s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
 
     iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
                                        icp_pit_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
     /* ??? Save/restore.  */
 }
 
diff --git a/hw/cdrom.c b/hw/cdrom.c
index a43b417..4f1fce1 100644
--- a/hw/cdrom.c
+++ b/hw/cdrom.c
@@ -1,8 +1,8 @@
 /*
  * QEMU ATAPI CD-ROM Emulator
- * 
+ *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -41,7 +41,7 @@
 {
     uint8_t *q;
     int len;
-    
+
     if (start_track > 1 && start_track != 0xaa)
         return -1;
     q = buf + 2;
@@ -85,7 +85,7 @@
 {
     uint8_t *q;
     int len;
-    
+
     q = buf + 2;
     *q++ = 1; /* first session */
     *q++ = 1; /* last session */
@@ -101,7 +101,7 @@
     *q++ = 1; /* first track */
     *q++ = 0x00; /* disk type */
     *q++ = 0x00;
-    
+
     *q++ = 1; /* session number */
     *q++ = 0x14; /* data track */
     *q++ = 0; /* track number */
@@ -113,7 +113,7 @@
     *q++ = 1; /* last track */
     *q++ = 0x00;
     *q++ = 0x00;
-    
+
     *q++ = 1; /* session number */
     *q++ = 0x14; /* data track */
     *q++ = 0; /* track number */
@@ -138,14 +138,14 @@
     *q++ = 0; /* sec */
     *q++ = 0; /* frame */
     if (msf) {
-        *q++ = 0; 
+        *q++ = 0;
         lba_to_msf(q, 0);
         q += 3;
     } else {
-        *q++ = 0; 
-        *q++ = 0; 
-        *q++ = 0; 
-        *q++ = 0; 
+        *q++ = 0;
+        *q++ = 0;
+        *q++ = 0;
+        *q++ = 0;
     }
 
     len = q - buf;
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 6c146c5..1693ed5 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -1,9 +1,9 @@
 /*
  * QEMU Cirrus CLGD 54xx VGA Emulator.
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
  * Copyright (c) 2004 Makoto Suzuki (suzu)
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -289,7 +289,7 @@
 } PCICirrusVGAState;
 
 static uint8_t rop_to_index[256];
-    
+
 /***************************************
  *
  *  prototypes.
@@ -416,7 +416,54 @@
     cirrus_bitblt_rop_bkwd_notsrc_or_dst,
     cirrus_bitblt_rop_bkwd_notsrc_and_notdst,
 };
-    
+
+#define TRANSP_ROP(name) {\
+    name ## _8,\
+    name ## _16,\
+        }
+#define TRANSP_NOP(func) {\
+    func,\
+    func,\
+        }
+
+static const cirrus_bitblt_rop_t cirrus_fwd_transp_rop[16][2] = {
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_0),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_dst),
+    TRANSP_NOP(cirrus_bitblt_rop_nop),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_and_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_1),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_xor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_notxor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_src_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_fwd_transp_notsrc_and_notdst),
+};
+
+static const cirrus_bitblt_rop_t cirrus_bkwd_transp_rop[16][2] = {
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_0),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_dst),
+    TRANSP_NOP(cirrus_bitblt_rop_nop),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_and_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_1),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_xor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_notxor_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_src_or_notdst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_or_dst),
+    TRANSP_ROP(cirrus_bitblt_rop_bkwd_transp_notsrc_and_notdst),
+};
+
 #define ROP2(name) {\
     name ## _8,\
     name ## _16,\
@@ -557,7 +604,7 @@
         s->cirrus_blt_fgcol = le16_to_cpu(color);
         break;
     case 3:
-        s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 | 
+        s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 |
             (s->gr[0x11] << 8) | (s->gr[0x13] << 16);
         break;
     default:
@@ -581,7 +628,7 @@
         s->cirrus_blt_bgcol = le16_to_cpu(color);
         break;
     case 3:
-        s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 | 
+        s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 |
             (s->gr[0x10] << 8) | (s->gr[0x12] << 16);
         break;
     default:
@@ -620,7 +667,7 @@
 
     dst = s->vram_ptr + s->cirrus_blt_dstaddr;
     (*s->cirrus_rop) (s, dst, src,
-                      s->cirrus_blt_dstpitch, 0, 
+                      s->cirrus_blt_dstpitch, 0,
                       s->cirrus_blt_width, s->cirrus_blt_height);
     cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
                              s->cirrus_blt_dstpitch, s->cirrus_blt_width,
@@ -635,7 +682,7 @@
     cirrus_fill_t rop_func;
 
     rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
-    rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr, 
+    rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr,
              s->cirrus_blt_dstpitch,
              s->cirrus_blt_width, s->cirrus_blt_height);
     cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
@@ -654,7 +701,7 @@
 static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
 {
     return cirrus_bitblt_common_patterncopy(s,
-					    s->vram_ptr + 
+					    s->vram_ptr +
                                             (s->cirrus_blt_srcaddr & ~7));
 }
 
@@ -755,7 +802,7 @@
 {
     int copy_count;
     uint8_t *end_ptr;
-    
+
     if (s->cirrus_srccounter > 0) {
         if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
             cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
@@ -821,7 +868,7 @@
     } else {
 	if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
             w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth;
-            if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) 
+            if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)
                 s->cirrus_blt_srcpitch = ((w + 31) >> 5);
             else
                 s->cirrus_blt_srcpitch = ((w + 7) >> 3);
@@ -880,7 +927,7 @@
 
 #ifdef DEBUG_BITBLT
     printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
-           blt_rop, 
+           blt_rop,
            s->cirrus_blt_mode,
            s->cirrus_blt_modeext,
            s->cirrus_blt_width,
@@ -924,16 +971,16 @@
     }
 
     if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
-        (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST | 
+        (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
                                CIRRUS_BLTMODE_TRANSPARENTCOMP |
-                               CIRRUS_BLTMODE_PATTERNCOPY | 
-                               CIRRUS_BLTMODE_COLOREXPAND)) == 
+                               CIRRUS_BLTMODE_PATTERNCOPY |
+                               CIRRUS_BLTMODE_COLOREXPAND)) ==
          (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
         cirrus_bitblt_fgcol(s);
         cirrus_bitblt_solidfill(s, blt_rop);
     } else {
-        if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND | 
-                                   CIRRUS_BLTMODE_PATTERNCOPY)) == 
+        if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND |
+                                   CIRRUS_BLTMODE_PATTERNCOPY)) ==
             CIRRUS_BLTMODE_COLOREXPAND) {
 
             if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
@@ -964,15 +1011,28 @@
                 s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
             }
         } else {
-            if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
-                s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
-                s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
-                s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
-            } else {
-                s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
-            }
-        }
-        
+	    if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
+		if (s->cirrus_blt_pixelwidth > 2) {
+		    printf("src transparent without colorexpand must be 8bpp or 16bpp\n");
+		    goto bitblt_ignore;
+		}
+		if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
+		    s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
+		    s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
+		    s->cirrus_rop = cirrus_bkwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+		} else {
+		    s->cirrus_rop = cirrus_fwd_transp_rop[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
+		}
+	    } else {
+		if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
+		    s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
+		    s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
+		    s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
+		} else {
+		    s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
+		}
+	    }
+	}
         // setup bitblt engine.
         if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
             if (!cirrus_bitblt_cputovideo(s))
@@ -1013,7 +1073,7 @@
  *
  ***************************************/
 
-static void cirrus_get_offsets(VGAState *s1, 
+static void cirrus_get_offsets(VGAState *s1,
                                uint32_t *pline_offset,
                                uint32_t *pstart_addr,
                                uint32_t *pline_compare)
@@ -1033,7 +1093,7 @@
 	| ((s->cr[0x1d] & 0x80) << 12);
     *pstart_addr = start_addr;
 
-    line_compare = s->cr[0x18] | 
+    line_compare = s->cr[0x18] |
         ((s->cr[0x07] & 0x10) << 4) |
         ((s->cr[0x09] & 0x40) << 3);
     *pline_compare = line_compare;
@@ -1102,10 +1162,10 @@
 static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight)
 {
     int width, height;
-    
+
     width = (s->cr[0x01] + 1) * 8;
-    height = s->cr[0x12] | 
-        ((s->cr[0x07] & 0x02) << 7) | 
+    height = s->cr[0x12] |
+        ((s->cr[0x07] & 0x02) << 7) |
         ((s->cr[0x07] & 0x40) << 3);
     height = (height + 1);
     /* interlace support */
@@ -1993,7 +2053,7 @@
     return v;
 }
 
-static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr, 
+static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
                                   uint32_t mem_value)
 {
     CirrusVGAState *s = opaque;
@@ -2104,7 +2164,7 @@
 static inline void invalidate_cursor1(CirrusVGAState *s)
 {
     if (s->last_hw_cursor_size) {
-        vga_invalidate_scanlines((VGAState *)s, 
+        vga_invalidate_scanlines((VGAState *)s,
                                  s->last_hw_cursor_y + s->last_hw_cursor_y_start,
                                  s->last_hw_cursor_y + s->last_hw_cursor_y_end);
     }
@@ -2180,7 +2240,7 @@
         s->last_hw_cursor_y != s->hw_cursor_y) {
 
         invalidate_cursor1(s);
-        
+
         s->last_hw_cursor_size = size;
         s->last_hw_cursor_x = s->hw_cursor_x;
         s->last_hw_cursor_y = s->hw_cursor_y;
@@ -2197,8 +2257,8 @@
     unsigned int color0, color1;
     const uint8_t *palette, *src;
     uint32_t content;
-    
-    if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW)) 
+
+    if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW))
         return;
     /* fast test to see if the cursor intersects with the scan line */
     if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
@@ -2209,7 +2269,7 @@
     if (scr_y < s->hw_cursor_y ||
         scr_y >= (s->hw_cursor_y + h))
         return;
-    
+
     src = s->vram_ptr + s->real_vram_size - 16 * 1024;
     if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
         src += (s->sr[0x13] & 0x3c) * 256;
@@ -2239,11 +2299,11 @@
         x2 = s->last_scr_width;
     w = x2 - x1;
     palette = s->cirrus_hidden_palette;
-    color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]), 
-                             c6_to_8(palette[0x0 * 3 + 1]), 
+    color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]),
+                             c6_to_8(palette[0x0 * 3 + 1]),
                              c6_to_8(palette[0x0 * 3 + 2]));
-    color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]), 
-                             c6_to_8(palette[0xf * 3 + 1]), 
+    color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]),
+                             c6_to_8(palette[0xf * 3 + 1]),
                              c6_to_8(palette[0xf * 3 + 2]));
     bpp = ((s->ds->depth + 7) >> 3);
     d1 += x1 * bpp;
@@ -2278,7 +2338,7 @@
 
     addr &= s->cirrus_addr_mask;
 
-    if (((s->sr[0x17] & 0x44) == 0x44) && 
+    if (((s->sr[0x17] & 0x44) == 0x44) &&
         ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
 	/* memory-mapped I/O */
 	ret = cirrus_mmio_blt_read(s, addr & 0xff);
@@ -2336,8 +2396,8 @@
     unsigned mode;
 
     addr &= s->cirrus_addr_mask;
-        
-    if (((s->sr[0x17] & 0x44) == 0x44) && 
+
+    if (((s->sr[0x17] & 0x44) == 0x44) &&
         ((addr & s->linear_mmio_mask) ==  s->linear_mmio_mask)) {
 	/* memory-mapped I/O */
 	cirrus_mmio_blt_write(s, addr & 0xff, val);
@@ -2636,7 +2696,7 @@
 	} else if (s->gr[0x0B] & 0x02) {
             goto generic_io;
         }
-        
+
 	mode = s->gr[0x05] & 0x7;
 	if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
 #ifdef USE_KVM
@@ -2923,7 +2983,7 @@
 	case 0x09:
 	case 0x0c:
 	case 0x0d:
-	case 0x12:		/* veritcal display end */
+	case 0x12:		/* vertical display end */
 	    s->cr[s->cr_index] = val;
 	    break;
 
@@ -3212,9 +3272,9 @@
     register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
     register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
 
-    vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read, 
+    vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read,
                                            cirrus_vga_mem_write, s);
-    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
+    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
                                  vga_io_memory);
 
     s->sr[0x06] = 0x0f;
@@ -3236,7 +3296,7 @@
     } else {
         s->sr[0x1F] = 0x22;		// MemClock
         s->sr[0x0F] = CIRRUS_MEMSIZE_2M;
-        if (is_pci) 
+        if (is_pci)
             s->sr[0x17] = CIRRUS_BUSTYPE_PCI;
         else
             s->sr[0x17] = CIRRUS_BUSTYPE_ISA;
@@ -3286,14 +3346,14 @@
  *
  ***************************************/
 
-void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, 
+void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
                          unsigned long vga_ram_offset, int vga_ram_size)
 {
     CirrusVGAState *s;
 
     s = qemu_mallocz(sizeof(CirrusVGAState));
-    
-    vga_common_init((VGAState *)s, 
+
+    vga_common_init((VGAState *)s,
                     ds, vga_ram_base, vga_ram_offset, vga_ram_size);
     cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0);
     /* XXX ISA-LFB support */
@@ -3337,19 +3397,19 @@
 				 s->cirrus_mmio_io_addr);
 }
 
-void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
+void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
                          unsigned long vga_ram_offset, int vga_ram_size)
 {
     PCICirrusVGAState *d;
     uint8_t *pci_conf;
     CirrusVGAState *s;
     int device_id;
-    
+
     device_id = CIRRUS_ID_CLGD5446;
 
     /* setup PCI configuration registers */
-    d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA", 
-                                                 sizeof(PCICirrusVGAState), 
+    d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA",
+                                                 sizeof(PCICirrusVGAState),
                                                  -1, NULL, NULL);
     pci_conf = d->dev.config;
     pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff);
@@ -3363,9 +3423,12 @@
 
     /* setup VGA */
     s = &d->cirrus_vga;
-    vga_common_init((VGAState *)s, 
+    vga_common_init((VGAState *)s,
                     ds, vga_ram_base, vga_ram_offset, vga_ram_size);
     cirrus_init_common(s, device_id, 1);
+
+    graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
+
     s->pci_dev = (PCIDevice *)d;
 
     /* setup memory space */
diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h
index c54f125..3d6a1fe 100644
--- a/hw/cirrus_vga_rop.h
+++ b/hw/cirrus_vga_rop.h
@@ -1,8 +1,8 @@
 /*
  * QEMU Cirrus CLGD 54xx VGA Emulator.
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -62,6 +62,108 @@
     }
 }
 
+static void
+glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
+						       uint8_t *dst,const uint8_t *src,
+						       int dstpitch,int srcpitch,
+						       int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p;
+    dstpitch -= bltwidth;
+    srcpitch -= bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+	    p = *dst;
+            ROP_OP(p, *src);
+	    if (p != s->gr[0x34]) *dst = p;
+            dst++;
+            src++;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_8)(CirrusVGAState *s,
+							uint8_t *dst,const uint8_t *src,
+							int dstpitch,int srcpitch,
+							int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p;
+    dstpitch += bltwidth;
+    srcpitch += bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x++) {
+	    p = *dst;
+            ROP_OP(p, *src);
+	    if (p != s->gr[0x34]) *dst = p;
+            dst--;
+            src--;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_fwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
+							uint8_t *dst,const uint8_t *src,
+							int dstpitch,int srcpitch,
+							int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p1, p2;
+    dstpitch -= bltwidth;
+    srcpitch -= bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x+=2) {
+	    p1 = *dst;
+	    p2 = *(dst+1);
+            ROP_OP(p1, *src);
+            ROP_OP(p2, *(src+1));
+	    if ((p1 != s->gr[0x34]) || (p2 != s->gr[0x35])) {
+		*dst = p1;
+		*(dst+1) = p2;
+	    }
+            dst+=2;
+            src+=2;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
+static void
+glue(glue(cirrus_bitblt_rop_bkwd_transp_, ROP_NAME),_16)(CirrusVGAState *s,
+							 uint8_t *dst,const uint8_t *src,
+							 int dstpitch,int srcpitch,
+							 int bltwidth,int bltheight)
+{
+    int x,y;
+    uint8_t p1, p2;
+    dstpitch += bltwidth;
+    srcpitch += bltwidth;
+    for (y = 0; y < bltheight; y++) {
+        for (x = 0; x < bltwidth; x+=2) {
+	    p1 = *(dst-1);
+	    p2 = *dst;
+            ROP_OP(p1, *(src-1));
+            ROP_OP(p2, *src);
+	    if ((p1 != s->gr[0x34]) || (p2 != s->gr[0x35])) {
+		*(dst-1) = p1;
+		*dst = p2;
+	    }
+            dst-=2;
+            src-=2;
+        }
+        dst += dstpitch;
+        src += srcpitch;
+    }
+}
+
 #define DEPTH 8
 #include "cirrus_vga_rop2.h"
 
diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h
index da11d0f..137681e 100644
--- a/hw/cirrus_vga_rop2.h
+++ b/hw/cirrus_vga_rop2.h
@@ -1,8 +1,8 @@
 /*
  * QEMU Cirrus CLGD 54xx VGA Emulator.
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -34,13 +34,13 @@
 #define PUTPIXEL()    ROP_OP(((uint32_t *)d)[0], col)
 #else
 #error unsupported DEPTH
-#endif                
+#endif
 
 static void
 glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
      (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src, 
-      int dstpitch, int srcpitch, 
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
     uint8_t *d;
@@ -94,8 +94,8 @@
 static void
 glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
      (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src, 
-      int dstpitch, int srcpitch, 
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
     uint8_t *d;
@@ -143,8 +143,8 @@
 static void
 glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
      (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src, 
-      int dstpitch, int srcpitch, 
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
     uint32_t colors[2];
@@ -179,8 +179,8 @@
 static void
 glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
      (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src, 
-      int dstpitch, int srcpitch, 
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
     uint8_t *d;
@@ -223,8 +223,8 @@
 static void
 glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
      (CirrusVGAState * s, uint8_t * dst,
-      const uint8_t * src, 
-      int dstpitch, int srcpitch, 
+      const uint8_t * src,
+      int dstpitch, int srcpitch,
       int bltwidth, int bltheight)
 {
     uint32_t colors[2];
@@ -254,10 +254,10 @@
     }
 }
 
-static void 
+static void
 glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
      (CirrusVGAState *s,
-      uint8_t *dst, int dst_pitch, 
+      uint8_t *dst, int dst_pitch,
       int width, int height)
 {
     uint8_t *d, *d1;
diff --git a/hw/cs4231.c b/hw/cs4231.c
index a154685..390ef74 100644
--- a/hw/cs4231.c
+++ b/hw/cs4231.c
@@ -30,6 +30,7 @@
  * In addition to Crystal CS4231 there is a DMA controller on Sparc.
  */
 #define CS_MAXADDR 0x3f
+#define CS_SIZE (CS_MAXADDR + 1)
 #define CS_REGS 16
 #define CS_DREGS 32
 #define CS_MAXDREG (CS_DREGS - 1)
@@ -47,9 +48,6 @@
 #ifdef DEBUG_CS
 #define DPRINTF(fmt, args...)                           \
     do { printf("CS: " fmt , ##args); } while (0)
-#define pic_set_irq_new(intctl, irq, level)                             \
-    do { printf("CS: set_irq(%d): %d\n", (irq), (level));               \
-        pic_set_irq_new((intctl), (irq),(level));} while (0)
 #else
 #define DPRINTF(fmt, args...)
 #endif
@@ -176,7 +174,7 @@
         return;
 
     cs_io_memory = cpu_register_io_memory(0, cs_mem_read, cs_mem_write, s);
-    cpu_register_physical_memory(base, CS_MAXADDR, cs_io_memory);
+    cpu_register_physical_memory(base, CS_SIZE, cs_io_memory);
     register_savevm("cs4231", base, 1, cs_save, cs_load, s);
     qemu_register_reset(cs_reset, s);
     cs_reset(s);
diff --git a/hw/cuda.c b/hw/cuda.c
index f3c2b56..9a05aeb 100644
--- a/hw/cuda.c
+++ b/hw/cuda.c
@@ -1,8 +1,8 @@
 /*
  * QEMU CUDA support
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -94,7 +94,7 @@
 #define RTC_OFFSET                      2082844800
 
 typedef struct CUDATimer {
-    int index; 
+    int index;
     uint16_t latch;
     uint16_t counter_value; /* counter value at load time */
     int64_t load_time;
@@ -116,17 +116,15 @@
     uint8_t anh;    /* A-side data, no handshake */
 
     CUDATimer timers[2];
-    
+
     uint8_t last_b; /* last value of B register */
     uint8_t last_acr; /* last value of B register */
-    
+
     int data_in_size;
     int data_in_index;
     int data_out_index;
 
-    SetIRQFunc *set_irq;
-    int irq;
-    void *irq_opaque;
+    qemu_irq irq;
     uint8_t autopoll;
     uint8_t data_in[128];
     uint8_t data_out[16];
@@ -137,17 +135,17 @@
 ADBBusState adb_bus;
 
 static void cuda_update(CUDAState *s);
-static void cuda_receive_packet_from_host(CUDAState *s, 
+static void cuda_receive_packet_from_host(CUDAState *s,
                                           const uint8_t *data, int len);
-static void cuda_timer_update(CUDAState *s, CUDATimer *ti, 
+static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
                               int64_t current_time);
 
 static void cuda_update_irq(CUDAState *s)
 {
     if (s->ifr & s->ier & (SR_INT | T1_INT)) {
-        s->set_irq(s->irq_opaque, s->irq, 1);
+        qemu_irq_raise(s->irq);
     } else {
-        s->set_irq(s->irq_opaque, s->irq, 0);
+        qemu_irq_lower(s->irq);
     }
 }
 
@@ -156,7 +154,7 @@
     int64_t d;
     unsigned int counter;
 
-    d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, 
+    d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
                  CUDA_TIMER_FREQ, ticks_per_sec);
     if (s->index == 0) {
         /* the timer goes down from latch to -1 (period of latch + 2) */
@@ -164,7 +162,7 @@
             counter = (s->counter_value - d) & 0xffff;
         } else {
             counter = (d - (s->counter_value + 1)) % (s->latch + 2);
-            counter = (s->latch - counter) & 0xffff; 
+            counter = (s->latch - counter) & 0xffff;
         }
     } else {
         counter = (s->counter_value - d) & 0xffff;
@@ -189,16 +187,16 @@
     unsigned int counter;
 
     /* current counter value */
-    d = muldiv64(current_time - s->load_time, 
+    d = muldiv64(current_time - s->load_time,
                  CUDA_TIMER_FREQ, ticks_per_sec);
     /* the timer goes down from latch to -1 (period of latch + 2) */
     if (d <= (s->counter_value + 1)) {
         counter = (s->counter_value - d) & 0xffff;
     } else {
         counter = (d - (s->counter_value + 1)) % (s->latch + 2);
-        counter = (s->latch - counter) & 0xffff; 
+        counter = (s->latch - counter) & 0xffff;
     }
-    
+
     /* Note: we consider the irq is raised on 0 */
     if (counter == 0xffff) {
         next_time = d + s->latch + 1;
@@ -209,18 +207,18 @@
     }
 #if 0
 #ifdef DEBUG_CUDA
-    printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", 
+    printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
            s->latch, d, next_time - d);
 #endif
 #endif
-    next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + 
+    next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
         s->load_time;
     if (next_time <= current_time)
         next_time = current_time + 1;
     return next_time;
 }
 
-static void cuda_timer_update(CUDAState *s, CUDATimer *ti, 
+static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
                               int64_t current_time)
 {
     if (!ti->timer)
@@ -298,7 +296,7 @@
         break;
     case 13:
         val = s->ifr;
-        if (s->ifr & s->ier) 
+        if (s->ifr & s->ier)
             val |= 0x80;
         break;
     case 14:
@@ -319,7 +317,7 @@
 static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     CUDAState *s = opaque;
-    
+
     addr = (addr >> 9) & 0xf;
 #ifdef DEBUG_CUDA
     printf("cuda: write: reg=0x%x val=%02x\n", addr, val);
@@ -447,9 +445,9 @@
             cuda_update_irq(s);
         } else {
             if (!(s->last_b & TIP)) {
-                /* handle end of host to cuda transfert */
+                /* handle end of host to cuda transfer */
                 packet_received = (s->data_out_index > 0);
-                /* always an IRQ at the end of transfert */
+                /* always an IRQ at the end of transfer */
                 s->ifr |= SR_INT;
                 cuda_update_irq(s);
             }
@@ -472,7 +470,7 @@
     }
 }
 
-static void cuda_send_packet_to_host(CUDAState *s, 
+static void cuda_send_packet_to_host(CUDAState *s,
                                      const uint8_t *data, int len)
 {
 #ifdef DEBUG_CUDA_PACKET
@@ -504,12 +502,12 @@
         obuf[1] = 0x40; /* polled data */
         cuda_send_packet_to_host(s, obuf, olen + 2);
     }
-    qemu_mod_timer(s->adb_poll_timer, 
-                   qemu_get_clock(vm_clock) + 
+    qemu_mod_timer(s->adb_poll_timer,
+                   qemu_get_clock(vm_clock) +
                    (ticks_per_sec / CUDA_ADB_POLL_FREQ));
 }
 
-static void cuda_receive_packet(CUDAState *s, 
+static void cuda_receive_packet(CUDAState *s,
                                 const uint8_t *data, int len)
 {
     uint8_t obuf[16];
@@ -521,8 +519,8 @@
         if (autopoll != s->autopoll) {
             s->autopoll = autopoll;
             if (autopoll) {
-                qemu_mod_timer(s->adb_poll_timer, 
-                               qemu_get_clock(vm_clock) + 
+                qemu_mod_timer(s->adb_poll_timer,
+                               qemu_get_clock(vm_clock) +
                                (ticks_per_sec / CUDA_ADB_POLL_FREQ));
             } else {
                 qemu_del_timer(s->adb_poll_timer);
@@ -559,12 +557,18 @@
         cuda_send_packet_to_host(s, obuf, 2);
 	qemu_system_shutdown_request();
 	break;
+    case CUDA_RESET_SYSTEM:
+        obuf[0] = CUDA_PACKET;
+        obuf[1] = 0;
+        cuda_send_packet_to_host(s, obuf, 2);
+        qemu_system_reset_request();
+        break;
     default:
         break;
     }
 }
 
-static void cuda_receive_packet_from_host(CUDAState *s, 
+static void cuda_receive_packet_from_host(CUDAState *s,
                                           const uint8_t *data, int len)
 {
 #ifdef DEBUG_CUDA_PACKET
@@ -630,13 +634,11 @@
     &cuda_readl,
 };
 
-int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq)
+int cuda_init(qemu_irq irq)
 {
     CUDAState *s = &cuda_state;
     int cuda_mem_index;
 
-    s->set_irq = set_irq;
-    s->irq_opaque = irq_opaque;
     s->irq = irq;
 
     s->timers[0].index = 0;
diff --git a/hw/dma.c b/hw/dma.c
index ea13eae..2e8608c 100644
--- a/hw/dma.c
+++ b/hw/dma.c
@@ -383,7 +383,7 @@
 int DMA_read_memory (int nchan, void *buf, int pos, int len)
 {
     struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
-    target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
+    target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
 
     if (r->mode & 0x20) {
         int i;
@@ -405,7 +405,7 @@
 int DMA_write_memory (int nchan, void *buf, int pos, int len)
 {
     struct dma_regs *r = &dma_controllers[nchan > 3].regs[nchan & 3];
-    target_ulong addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
+    target_phys_addr_t addr = ((r->pageh & 0x7f) << 24) | (r->page << 16) | r->now[ADDR];
 
     if (r->mode & 0x20) {
         int i;
diff --git a/hw/ds1225y.c b/hw/ds1225y.c
new file mode 100644
index 0000000..7851096
--- /dev/null
+++ b/hw/ds1225y.c
@@ -0,0 +1,121 @@
+/*

+ * QEMU NVRAM emulation for DS1225Y chip

+ * 

+ * Copyright (c) 2007 Hervé Poussineau

+ * 

+ * Permission is hereby granted, free of charge, to any person obtaining a copy

+ * of this software and associated documentation files (the "Software"), to deal

+ * in the Software without restriction, including without limitation the rights

+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

+ * copies of the Software, and to permit persons to whom the Software is

+ * furnished to do so, subject to the following conditions:

+ *

+ * The above copyright notice and this permission notice shall be included in

+ * all copies or substantial portions of the Software.

+ *

+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL

+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

+ * THE SOFTWARE.

+ */

+

+#include "vl.h"

+

+typedef enum

+{

+    none = 0,

+    readmode,

+    writemode,

+} nvram_open_mode;

+

+struct ds1225y_t

+{

+    target_phys_addr_t mem_base;

+    uint32_t capacity;

+    const char *filename;

+    QEMUFile *file;

+    nvram_open_mode open_mode;

+};

+

+static int ds1225y_set_to_mode(ds1225y_t *NVRAM, nvram_open_mode mode, const char *filemode)

+{

+    if (NVRAM->open_mode != mode)

+    {

+        if (NVRAM->file)

+            qemu_fclose(NVRAM->file);

+        NVRAM->file = qemu_fopen(NVRAM->filename, filemode);

+        NVRAM->open_mode = mode;

+    }

+    return (NVRAM->file != NULL);

+}

+

+static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)

+{

+    ds1225y_t *NVRAM = opaque;

+    int64_t pos;

+

+    pos = addr - NVRAM->mem_base;

+    if (addr >= NVRAM->capacity)

+        addr -= NVRAM->capacity;

+

+    if (!ds1225y_set_to_mode(NVRAM, readmode, "rb"))

+        return 0;

+    qemu_fseek(NVRAM->file, pos, SEEK_SET);

+    return (uint32_t)qemu_get_byte(NVRAM->file);

+}

+

+static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)

+{

+    ds1225y_t *NVRAM = opaque;

+    int64_t pos;

+

+    pos = addr - NVRAM->mem_base;

+    if (ds1225y_set_to_mode(NVRAM, writemode, "wb"))

+    {

+        qemu_fseek(NVRAM->file, pos, SEEK_SET);

+        qemu_put_byte(NVRAM->file, (int)value);

+    }

+}

+

+static CPUReadMemoryFunc *nvram_read[] = {

+    &nvram_readb,

+    NULL,

+    NULL,

+};

+

+static CPUWriteMemoryFunc *nvram_write[] = {

+    &nvram_writeb,

+    NULL,

+    NULL,

+};

+

+static CPUWriteMemoryFunc *nvram_none[] = {

+    NULL,

+    NULL,

+    NULL,

+};

+

+/* Initialisation routine */

+ds1225y_t *ds1225y_init(target_phys_addr_t mem_base, const char *filename)

+{

+    ds1225y_t *s;

+    int mem_index1, mem_index2;

+

+    s = qemu_mallocz(sizeof(ds1225y_t));

+    if (!s)

+        return NULL;

+    s->mem_base = mem_base;

+    s->capacity = 0x2000; /* Fixed for ds1225y chip: 8K */

+    s->filename = filename;

+

+    /* Read/write memory */

+    mem_index1 = cpu_register_io_memory(0, nvram_read, nvram_write, s);

+    cpu_register_physical_memory(mem_base, s->capacity, mem_index1);

+    /* Read-only memory */

+    mem_index2 = cpu_register_io_memory(0, nvram_read, nvram_none, s);

+    cpu_register_physical_memory(mem_base + s->capacity, s->capacity, mem_index2);

+    return s;

+}

diff --git a/hw/ecc.c b/hw/ecc.c
new file mode 100644
index 0000000..970ede8
--- /dev/null
+++ b/hw/ecc.c
@@ -0,0 +1,90 @@
+/*
+ * Calculate Error-correcting Codes. Used by NAND Flash controllers
+ * (not by NAND chips).
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "vl.h"
+
+/*
+ * Pre-calculated 256-way 1 byte column parity.  Table borrowed from Linux.
+ */
+static const uint8_t nand_ecc_precalc_table[] = {
+    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+    0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30,
+    0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a,
+    0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55,
+    0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f,
+    0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56,
+    0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c,
+    0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33,
+    0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69,
+    0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59,
+    0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03,
+    0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c,
+    0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66,
+    0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f,
+    0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65,
+    0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a,
+    0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00,
+};
+
+/* Update ECC parity count.  */
+uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample)
+{
+    uint8_t idx = nand_ecc_precalc_table[sample];
+
+    s->cp ^= idx & 0x3f;
+    if (idx & 0x40) {
+        s->lp[0] ^= ~s->count;
+        s->lp[1] ^= s->count;
+    }
+    s->count ++;
+
+    return sample;
+}
+
+/* Reinitialise the counters.  */
+void ecc_reset(struct ecc_state_s *s)
+{
+    s->lp[0] = 0x0000;
+    s->lp[1] = 0x0000;
+    s->cp = 0x00;
+    s->count = 0;
+}
+
+/* Save/restore */
+void ecc_put(QEMUFile *f, struct ecc_state_s *s)
+{
+    qemu_put_8s(f, &s->cp);
+    qemu_put_be16s(f, &s->lp[0]);
+    qemu_put_be16s(f, &s->lp[1]);
+    qemu_put_be16s(f, &s->count);
+}
+
+void ecc_get(QEMUFile *f, struct ecc_state_s *s)
+{
+    qemu_get_8s(f, &s->cp);
+    qemu_get_be16s(f, &s->lp[0]);
+    qemu_get_be16s(f, &s->lp[1]);
+    qemu_get_be16s(f, &s->count);
+}
diff --git a/hw/eepro100.c b/hw/eepro100.c
new file mode 100644
index 0000000..975aeb1
--- /dev/null
+++ b/hw/eepro100.c
@@ -0,0 +1,1813 @@
+/*
+ * QEMU i8255x (PRO100) emulation
+ *
+ * Copyright (c) 2006-2007 Stefan Weil
+ *
+ * Portions of the code are copies from grub / etherboot eepro100.c
+ * and linux e100.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * Tested features (i82559):
+ *      PXE boot (i386) no valid link
+ *      Linux networking (i386) ok
+ *
+ * Untested:
+ *      non-i386 platforms
+ *      Windows networking
+ *
+ * References:
+ *
+ * Intel 8255x 10/100 Mbps Ethernet Controller Family
+ * Open Source Software Developer Manual
+ */
+
+#if defined(TARGET_I386)
+# warning "PXE boot still not working!"
+#endif
+
+#include <assert.h>
+#include <stddef.h>             /* offsetof */
+#include "vl.h"
+#include "eeprom93xx.h"
+
+/* Common declarations for all PCI devices. */
+
+#define PCI_VENDOR_ID           0x00    /* 16 bits */
+#define PCI_DEVICE_ID           0x02    /* 16 bits */
+#define PCI_COMMAND             0x04    /* 16 bits */
+#define PCI_STATUS              0x06    /* 16 bits */
+
+#define PCI_REVISION_ID         0x08    /* 8 bits  */
+#define PCI_CLASS_CODE          0x0b    /* 8 bits */
+#define PCI_SUBCLASS_CODE       0x0a    /* 8 bits */
+#define PCI_HEADER_TYPE         0x0e    /* 8 bits */
+
+#define PCI_BASE_ADDRESS_0      0x10    /* 32 bits */
+#define PCI_BASE_ADDRESS_1      0x14    /* 32 bits */
+#define PCI_BASE_ADDRESS_2      0x18    /* 32 bits */
+#define PCI_BASE_ADDRESS_3      0x1c    /* 32 bits */
+#define PCI_BASE_ADDRESS_4      0x20    /* 32 bits */
+#define PCI_BASE_ADDRESS_5      0x24    /* 32 bits */
+
+#define PCI_CONFIG_8(offset, value) \
+    (pci_conf[offset] = (value))
+#define PCI_CONFIG_16(offset, value) \
+    (*(uint16_t *)&pci_conf[offset] = cpu_to_le16(value))
+#define PCI_CONFIG_32(offset, value) \
+    (*(uint32_t *)&pci_conf[offset] = cpu_to_le32(value))
+
+#define KiB 1024
+
+/* debug EEPRO100 card */
+//~ #define DEBUG_EEPRO100
+
+#ifdef DEBUG_EEPRO100
+#define logout(fmt, args...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ##args)
+#else
+#define logout(fmt, args...) ((void)0)
+#endif
+
+/* Set flags to 0 to disable debug output. */
+#define MDI     0
+
+#define TRACE(flag, command) ((flag) ? (command) : (void)0)
+
+#define missing(text)       assert(!"feature is missing in this emulation: " text)
+
+#define MAX_ETH_FRAME_SIZE 1514
+
+/* This driver supports several different devices which are declared here. */
+#define i82551          0x82551
+#define i82557B         0x82557b
+#define i82557C         0x82557c
+#define i82558B         0x82558b
+#define i82559C         0x82559c
+#define i82559ER        0x82559e
+#define i82562          0x82562
+
+#define EEPROM_SIZE     64
+
+#define PCI_MEM_SIZE            (4 * KiB)
+#define PCI_IO_SIZE             64
+#define PCI_FLASH_SIZE          (128 * KiB)
+
+#define BIT(n) (1 << (n))
+#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
+
+/* The SCB accepts the following controls for the Tx and Rx units: */
+#define  CU_NOP         0x0000  /* No operation. */
+#define  CU_START       0x0010  /* CU start. */
+#define  CU_RESUME      0x0020  /* CU resume. */
+#define  CU_STATSADDR   0x0040  /* Load dump counters address. */
+#define  CU_SHOWSTATS   0x0050  /* Dump statistical counters. */
+#define  CU_CMD_BASE    0x0060  /* Load CU base address. */
+#define  CU_DUMPSTATS   0x0070  /* Dump and reset statistical counters. */
+#define  CU_SRESUME     0x00a0  /* CU static resume. */
+
+#define  RU_NOP         0x0000
+#define  RX_START       0x0001
+#define  RX_RESUME      0x0002
+#define  RX_ABORT       0x0004
+#define  RX_ADDR_LOAD   0x0006
+#define  RX_RESUMENR    0x0007
+#define INT_MASK        0x0100
+#define DRVR_INT        0x0200  /* Driver generated interrupt. */
+
+typedef unsigned char bool;
+
+/* Offsets to the various registers.
+   All accesses need not be longword aligned. */
+enum speedo_offsets {
+    SCBStatus = 0,
+    SCBAck = 1,
+    SCBCmd = 2,                 /* Rx/Command Unit command and status. */
+    SCBIntmask = 3,
+    SCBPointer = 4,             /* General purpose pointer. */
+    SCBPort = 8,                /* Misc. commands and operands.  */
+    SCBflash = 12, SCBeeprom = 14,      /* EEPROM and flash memory control. */
+    SCBCtrlMDI = 16,            /* MDI interface control. */
+    SCBEarlyRx = 20,            /* Early receive byte count. */
+    SCBFlow = 24,
+};
+
+/* A speedo3 transmit buffer descriptor with two buffers... */
+typedef struct {
+    uint16_t status;
+    uint16_t command;
+    uint32_t link;              /* void * */
+    uint32_t tx_desc_addr;      /* transmit buffer decsriptor array address. */
+    uint16_t tcb_bytes;         /* transmit command block byte count (in lower 14 bits */
+    uint8_t tx_threshold;       /* transmit threshold */
+    uint8_t tbd_count;          /* TBD number */
+    //~ /* This constitutes two "TBD" entries: hdr and data */
+    //~ uint32_t tx_buf_addr0;  /* void *, header of frame to be transmitted.  */
+    //~ int32_t  tx_buf_size0;  /* Length of Tx hdr. */
+    //~ uint32_t tx_buf_addr1;  /* void *, data to be transmitted.  */
+    //~ int32_t  tx_buf_size1;  /* Length of Tx data. */
+} eepro100_tx_t;
+
+/* Receive frame descriptor. */
+typedef struct {
+    int16_t status;
+    uint16_t command;
+    uint32_t link;              /* struct RxFD * */
+    uint32_t rx_buf_addr;       /* void * */
+    uint16_t count;
+    uint16_t size;
+    char packet[MAX_ETH_FRAME_SIZE + 4];
+} eepro100_rx_t;
+
+typedef struct {
+    uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
+        tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
+        tx_multiple_collisions, tx_total_collisions;
+    uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
+        rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
+        rx_short_frame_errors;
+    uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
+    uint16_t xmt_tco_frames, rcv_tco_frames;
+    uint32_t complete;
+} eepro100_stats_t;
+
+typedef enum {
+    cu_idle = 0,
+    cu_suspended = 1,
+    cu_active = 2,
+    cu_lpq_active = 2,
+    cu_hqp_active = 3
+} cu_state_t;
+
+typedef enum {
+    ru_idle = 0,
+    ru_suspended = 1,
+    ru_no_resources = 2,
+    ru_ready = 4
+} ru_state_t;
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+#define X(a,b)	b,a
+#else
+#define X(a,b)	a,b
+#endif
+
+typedef struct {
+#if 1
+    uint8_t cmd;
+    uint32_t start;
+    uint32_t stop;
+    uint8_t boundary;
+    uint8_t tsr;
+    uint8_t tpsr;
+    uint16_t tcnt;
+    uint16_t rcnt;
+    uint32_t rsar;
+    uint8_t rsr;
+    uint8_t rxcr;
+    uint8_t isr;
+    uint8_t dcfg;
+    uint8_t imr;
+    uint8_t phys[6];            /* mac address */
+    uint8_t curpag;
+    uint8_t mult[8];            /* multicast mask array */
+    int mmio_index;
+    PCIDevice *pci_dev;
+    VLANClientState *vc;
+#endif
+    uint8_t scb_stat;           /* SCB stat/ack byte */
+    uint8_t int_stat;           /* PCI interrupt status */
+    uint32_t region[3];         /* PCI region addresses */
+    uint8_t macaddr[6];
+    uint32_t statcounter[19];
+    uint16_t mdimem[32];
+    eeprom_t *eeprom;
+    uint32_t device;            /* device variant */
+    uint32_t pointer;
+    /* (cu_base + cu_offset) address the next command block in the command block list. */
+    uint32_t cu_base;           /* CU base address */
+    uint32_t cu_offset;         /* CU address offset */
+    /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
+    uint32_t ru_base;           /* RU base address */
+    uint32_t ru_offset;         /* RU address offset */
+    uint32_t statsaddr;         /* pointer to eepro100_stats_t */
+    eepro100_stats_t statistics;        /* statistical counters */
+#if 0
+    uint16_t status;
+#endif
+
+    /* Configuration bytes. */
+    uint8_t configuration[22];
+
+    /* Data in mem is always in the byte order of the controller (le). */
+    uint8_t mem[PCI_MEM_SIZE];
+} EEPRO100State;
+
+/* Default values for MDI (PHY) registers */
+static const uint16_t eepro100_mdi_default[] = {
+    /* MDI Registers 0 - 6, 7 */
+    0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
+    /* MDI Registers 8 - 15 */
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    /* MDI Registers 16 - 31 */
+    0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+/* Readonly mask for MDI (PHY) registers */
+static const uint16_t eepro100_mdi_mask[] = {
+    0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
+    0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+    0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+    0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+#define POLYNOMIAL 0x04c11db6
+
+/* From FreeBSD */
+/* XXX: optimize */
+static int compute_mcast_idx(const uint8_t * ep)
+{
+    uint32_t crc;
+    int carry, i, j;
+    uint8_t b;
+
+    crc = 0xffffffff;
+    for (i = 0; i < 6; i++) {
+        b = *ep++;
+        for (j = 0; j < 8; j++) {
+            carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+            crc <<= 1;
+            b >>= 1;
+            if (carry)
+                crc = ((crc ^ POLYNOMIAL) | carry);
+        }
+    }
+    return (crc >> 26);
+}
+
+#if defined(DEBUG_EEPRO100)
+static const char *nic_dump(const uint8_t * buf, unsigned size)
+{
+    static char dump[3 * 16 + 1];
+    char *p = &dump[0];
+    if (size > 16)
+        size = 16;
+    while (size-- > 0) {
+        p += sprintf(p, " %02x", *buf++);
+    }
+    return dump;
+}
+#endif                          /* DEBUG_EEPRO100 */
+
+enum scb_stat_ack {
+    stat_ack_not_ours = 0x00,
+    stat_ack_sw_gen = 0x04,
+    stat_ack_rnr = 0x10,
+    stat_ack_cu_idle = 0x20,
+    stat_ack_frame_rx = 0x40,
+    stat_ack_cu_cmd_done = 0x80,
+    stat_ack_not_present = 0xFF,
+    stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
+    stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
+};
+
+static void disable_interrupt(EEPRO100State * s)
+{
+    if (s->int_stat) {
+        logout("interrupt disabled\n");
+        qemu_irq_lower(s->pci_dev->irq[0]);
+        s->int_stat = 0;
+    }
+}
+
+static void enable_interrupt(EEPRO100State * s)
+{
+    if (!s->int_stat) {
+        logout("interrupt enabled\n");
+        qemu_irq_raise(s->pci_dev->irq[0]);
+        s->int_stat = 1;
+    }
+}
+
+static void eepro100_acknowledge(EEPRO100State * s)
+{
+    s->scb_stat &= ~s->mem[SCBAck];
+    s->mem[SCBAck] = s->scb_stat;
+    if (s->scb_stat == 0) {
+        disable_interrupt(s);
+    }
+}
+
+static void eepro100_interrupt(EEPRO100State * s, uint8_t stat)
+{
+    uint8_t mask = ~s->mem[SCBIntmask];
+    s->mem[SCBAck] |= stat;
+    stat = s->scb_stat = s->mem[SCBAck];
+    stat &= (mask | 0x0f);
+    //~ stat &= (~s->mem[SCBIntmask] | 0x0xf);
+    if (stat && (mask & 0x01)) {
+        /* SCB mask and SCB Bit M do not disable interrupt. */
+        enable_interrupt(s);
+    } else if (s->int_stat) {
+        disable_interrupt(s);
+    }
+}
+
+static void eepro100_cx_interrupt(EEPRO100State * s)
+{
+    /* CU completed action command. */
+    /* Transmit not ok (82557 only, not in emulation). */
+    eepro100_interrupt(s, 0x80);
+}
+
+static void eepro100_cna_interrupt(EEPRO100State * s)
+{
+    /* CU left the active state. */
+    eepro100_interrupt(s, 0x20);
+}
+
+static void eepro100_fr_interrupt(EEPRO100State * s)
+{
+    /* RU received a complete frame. */
+    eepro100_interrupt(s, 0x40);
+}
+
+#if 0
+static void eepro100_rnr_interrupt(EEPRO100State * s)
+{
+    /* RU is not ready. */
+    eepro100_interrupt(s, 0x10);
+}
+#endif
+
+static void eepro100_mdi_interrupt(EEPRO100State * s)
+{
+    /* MDI completed read or write cycle. */
+    eepro100_interrupt(s, 0x08);
+}
+
+static void eepro100_swi_interrupt(EEPRO100State * s)
+{
+    /* Software has requested an interrupt. */
+    eepro100_interrupt(s, 0x04);
+}
+
+#if 0
+static void eepro100_fcp_interrupt(EEPRO100State * s)
+{
+    /* Flow control pause interrupt (82558 and later). */
+    eepro100_interrupt(s, 0x01);
+}
+#endif
+
+static void pci_reset(EEPRO100State * s)
+{
+    uint32_t device = s->device;
+    uint8_t *pci_conf = s->pci_dev->config;
+
+    logout("%p\n", s);
+
+    /* PCI Vendor ID */
+    PCI_CONFIG_16(PCI_VENDOR_ID, 0x8086);
+    /* PCI Device ID */
+    PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
+    /* PCI Command */
+    PCI_CONFIG_16(PCI_COMMAND, 0x0000);
+    /* PCI Status */
+    PCI_CONFIG_16(PCI_STATUS, 0x2800);
+    /* PCI Revision ID */
+    PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
+    /* PCI Class Code */
+    PCI_CONFIG_8(0x09, 0x00);
+    PCI_CONFIG_8(PCI_SUBCLASS_CODE, 0x00);      // ethernet network controller
+    PCI_CONFIG_8(PCI_CLASS_CODE, 0x02); // network controller
+    /* PCI Cache Line Size */
+    /* check cache line size!!! */
+    //~ PCI_CONFIG_8(0x0c, 0x00);
+    /* PCI Latency Timer */
+    PCI_CONFIG_8(0x0d, 0x20);   // latency timer = 32 clocks
+    /* PCI Header Type */
+    /* BIST (built-in self test) */
+#if defined(TARGET_I386)
+// !!! workaround for buggy bios
+//~ #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0
+#endif
+#if 0
+    /* PCI Base Address Registers */
+    /* CSR Memory Mapped Base Address */
+    PCI_CONFIG_32(PCI_BASE_ADDRESS_0,
+                  PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH);
+    /* CSR I/O Mapped Base Address */
+    PCI_CONFIG_32(PCI_BASE_ADDRESS_1, PCI_ADDRESS_SPACE_IO);
+#if 0
+    /* Flash Memory Mapped Base Address */
+    PCI_CONFIG_32(PCI_BASE_ADDRESS_2, 0xfffe0000 | PCI_ADDRESS_SPACE_MEM);
+#endif
+#endif
+    /* Expansion ROM Base Address (depends on boot disable!!!) */
+    PCI_CONFIG_32(0x30, 0x00000000);
+    /* Capability Pointer */
+    PCI_CONFIG_8(0x34, 0xdc);
+    /* Interrupt Pin */
+    PCI_CONFIG_8(0x3d, 1);      // interrupt pin 0
+    /* Minimum Grant */
+    PCI_CONFIG_8(0x3e, 0x08);
+    /* Maximum Latency */
+    PCI_CONFIG_8(0x3f, 0x18);
+    /* Power Management Capabilities / Next Item Pointer / Capability ID */
+    PCI_CONFIG_32(0xdc, 0x7e210001);
+
+    switch (device) {
+    case i82551:
+        //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
+        PCI_CONFIG_8(PCI_REVISION_ID, 0x0f);
+        break;
+    case i82557B:
+        PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+        PCI_CONFIG_8(PCI_REVISION_ID, 0x02);
+        break;
+    case i82557C:
+        PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+        PCI_CONFIG_8(PCI_REVISION_ID, 0x03);
+        break;
+    case i82558B:
+        PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+        PCI_CONFIG_16(PCI_STATUS, 0x2810);
+        PCI_CONFIG_8(PCI_REVISION_ID, 0x05);
+        break;
+    case i82559C:
+        PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+        PCI_CONFIG_16(PCI_STATUS, 0x2810);
+        //~ PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
+        break;
+    case i82559ER:
+        //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
+        PCI_CONFIG_16(PCI_STATUS, 0x2810);
+        PCI_CONFIG_8(PCI_REVISION_ID, 0x09);
+        break;
+    //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1029);
+    //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1030);       /* 82559 InBusiness 10/100 */
+    default:
+        logout("Device %X is undefined!\n", device);
+    }
+
+    if (device == i82557C || device == i82558B || device == i82559C) {
+        logout("Get device id and revision from EEPROM!!!\n");
+    }
+}
+
+static void nic_selective_reset(EEPRO100State * s)
+{
+    size_t i;
+    uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
+    //~ eeprom93xx_reset(s->eeprom);
+    memcpy(eeprom_contents, s->macaddr, 6);
+    eeprom_contents[0xa] = 0x4000;
+    uint16_t sum = 0;
+    for (i = 0; i < EEPROM_SIZE - 1; i++) {
+        sum += eeprom_contents[i];
+    }
+    eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
+
+    memset(s->mem, 0, sizeof(s->mem));
+    uint32_t val = BIT(21);
+    memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val));
+
+    assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
+    memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
+}
+
+static void nic_reset(void *opaque)
+{
+    EEPRO100State *s = (EEPRO100State *) opaque;
+    logout("%p\n", s);
+    static int first;
+    if (!first) {
+        first = 1;
+    }
+    nic_selective_reset(s);
+}
+
+#if defined(DEBUG_EEPRO100)
+static const char *reg[PCI_IO_SIZE / 4] = {
+    "Command/Status",
+    "General Pointer",
+    "Port",
+    "EEPROM/Flash Control",
+    "MDI Control",
+    "Receive DMA Byte Count",
+    "Flow control register",
+    "General Status/Control"
+};
+
+static char *regname(uint32_t addr)
+{
+    static char buf[16];
+    if (addr < PCI_IO_SIZE) {
+        const char *r = reg[addr / 4];
+        if (r != 0) {
+            sprintf(buf, "%s+%u", r, addr % 4);
+        } else {
+            sprintf(buf, "0x%02x", addr);
+        }
+    } else {
+        sprintf(buf, "??? 0x%08x", addr);
+    }
+    return buf;
+}
+#endif                          /* DEBUG_EEPRO100 */
+
+#if 0
+static uint16_t eepro100_read_status(EEPRO100State * s)
+{
+    uint16_t val = s->status;
+    logout("val=0x%04x\n", val);
+    return val;
+}
+
+static void eepro100_write_status(EEPRO100State * s, uint16_t val)
+{
+    logout("val=0x%04x\n", val);
+    s->status = val;
+}
+#endif
+
+/*****************************************************************************
+ *
+ * Command emulation.
+ *
+ ****************************************************************************/
+
+#if 0
+static uint16_t eepro100_read_command(EEPRO100State * s)
+{
+    uint16_t val = 0xffff;
+    //~ logout("val=0x%04x\n", val);
+    return val;
+}
+#endif
+
+/* Commands that can be put in a command list entry. */
+enum commands {
+    CmdNOp = 0,
+    CmdIASetup = 1,
+    CmdConfigure = 2,
+    CmdMulticastList = 3,
+    CmdTx = 4,
+    CmdTDR = 5,                 /* load microcode */
+    CmdDump = 6,
+    CmdDiagnose = 7,
+
+    /* And some extra flags: */
+    CmdSuspend = 0x4000,        /* Suspend after completion. */
+    CmdIntr = 0x2000,           /* Interrupt after completion. */
+    CmdTxFlex = 0x0008,         /* Use "Flexible mode" for CmdTx command. */
+};
+
+static cu_state_t get_cu_state(EEPRO100State * s)
+{
+    return ((s->mem[SCBStatus] >> 6) & 0x03);
+}
+
+static void set_cu_state(EEPRO100State * s, cu_state_t state)
+{
+    s->mem[SCBStatus] = (s->mem[SCBStatus] & 0x3f) + (state << 6);
+}
+
+static ru_state_t get_ru_state(EEPRO100State * s)
+{
+    return ((s->mem[SCBStatus] >> 2) & 0x0f);
+}
+
+static void set_ru_state(EEPRO100State * s, ru_state_t state)
+{
+    s->mem[SCBStatus] = (s->mem[SCBStatus] & 0xc3) + (state << 2);
+}
+
+static void dump_statistics(EEPRO100State * s)
+{
+    /* Dump statistical data. Most data is never changed by the emulation
+     * and always 0, so we first just copy the whole block and then those
+     * values which really matter.
+     * Number of data should check configuration!!!
+     */
+    cpu_physical_memory_write(s->statsaddr, (uint8_t *) & s->statistics, 64);
+    stl_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
+    stl_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
+    stl_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
+    stl_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
+    //~ stw_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
+    //~ stw_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames);
+    //~ missing("CU dump statistical counters");
+}
+
+static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
+{
+    eepro100_tx_t tx;
+    uint32_t cb_address;
+    switch (val) {
+    case CU_NOP:
+        /* No operation. */
+        break;
+    case CU_START:
+        if (get_cu_state(s) != cu_idle) {
+            /* Intel documentation says that CU must be idle for the CU
+             * start command. Intel driver for Linux also starts the CU
+             * from suspended state. */
+            logout("CU state is %u, should be %u\n", get_cu_state(s), cu_idle);
+            //~ assert(!"wrong CU state");
+        }
+        set_cu_state(s, cu_active);
+        s->cu_offset = s->pointer;
+      next_command:
+        cb_address = s->cu_base + s->cu_offset;
+        cpu_physical_memory_read(cb_address, (uint8_t *) & tx, sizeof(tx));
+        uint16_t status = le16_to_cpu(tx.status);
+        uint16_t command = le16_to_cpu(tx.command);
+        logout
+            ("val=0x%02x (cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
+             val, status, command, tx.link);
+        bool bit_el = ((command & 0x8000) != 0);
+        bool bit_s = ((command & 0x4000) != 0);
+        bool bit_i = ((command & 0x2000) != 0);
+        bool bit_nc = ((command & 0x0010) != 0);
+        //~ bool bit_sf = ((command & 0x0008) != 0);
+        uint16_t cmd = command & 0x0007;
+        s->cu_offset = le32_to_cpu(tx.link);
+        switch (cmd) {
+        case CmdNOp:
+            /* Do nothing. */
+            break;
+        case CmdIASetup:
+            cpu_physical_memory_read(cb_address + 8, &s->macaddr[0], 6);
+            logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6));
+            break;
+        case CmdConfigure:
+            cpu_physical_memory_read(cb_address + 8, &s->configuration[0],
+                                     sizeof(s->configuration));
+            logout("configuration: %s\n", nic_dump(&s->configuration[0], 16));
+            break;
+        case CmdMulticastList:
+            //~ missing("multicast list");
+            break;
+        case CmdTx:
+            (void)0;
+            uint32_t tbd_array = le32_to_cpu(tx.tx_desc_addr);
+            uint16_t tcb_bytes = (le16_to_cpu(tx.tcb_bytes) & 0x3fff);
+            logout
+                ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n",
+                 tbd_array, tcb_bytes, tx.tbd_count);
+            assert(!bit_nc);
+            //~ assert(!bit_sf);
+            assert(tcb_bytes <= 2600);
+            /* Next assertion fails for local configuration. */
+            //~ assert((tcb_bytes > 0) || (tbd_array != 0xffffffff));
+            if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
+                logout
+                    ("illegal values of TBD array address and TCB byte count!\n");
+            }
+            uint8_t buf[MAX_ETH_FRAME_SIZE + 4];
+            uint16_t size = 0;
+            uint32_t tbd_address = cb_address + 0x10;
+            assert(tcb_bytes <= sizeof(buf));
+            while (size < tcb_bytes) {
+                uint32_t tx_buffer_address = ldl_phys(tbd_address);
+                uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
+                //~ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+                tbd_address += 8;
+                logout
+                    ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
+                     tx_buffer_address, tx_buffer_size);
+                cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                         tx_buffer_size);
+                size += tx_buffer_size;
+            }
+            if (tbd_array == 0xffffffff) {
+                /* Simplified mode. Was already handled by code above. */
+            } else {
+                /* Flexible mode. */
+                uint8_t tbd_count = 0;
+                if (!(s->configuration[6] & BIT(4))) {
+                    /* Extended TCB. */
+                    assert(tcb_bytes == 0);
+                    for (; tbd_count < 2; tbd_count++) {
+                        uint32_t tx_buffer_address = ldl_phys(tbd_address);
+                        uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
+                        uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+                        tbd_address += 8;
+                        logout
+                            ("TBD (extended mode): buffer address 0x%08x, size 0x%04x\n",
+                             tx_buffer_address, tx_buffer_size);
+                        cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                                 tx_buffer_size);
+                        size += tx_buffer_size;
+                        if (tx_buffer_el & 1) {
+                            break;
+                        }
+                    }
+                }
+                tbd_address = tbd_array;
+                for (; tbd_count < tx.tbd_count; tbd_count++) {
+                    uint32_t tx_buffer_address = ldl_phys(tbd_address);
+                    uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
+                    uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+                    tbd_address += 8;
+                    logout
+                        ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
+                         tx_buffer_address, tx_buffer_size);
+                    cpu_physical_memory_read(tx_buffer_address, &buf[size],
+                                             tx_buffer_size);
+                    size += tx_buffer_size;
+                    if (tx_buffer_el & 1) {
+                        break;
+                    }
+                }
+            }
+            qemu_send_packet(s->vc, buf, size);
+            s->statistics.tx_good_frames++;
+            /* Transmit with bad status would raise an CX/TNO interrupt.
+             * (82557 only). Emulation never has bad status. */
+            //~ eepro100_cx_interrupt(s);
+            break;
+        case CmdTDR:
+            logout("load microcode\n");
+            /* Starting with offset 8, the command contains
+             * 64 dwords microcode which we just ignore here. */
+            break;
+        default:
+            missing("undefined command");
+        }
+        /* Write new status (success). */
+        stw_phys(cb_address, status | 0x8000 | 0x2000);
+        if (bit_i) {
+            /* CU completed action. */
+            eepro100_cx_interrupt(s);
+        }
+        if (bit_el) {
+            /* CU becomes idle. */
+            set_cu_state(s, cu_idle);
+            eepro100_cna_interrupt(s);
+        } else if (bit_s) {
+            /* CU becomes suspended. */
+            set_cu_state(s, cu_suspended);
+            eepro100_cna_interrupt(s);
+        } else {
+            /* More entries in list. */
+            logout("CU list with at least one more entry\n");
+            goto next_command;
+        }
+        logout("CU list empty\n");
+        /* List is empty. Now CU is idle or suspended. */
+        break;
+    case CU_RESUME:
+        if (get_cu_state(s) != cu_suspended) {
+            logout("bad CU resume from CU state %u\n", get_cu_state(s));
+            /* Workaround for bad Linux eepro100 driver which resumes
+             * from idle state. */
+            //~ missing("cu resume");
+            set_cu_state(s, cu_suspended);
+        }
+        if (get_cu_state(s) == cu_suspended) {
+            logout("CU resuming\n");
+            set_cu_state(s, cu_active);
+            goto next_command;
+        }
+        break;
+    case CU_STATSADDR:
+        /* Load dump counters address. */
+        s->statsaddr = s->pointer;
+        logout("val=0x%02x (status address)\n", val);
+        break;
+    case CU_SHOWSTATS:
+        /* Dump statistical counters. */
+        dump_statistics(s);
+        break;
+    case CU_CMD_BASE:
+        /* Load CU base. */
+        logout("val=0x%02x (CU base address)\n", val);
+        s->cu_base = s->pointer;
+        break;
+    case CU_DUMPSTATS:
+        /* Dump and reset statistical counters. */
+        dump_statistics(s);
+        memset(&s->statistics, 0, sizeof(s->statistics));
+        break;
+    case CU_SRESUME:
+        /* CU static resume. */
+        missing("CU static resume");
+        break;
+    default:
+        missing("Undefined CU command");
+    }
+}
+
+static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
+{
+    switch (val) {
+    case RU_NOP:
+        /* No operation. */
+        break;
+    case RX_START:
+        /* RU start. */
+        if (get_ru_state(s) != ru_idle) {
+            logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle);
+            //~ assert(!"wrong RU state");
+        }
+        set_ru_state(s, ru_ready);
+        s->ru_offset = s->pointer;
+        logout("val=0x%02x (rx start)\n", val);
+        break;
+    case RX_RESUME:
+        /* Restart RU. */
+        if (get_ru_state(s) != ru_suspended) {
+            logout("RU state is %u, should be %u\n", get_ru_state(s),
+                   ru_suspended);
+            //~ assert(!"wrong RU state");
+        }
+        set_ru_state(s, ru_ready);
+        break;
+    case RX_ADDR_LOAD:
+        /* Load RU base. */
+        logout("val=0x%02x (RU base address)\n", val);
+        s->ru_base = s->pointer;
+        break;
+    default:
+        logout("val=0x%02x (undefined RU command)\n", val);
+        missing("Undefined SU command");
+    }
+}
+
+static void eepro100_write_command(EEPRO100State * s, uint8_t val)
+{
+    eepro100_ru_command(s, val & 0x0f);
+    eepro100_cu_command(s, val & 0xf0);
+    if ((val) == 0) {
+        logout("val=0x%02x\n", val);
+    }
+    /* Clear command byte after command was accepted. */
+    s->mem[SCBCmd] = 0;
+}
+
+/*****************************************************************************
+ *
+ * EEPROM emulation.
+ *
+ ****************************************************************************/
+
+#define EEPROM_CS       0x02
+#define EEPROM_SK       0x01
+#define EEPROM_DI       0x04
+#define EEPROM_DO       0x08
+
+static uint16_t eepro100_read_eeprom(EEPRO100State * s)
+{
+    uint16_t val;
+    memcpy(&val, &s->mem[SCBeeprom], sizeof(val));
+    if (eeprom93xx_read(s->eeprom)) {
+        val |= EEPROM_DO;
+    } else {
+        val &= ~EEPROM_DO;
+    }
+    return val;
+}
+
+static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
+{
+    logout("write val=0x%02x\n", val);
+
+    /* mask unwriteable bits */
+    //~ val = SET_MASKED(val, 0x31, eeprom->value);
+
+    int eecs = ((val & EEPROM_CS) != 0);
+    int eesk = ((val & EEPROM_SK) != 0);
+    int eedi = ((val & EEPROM_DI) != 0);
+    eeprom93xx_write(eeprom, eecs, eesk, eedi);
+}
+
+static void eepro100_write_pointer(EEPRO100State * s, uint32_t val)
+{
+    s->pointer = le32_to_cpu(val);
+    logout("val=0x%08x\n", val);
+}
+
+/*****************************************************************************
+ *
+ * MDI emulation.
+ *
+ ****************************************************************************/
+
+#if defined(DEBUG_EEPRO100)
+static const char *mdi_op_name[] = {
+    "opcode 0",
+    "write",
+    "read",
+    "opcode 3"
+};
+
+static const char *mdi_reg_name[] = {
+    "Control",
+    "Status",
+    "PHY Identification (Word 1)",
+    "PHY Identification (Word 2)",
+    "Auto-Negotiation Advertisement",
+    "Auto-Negotiation Link Partner Ability",
+    "Auto-Negotiation Expansion"
+};
+#endif                          /* DEBUG_EEPRO100 */
+
+static uint32_t eepro100_read_mdi(EEPRO100State * s)
+{
+    uint32_t val;
+    memcpy(&val, &s->mem[0x10], sizeof(val));
+
+#ifdef DEBUG_EEPRO100
+    uint8_t raiseint = (val & BIT(29)) >> 29;
+    uint8_t opcode = (val & BITS(27, 26)) >> 26;
+    uint8_t phy = (val & BITS(25, 21)) >> 21;
+    uint8_t reg = (val & BITS(20, 16)) >> 16;
+    uint16_t data = (val & BITS(15, 0));
+#endif
+    /* Emulation takes no time to finish MDI transaction. */
+    val |= BIT(28);
+    TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+                      val, raiseint, mdi_op_name[opcode], phy,
+                      mdi_reg_name[reg], data));
+    return val;
+}
+
+//~ #define BITS(val, upper, lower) (val & ???)
+static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
+{
+    uint8_t raiseint = (val & BIT(29)) >> 29;
+    uint8_t opcode = (val & BITS(27, 26)) >> 26;
+    uint8_t phy = (val & BITS(25, 21)) >> 21;
+    uint8_t reg = (val & BITS(20, 16)) >> 16;
+    uint16_t data = (val & BITS(15, 0));
+    if (phy != 1) {
+        /* Unsupported PHY address. */
+        //~ logout("phy must be 1 but is %u\n", phy);
+        data = 0;
+    } else if (opcode != 1 && opcode != 2) {
+        /* Unsupported opcode. */
+        logout("opcode must be 1 or 2 but is %u\n", opcode);
+        data = 0;
+    } else if (reg > 6) {
+        /* Unsupported register. */
+        logout("register must be 0...6 but is %u\n", reg);
+        data = 0;
+    } else {
+        TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+                          val, raiseint, mdi_op_name[opcode], phy,
+                          mdi_reg_name[reg], data));
+        if (opcode == 1) {
+            /* MDI write */
+            switch (reg) {
+            case 0:            /* Control Register */
+                if (data & 0x8000) {
+                    /* Reset status and control registers to default. */
+                    s->mdimem[0] = eepro100_mdi_default[0];
+                    s->mdimem[1] = eepro100_mdi_default[1];
+                    data = s->mdimem[reg];
+                } else {
+                    /* Restart Auto Configuration = Normal Operation */
+                    data &= ~0x0200;
+                }
+                break;
+            case 1:            /* Status Register */
+                missing("not writable");
+                data = s->mdimem[reg];
+                break;
+            case 2:            /* PHY Identification Register (Word 1) */
+            case 3:            /* PHY Identification Register (Word 2) */
+                missing("not implemented");
+                break;
+            case 4:            /* Auto-Negotiation Advertisement Register */
+            case 5:            /* Auto-Negotiation Link Partner Ability Register */
+                break;
+            case 6:            /* Auto-Negotiation Expansion Register */
+            default:
+                missing("not implemented");
+            }
+            s->mdimem[reg] = data;
+        } else if (opcode == 2) {
+            /* MDI read */
+            switch (reg) {
+            case 0:            /* Control Register */
+                if (data & 0x8000) {
+                    /* Reset status and control registers to default. */
+                    s->mdimem[0] = eepro100_mdi_default[0];
+                    s->mdimem[1] = eepro100_mdi_default[1];
+                }
+                break;
+            case 1:            /* Status Register */
+                s->mdimem[reg] |= 0x0020;
+                break;
+            case 2:            /* PHY Identification Register (Word 1) */
+            case 3:            /* PHY Identification Register (Word 2) */
+            case 4:            /* Auto-Negotiation Advertisement Register */
+                break;
+            case 5:            /* Auto-Negotiation Link Partner Ability Register */
+                s->mdimem[reg] = 0x41fe;
+                break;
+            case 6:            /* Auto-Negotiation Expansion Register */
+                s->mdimem[reg] = 0x0001;
+                break;
+            }
+            data = s->mdimem[reg];
+        }
+        /* Emulation takes no time to finish MDI transaction.
+         * Set MDI bit in SCB status register. */
+        s->mem[SCBAck] |= 0x08;
+        val |= BIT(28);
+        if (raiseint) {
+            eepro100_mdi_interrupt(s);
+        }
+    }
+    val = (val & 0xffff0000) + data;
+    memcpy(&s->mem[0x10], &val, sizeof(val));
+}
+
+/*****************************************************************************
+ *
+ * Port emulation.
+ *
+ ****************************************************************************/
+
+#define PORT_SOFTWARE_RESET     0
+#define PORT_SELFTEST           1
+#define PORT_SELECTIVE_RESET    2
+#define PORT_DUMP               3
+#define PORT_SELECTION_MASK     3
+
+typedef struct {
+    uint32_t st_sign;           /* Self Test Signature */
+    uint32_t st_result;         /* Self Test Results */
+} eepro100_selftest_t;
+
+static uint32_t eepro100_read_port(EEPRO100State * s)
+{
+    return 0;
+}
+
+static void eepro100_write_port(EEPRO100State * s, uint32_t val)
+{
+    val = le32_to_cpu(val);
+    uint32_t address = (val & ~PORT_SELECTION_MASK);
+    uint8_t selection = (val & PORT_SELECTION_MASK);
+    switch (selection) {
+    case PORT_SOFTWARE_RESET:
+        nic_reset(s);
+        break;
+    case PORT_SELFTEST:
+        logout("selftest address=0x%08x\n", address);
+        eepro100_selftest_t data;
+        cpu_physical_memory_read(address, (uint8_t *) & data, sizeof(data));
+        data.st_sign = 0xffffffff;
+        data.st_result = 0;
+        cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data));
+        break;
+    case PORT_SELECTIVE_RESET:
+        logout("selective reset, selftest address=0x%08x\n", address);
+        nic_selective_reset(s);
+        break;
+    default:
+        logout("val=0x%08x\n", val);
+        missing("unknown port selection");
+    }
+}
+
+/*****************************************************************************
+ *
+ * General hardware emulation.
+ *
+ ****************************************************************************/
+
+static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
+{
+    uint8_t val;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        memcpy(&val, &s->mem[addr], sizeof(val));
+    }
+
+    switch (addr) {
+    case SCBStatus:
+        //~ val = eepro100_read_status(s);
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        break;
+    case SCBAck:
+        //~ val = eepro100_read_status(s);
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        break;
+    case SCBCmd:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        //~ val = eepro100_read_command(s);
+        break;
+    case SCBIntmask:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        break;
+    case SCBPort + 3:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        break;
+    case SCBeeprom:
+        val = eepro100_read_eeprom(s);
+        break;
+    case 0x1b:                 /* PMDR (power management driver register) */
+        val = 0;
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        break;
+    case 0x1d:                 /* general status register */
+        /* 100 Mbps full duplex, valid link */
+        val = 0x07;
+        logout("addr=General Status val=%02x\n", val);
+        break;
+    default:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        missing("unknown byte read");
+    }
+    return val;
+}
+
+static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
+{
+    uint16_t val;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        memcpy(&val, &s->mem[addr], sizeof(val));
+    }
+
+    logout("addr=%s val=0x%04x\n", regname(addr), val);
+
+    switch (addr) {
+    case SCBStatus:
+        //~ val = eepro100_read_status(s);
+        break;
+    case SCBeeprom:
+        val = eepro100_read_eeprom(s);
+        break;
+    default:
+        logout("addr=%s val=0x%04x\n", regname(addr), val);
+        missing("unknown word read");
+    }
+    return val;
+}
+
+static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
+{
+    uint32_t val;
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        memcpy(&val, &s->mem[addr], sizeof(val));
+    }
+
+    switch (addr) {
+    case SCBStatus:
+        //~ val = eepro100_read_status(s);
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        break;
+    case SCBPointer:
+        //~ val = eepro100_read_pointer(s);
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        break;
+    case SCBPort:
+        val = eepro100_read_port(s);
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        break;
+    case SCBCtrlMDI:
+        val = eepro100_read_mdi(s);
+        break;
+    default:
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        missing("unknown longword read");
+    }
+    return val;
+}
+
+static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
+{
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        memcpy(&s->mem[addr], &val, sizeof(val));
+    }
+
+    logout("addr=%s val=0x%02x\n", regname(addr), val);
+
+    switch (addr) {
+    case SCBStatus:
+        //~ eepro100_write_status(s, val);
+        break;
+    case SCBAck:
+        eepro100_acknowledge(s);
+        break;
+    case SCBCmd:
+        eepro100_write_command(s, val);
+        break;
+    case SCBIntmask:
+        if (val & BIT(1)) {
+            eepro100_swi_interrupt(s);
+        }
+        eepro100_interrupt(s, 0);
+        break;
+    case SCBPort + 3:
+    case SCBFlow:
+    case SCBFlow + 1:
+    case SCBFlow + 2:
+    case SCBFlow + 3:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        break;
+    case SCBeeprom:
+        eepro100_write_eeprom(s->eeprom, val);
+        break;
+    default:
+        logout("addr=%s val=0x%02x\n", regname(addr), val);
+        missing("unknown byte write");
+    }
+}
+
+static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
+{
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        memcpy(&s->mem[addr], &val, sizeof(val));
+    }
+
+    logout("addr=%s val=0x%04x\n", regname(addr), val);
+
+    switch (addr) {
+    case SCBStatus:
+        //~ eepro100_write_status(s, val);
+        eepro100_acknowledge(s);
+        break;
+    case SCBCmd:
+        eepro100_write_command(s, val);
+        eepro100_write1(s, SCBIntmask, val >> 8);
+        break;
+    case SCBeeprom:
+        eepro100_write_eeprom(s->eeprom, val);
+        break;
+    default:
+        logout("addr=%s val=0x%04x\n", regname(addr), val);
+        missing("unknown word write");
+    }
+}
+
+static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
+{
+    if (addr <= sizeof(s->mem) - sizeof(val)) {
+        memcpy(&s->mem[addr], &val, sizeof(val));
+    }
+
+    switch (addr) {
+    case SCBPointer:
+        eepro100_write_pointer(s, val);
+        break;
+    case SCBPort:
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        eepro100_write_port(s, val);
+        break;
+    case SCBCtrlMDI:
+        eepro100_write_mdi(s, val);
+        break;
+    default:
+        logout("addr=%s val=0x%08x\n", regname(addr), val);
+        missing("unknown longword write");
+    }
+}
+
+static uint32_t ioport_read1(void *opaque, uint32_t addr)
+{
+    EEPRO100State *s = opaque;
+    //~ logout("addr=%s\n", regname(addr));
+    return eepro100_read1(s, addr - s->region[1]);
+}
+
+static uint32_t ioport_read2(void *opaque, uint32_t addr)
+{
+    EEPRO100State *s = opaque;
+    return eepro100_read2(s, addr - s->region[1]);
+}
+
+static uint32_t ioport_read4(void *opaque, uint32_t addr)
+{
+    EEPRO100State *s = opaque;
+    return eepro100_read4(s, addr - s->region[1]);
+}
+
+static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+    //~ logout("addr=%s val=0x%02x\n", regname(addr), val);
+    eepro100_write1(s, addr - s->region[1], val);
+}
+
+static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+    eepro100_write2(s, addr - s->region[1], val);
+}
+
+static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+    eepro100_write4(s, addr - s->region[1], val);
+}
+
+/***********************************************************/
+/* PCI EEPRO100 definitions */
+
+typedef struct PCIEEPRO100State {
+    PCIDevice dev;
+    EEPRO100State eepro100;
+} PCIEEPRO100State;
+
+static void pci_map(PCIDevice * pci_dev, int region_num,
+                    uint32_t addr, uint32_t size, int type)
+{
+    PCIEEPRO100State *d = (PCIEEPRO100State *) pci_dev;
+    EEPRO100State *s = &d->eepro100;
+
+    logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
+           region_num, addr, size, type);
+
+    assert(region_num == 1);
+    register_ioport_write(addr, size, 1, ioport_write1, s);
+    register_ioport_read(addr, size, 1, ioport_read1, s);
+    register_ioport_write(addr, size, 2, ioport_write2, s);
+    register_ioport_read(addr, size, 2, ioport_read2, s);
+    register_ioport_write(addr, size, 4, ioport_write4, s);
+    register_ioport_read(addr, size, 4, ioport_read4, s);
+
+    s->region[region_num] = addr;
+}
+
+static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+    addr -= s->region[0];
+    //~ logout("addr=%s val=0x%02x\n", regname(addr), val);
+    eepro100_write1(s, addr, val);
+}
+
+static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+    addr -= s->region[0];
+    //~ logout("addr=%s val=0x%02x\n", regname(addr), val);
+    eepro100_write2(s, addr, val);
+}
+
+static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    EEPRO100State *s = opaque;
+    addr -= s->region[0];
+    //~ logout("addr=%s val=0x%02x\n", regname(addr), val);
+    eepro100_write4(s, addr, val);
+}
+
+static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+    EEPRO100State *s = opaque;
+    addr -= s->region[0];
+    //~ logout("addr=%s\n", regname(addr));
+    return eepro100_read1(s, addr);
+}
+
+static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+    EEPRO100State *s = opaque;
+    addr -= s->region[0];
+    //~ logout("addr=%s\n", regname(addr));
+    return eepro100_read2(s, addr);
+}
+
+static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+    EEPRO100State *s = opaque;
+    addr -= s->region[0];
+    //~ logout("addr=%s\n", regname(addr));
+    return eepro100_read4(s, addr);
+}
+
+static CPUWriteMemoryFunc *pci_mmio_write[] = {
+    pci_mmio_writeb,
+    pci_mmio_writew,
+    pci_mmio_writel
+};
+
+static CPUReadMemoryFunc *pci_mmio_read[] = {
+    pci_mmio_readb,
+    pci_mmio_readw,
+    pci_mmio_readl
+};
+
+static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
+                         uint32_t addr, uint32_t size, int type)
+{
+    PCIEEPRO100State *d = (PCIEEPRO100State *) pci_dev;
+
+    logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
+           region_num, addr, size, type);
+
+    if (region_num == 0) {
+        /* Map control / status registers. */
+        cpu_register_physical_memory(addr, size, d->eepro100.mmio_index);
+        d->eepro100.region[region_num] = addr;
+    }
+}
+
+static int nic_can_receive(void *opaque)
+{
+    EEPRO100State *s = opaque;
+    logout("%p\n", s);
+    return get_ru_state(s) == ru_ready;
+    //~ return !eepro100_buffer_full(s);
+}
+
+#define MIN_BUF_SIZE 60
+
+static void nic_receive(void *opaque, const uint8_t * buf, int size)
+{
+    /* TODO:
+     * - Magic packets should set bit 30 in power management driver register.
+     * - Interesting packets should set bit 29 in power management driver register.
+     */
+    EEPRO100State *s = opaque;
+    uint16_t rfd_status = 0xa000;
+    static const uint8_t broadcast_macaddr[6] =
+        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+    /* TODO: check multiple IA bit. */
+    assert(!(s->configuration[20] & BIT(6)));
+
+    if (s->configuration[8] & 0x80) {
+        /* CSMA is disabled. */
+        logout("%p received while CSMA is disabled\n", s);
+        return;
+    } else if (size < 64 && (s->configuration[7] & 1)) {
+        /* Short frame and configuration byte 7/0 (discard short receive) set:
+         * Short frame is discarded */
+        logout("%p received short frame (%d byte)\n", s, size);
+        s->statistics.rx_short_frame_errors++;
+        //~ return;
+    } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & 8)) {
+        /* Long frame and configuration byte 18/3 (long receive ok) not set:
+         * Long frames are discarded. */
+        logout("%p received long frame (%d byte), ignored\n", s, size);
+        return;
+    } else if (memcmp(buf, s->macaddr, 6) == 0) {       // !!!
+        /* Frame matches individual address. */
+        /* TODO: check configuration byte 15/4 (ignore U/L). */
+        logout("%p received frame for me, len=%d\n", s, size);
+    } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
+        /* Broadcast frame. */
+        logout("%p received broadcast, len=%d\n", s, size);
+        rfd_status |= 0x0002;
+    } else if (buf[0] & 0x01) { // !!!
+        /* Multicast frame. */
+        logout("%p received multicast, len=%d\n", s, size);
+        /* TODO: check multicast all bit. */
+        assert(!(s->configuration[21] & BIT(3)));
+        int mcast_idx = compute_mcast_idx(buf);
+        if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) {
+            return;
+        }
+        rfd_status |= 0x0002;
+    } else if (s->configuration[15] & 1) {
+        /* Promiscuous: receive all. */
+        logout("%p received frame in promiscuous mode, len=%d\n", s, size);
+        rfd_status |= 0x0004;
+    } else {
+        logout("%p received frame, ignored, len=%d,%s\n", s, size,
+               nic_dump(buf, size));
+        return;
+    }
+
+    if (get_ru_state(s) != ru_ready) {
+        /* No ressources available. */
+        logout("no ressources, state=%u\n", get_ru_state(s));
+        s->statistics.rx_resource_errors++;
+        //~ assert(!"no ressources");
+        return;
+    }
+    //~ !!!
+//~ $3 = {status = 0x0, command = 0xc000, link = 0x2d220, rx_buf_addr = 0x207dc, count = 0x0, size = 0x5f8, packet = {0x0 <repeats 1518 times>}}
+    eepro100_rx_t rx;
+    cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx,
+                             offsetof(eepro100_rx_t, packet));
+    uint16_t rfd_command = le16_to_cpu(rx.command);
+    uint16_t rfd_size = le16_to_cpu(rx.size);
+    assert(size <= rfd_size);
+    if (size < 64) {
+        rfd_status |= 0x0080;
+    }
+    logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n", rfd_command,
+           rx.link, rx.rx_buf_addr, rfd_size);
+    stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status),
+             rfd_status);
+    stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size);
+    /* Early receive interrupt not supported. */
+    //~ eepro100_er_interrupt(s);
+    /* Receive CRC Transfer not supported. */
+    assert(!(s->configuration[18] & 4));
+    /* TODO: check stripping enable bit. */
+    //~ assert(!(s->configuration[17] & 1));
+    cpu_physical_memory_write(s->ru_base + s->ru_offset +
+                              offsetof(eepro100_rx_t, packet), buf, size);
+    s->statistics.rx_good_frames++;
+    eepro100_fr_interrupt(s);
+    s->ru_offset = le32_to_cpu(rx.link);
+    if (rfd_command & 0x8000) {
+        /* EL bit is set, so this was the last frame. */
+        assert(0);
+    }
+    if (rfd_command & 0x4000) {
+        /* S bit is set. */
+        set_ru_state(s, ru_suspended);
+    }
+}
+
+static int nic_load(QEMUFile * f, void *opaque, int version_id)
+{
+    EEPRO100State *s = (EEPRO100State *) opaque;
+    int i;
+    int ret;
+
+    if (version_id > 3)
+        return -EINVAL;
+
+    if (s->pci_dev && version_id >= 3) {
+        ret = pci_device_load(s->pci_dev, f);
+        if (ret < 0)
+            return ret;
+    }
+
+    if (version_id >= 2) {
+        qemu_get_8s(f, &s->rxcr);
+    } else {
+        s->rxcr = 0x0c;
+    }
+
+    qemu_get_8s(f, &s->cmd);
+    qemu_get_be32s(f, &s->start);
+    qemu_get_be32s(f, &s->stop);
+    qemu_get_8s(f, &s->boundary);
+    qemu_get_8s(f, &s->tsr);
+    qemu_get_8s(f, &s->tpsr);
+    qemu_get_be16s(f, &s->tcnt);
+    qemu_get_be16s(f, &s->rcnt);
+    qemu_get_be32s(f, &s->rsar);
+    qemu_get_8s(f, &s->rsr);
+    qemu_get_8s(f, &s->isr);
+    qemu_get_8s(f, &s->dcfg);
+    qemu_get_8s(f, &s->imr);
+    qemu_get_buffer(f, s->phys, 6);
+    qemu_get_8s(f, &s->curpag);
+    qemu_get_buffer(f, s->mult, 8);
+    qemu_get_buffer(f, s->mem, sizeof(s->mem));
+
+    /* Restore all members of struct between scv_stat and mem */
+    qemu_get_8s(f, &s->scb_stat);
+    qemu_get_8s(f, &s->int_stat);
+    for (i = 0; i < 3; i++)
+        qemu_get_be32s(f, &s->region[i]);
+    qemu_get_buffer(f, s->macaddr, 6);
+    for (i = 0; i < 19; i++)
+        qemu_get_be32s(f, &s->statcounter[i]);
+    for (i = 0; i < 32; i++)
+        qemu_get_be16s(f, &s->mdimem[i]);
+    /* The eeprom should be saved and restored by its own routines */
+    qemu_get_be32s(f, &s->device);
+    qemu_get_be32s(f, &s->pointer);
+    qemu_get_be32s(f, &s->cu_base);
+    qemu_get_be32s(f, &s->cu_offset);
+    qemu_get_be32s(f, &s->ru_base);
+    qemu_get_be32s(f, &s->ru_offset);
+    qemu_get_be32s(f, &s->statsaddr);
+    /* Restore epro100_stats_t statistics */
+    qemu_get_be32s(f, &s->statistics.tx_good_frames);
+    qemu_get_be32s(f, &s->statistics.tx_max_collisions);
+    qemu_get_be32s(f, &s->statistics.tx_late_collisions);
+    qemu_get_be32s(f, &s->statistics.tx_underruns);
+    qemu_get_be32s(f, &s->statistics.tx_lost_crs);
+    qemu_get_be32s(f, &s->statistics.tx_deferred);
+    qemu_get_be32s(f, &s->statistics.tx_single_collisions);
+    qemu_get_be32s(f, &s->statistics.tx_multiple_collisions);
+    qemu_get_be32s(f, &s->statistics.tx_total_collisions);
+    qemu_get_be32s(f, &s->statistics.rx_good_frames);
+    qemu_get_be32s(f, &s->statistics.rx_crc_errors);
+    qemu_get_be32s(f, &s->statistics.rx_alignment_errors);
+    qemu_get_be32s(f, &s->statistics.rx_resource_errors);
+    qemu_get_be32s(f, &s->statistics.rx_overrun_errors);
+    qemu_get_be32s(f, &s->statistics.rx_cdt_errors);
+    qemu_get_be32s(f, &s->statistics.rx_short_frame_errors);
+    qemu_get_be32s(f, &s->statistics.fc_xmt_pause);
+    qemu_get_be32s(f, &s->statistics.fc_rcv_pause);
+    qemu_get_be32s(f, &s->statistics.fc_rcv_unsupported);
+    qemu_get_be16s(f, &s->statistics.xmt_tco_frames);
+    qemu_get_be16s(f, &s->statistics.rcv_tco_frames);
+    qemu_get_be32s(f, &s->statistics.complete);
+#if 0
+    qemu_get_be16s(f, &s->status);
+#endif
+
+    /* Configuration bytes. */
+    qemu_get_buffer(f, s->configuration, sizeof(s->configuration));
+
+    return 0;
+}
+
+static void nic_save(QEMUFile * f, void *opaque)
+{
+    EEPRO100State *s = (EEPRO100State *) opaque;
+    int i;
+
+    if (s->pci_dev)
+        pci_device_save(s->pci_dev, f);
+
+    qemu_put_8s(f, &s->rxcr);
+
+    qemu_put_8s(f, &s->cmd);
+    qemu_put_be32s(f, &s->start);
+    qemu_put_be32s(f, &s->stop);
+    qemu_put_8s(f, &s->boundary);
+    qemu_put_8s(f, &s->tsr);
+    qemu_put_8s(f, &s->tpsr);
+    qemu_put_be16s(f, &s->tcnt);
+    qemu_put_be16s(f, &s->rcnt);
+    qemu_put_be32s(f, &s->rsar);
+    qemu_put_8s(f, &s->rsr);
+    qemu_put_8s(f, &s->isr);
+    qemu_put_8s(f, &s->dcfg);
+    qemu_put_8s(f, &s->imr);
+    qemu_put_buffer(f, s->phys, 6);
+    qemu_put_8s(f, &s->curpag);
+    qemu_put_buffer(f, s->mult, 8);
+    qemu_put_buffer(f, s->mem, sizeof(s->mem));
+
+    /* Save all members of struct between scv_stat and mem */
+    qemu_put_8s(f, &s->scb_stat);
+    qemu_put_8s(f, &s->int_stat);
+    for (i = 0; i < 3; i++)
+        qemu_put_be32s(f, &s->region[i]);
+    qemu_put_buffer(f, s->macaddr, 6);
+    for (i = 0; i < 19; i++)
+        qemu_put_be32s(f, &s->statcounter[i]);
+    for (i = 0; i < 32; i++)
+        qemu_put_be16s(f, &s->mdimem[i]);
+    /* The eeprom should be saved and restored by its own routines */
+    qemu_put_be32s(f, &s->device);
+    qemu_put_be32s(f, &s->pointer);
+    qemu_put_be32s(f, &s->cu_base);
+    qemu_put_be32s(f, &s->cu_offset);
+    qemu_put_be32s(f, &s->ru_base);
+    qemu_put_be32s(f, &s->ru_offset);
+    qemu_put_be32s(f, &s->statsaddr);
+    /* Save epro100_stats_t statistics */
+    qemu_put_be32s(f, &s->statistics.tx_good_frames);
+    qemu_put_be32s(f, &s->statistics.tx_max_collisions);
+    qemu_put_be32s(f, &s->statistics.tx_late_collisions);
+    qemu_put_be32s(f, &s->statistics.tx_underruns);
+    qemu_put_be32s(f, &s->statistics.tx_lost_crs);
+    qemu_put_be32s(f, &s->statistics.tx_deferred);
+    qemu_put_be32s(f, &s->statistics.tx_single_collisions);
+    qemu_put_be32s(f, &s->statistics.tx_multiple_collisions);
+    qemu_put_be32s(f, &s->statistics.tx_total_collisions);
+    qemu_put_be32s(f, &s->statistics.rx_good_frames);
+    qemu_put_be32s(f, &s->statistics.rx_crc_errors);
+    qemu_put_be32s(f, &s->statistics.rx_alignment_errors);
+    qemu_put_be32s(f, &s->statistics.rx_resource_errors);
+    qemu_put_be32s(f, &s->statistics.rx_overrun_errors);
+    qemu_put_be32s(f, &s->statistics.rx_cdt_errors);
+    qemu_put_be32s(f, &s->statistics.rx_short_frame_errors);
+    qemu_put_be32s(f, &s->statistics.fc_xmt_pause);
+    qemu_put_be32s(f, &s->statistics.fc_rcv_pause);
+    qemu_put_be32s(f, &s->statistics.fc_rcv_unsupported);
+    qemu_put_be16s(f, &s->statistics.xmt_tco_frames);
+    qemu_put_be16s(f, &s->statistics.rcv_tco_frames);
+    qemu_put_be32s(f, &s->statistics.complete);
+#if 0
+    qemu_put_be16s(f, &s->status);
+#endif
+
+    /* Configuration bytes. */
+    qemu_put_buffer(f, s->configuration, sizeof(s->configuration));
+}
+
+static void nic_init(PCIBus * bus, NICInfo * nd,
+                     const char *name, uint32_t device)
+{
+    PCIEEPRO100State *d;
+    EEPRO100State *s;
+
+    logout("\n");
+
+    d = (PCIEEPRO100State *) pci_register_device(bus, name,
+                                                 sizeof(PCIEEPRO100State), -1,
+                                                 NULL, NULL);
+
+    s = &d->eepro100;
+    s->device = device;
+    s->pci_dev = &d->dev;
+
+    pci_reset(s);
+
+    /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
+     * i82559 and later support 64 or 256 word EEPROM. */
+    s->eeprom = eeprom93xx_new(EEPROM_SIZE);
+
+    /* Handler for memory-mapped I/O */
+    d->eepro100.mmio_index =
+        cpu_register_io_memory(0, pci_mmio_read, pci_mmio_write, s);
+
+    pci_register_io_region(&d->dev, 0, PCI_MEM_SIZE,
+                           PCI_ADDRESS_SPACE_MEM |
+                           PCI_ADDRESS_SPACE_MEM_PREFETCH, pci_mmio_map);
+    pci_register_io_region(&d->dev, 1, PCI_IO_SIZE, PCI_ADDRESS_SPACE_IO,
+                           pci_map);
+    pci_register_io_region(&d->dev, 2, PCI_FLASH_SIZE, PCI_ADDRESS_SPACE_MEM,
+                           pci_mmio_map);
+
+    memcpy(s->macaddr, nd->macaddr, 6);
+    logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6));
+    assert(s->region[1] == 0);
+
+    nic_reset(s);
+
+    s->vc = qemu_new_vlan_client(nd->vlan, nic_receive, nic_can_receive, s);
+
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+             "eepro100 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+             s->macaddr[0],
+             s->macaddr[1],
+             s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]);
+
+    qemu_register_reset(nic_reset, s);
+
+    /* XXX: instance number ? */
+    register_savevm(name, 0, 3, nic_save, nic_load, s);
+}
+
+void pci_i82551_init(PCIBus * bus, NICInfo * nd, int devfn)
+{
+    nic_init(bus, nd, "i82551", i82551);
+    //~ uint8_t *pci_conf = d->dev.config;
+}
+
+void pci_i82557b_init(PCIBus * bus, NICInfo * nd, int devfn)
+{
+    nic_init(bus, nd, "i82557b", i82557B);
+}
+
+void pci_i82559er_init(PCIBus * bus, NICInfo * nd, int devfn)
+{
+    nic_init(bus, nd, "i82559er", i82559ER);
+}
+
+/* eof */
diff --git a/hw/eeprom93xx.c b/hw/eeprom93xx.c
new file mode 100644
index 0000000..14f0189
--- /dev/null
+++ b/hw/eeprom93xx.c
@@ -0,0 +1,312 @@
+/*
+ * QEMU EEPROM 93xx emulation
+ *
+ * Copyright (c) 2006-2007 Stefan Weil
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/* Emulation for serial EEPROMs:
+ * NMC93C06 256-Bit (16 x 16)
+ * NMC93C46 1024-Bit (64 x 16)
+ * NMC93C56 2028 Bit (128 x 16)
+ * NMC93C66 4096 Bit (256 x 16)
+ * Compatible devices include FM93C46 and others.
+ *
+ * Other drivers use these interface functions:
+ * eeprom93xx_new   - add a new EEPROM (with 16, 64 or 256 words)
+ * eeprom93xx_free  - destroy EEPROM
+ * eeprom93xx_read  - read data from the EEPROM
+ * eeprom93xx_write - write data to the EEPROM
+ * eeprom93xx_data  - get EEPROM data array for external manipulation
+ *
+ * Todo list:
+ * - No emulation of EEPROM timings.
+ */
+
+#include <assert.h>
+#include "eeprom93xx.h"
+
+/* Debug EEPROM emulation. */
+//~ #define DEBUG_EEPROM
+
+#ifdef DEBUG_EEPROM
+#define logout(fmt, args...) fprintf(stderr, "EEPROM\t%-24s" fmt, __func__, ##args)
+#else
+#define logout(fmt, args...) ((void)0)
+#endif
+
+static int eeprom_instance = 0;
+static const int eeprom_version = 20061112;
+
+#if 0
+typedef enum {
+  eeprom_read  = 0x80,   /* read register xx */
+  eeprom_write = 0x40,   /* write register xx */
+  eeprom_erase = 0xc0,   /* erase register xx */
+  eeprom_ewen  = 0x30,   /* erase / write enable */
+  eeprom_ewds  = 0x00,   /* erase / write disable */
+  eeprom_eral  = 0x20,   /* erase all registers */
+  eeprom_wral  = 0x10,   /* write all registers */
+  eeprom_amask = 0x0f,
+  eeprom_imask = 0xf0
+} eeprom_instruction_t;
+#endif
+
+#ifdef DEBUG_EEPROM
+static const char *opstring[] = {
+  "extended", "write", "read", "erase"
+};
+#endif
+
+struct _eeprom_t {
+    uint8_t  tick;
+    uint8_t  address;
+    uint8_t  command;
+    uint8_t  writeable;
+
+    uint8_t eecs;
+    uint8_t eesk;
+    uint8_t eedo;
+
+    uint8_t  addrbits;
+    uint8_t  size;
+    uint16_t data;
+    uint16_t contents[0];
+};
+
+/* Code for saving and restoring of EEPROM state. */
+
+static void eeprom_save(QEMUFile *f, void *opaque)
+{
+    /* Save EEPROM data. */
+    unsigned address;
+    eeprom_t *eeprom = (eeprom_t *)opaque;
+    qemu_put_buffer(f, (uint8_t *)eeprom, sizeof(*eeprom) - 2);
+    qemu_put_be16(f, eeprom->data);
+    for (address = 0; address < eeprom->size; address++) {
+        qemu_put_be16(f, eeprom->contents[address]);
+    }
+}
+
+static int eeprom_load(QEMUFile *f, void *opaque, int version_id)
+{
+    /* Load EEPROM data from saved data if version and EEPROM size
+       of data and current EEPROM are identical. */
+    eeprom_t *eeprom = (eeprom_t *)opaque;
+    int result = -EINVAL;
+    if (version_id == eeprom_version) {
+        unsigned address;
+        uint8_t size = eeprom->size;
+        qemu_get_buffer(f, (uint8_t *)eeprom, sizeof(*eeprom) - 2);
+        if (eeprom->size == size) {
+            eeprom->data = qemu_get_be16(f);
+            for (address = 0; address < eeprom->size; address++) {
+                eeprom->contents[address] = qemu_get_be16(f);
+            }
+            result = 0;
+        }
+    }
+    return result;
+}
+
+void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
+{
+    uint8_t tick = eeprom->tick;
+    uint8_t eedo = eeprom->eedo;
+    uint16_t address = eeprom->address;
+    uint8_t command = eeprom->command;
+
+    logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
+           eecs, eesk, eedi, eedo, tick);
+
+    if (! eeprom->eecs && eecs) {
+        /* Start chip select cycle. */
+        logout("Cycle start, waiting for 1st start bit (0)\n");
+        tick = 0;
+        command = 0x0;
+        address = 0x0;
+    } else if (eeprom->eecs && ! eecs) {
+        /* End chip select cycle. This triggers write / erase. */
+        if (eeprom->writeable) {
+            uint8_t subcommand = address >> (eeprom->addrbits - 2);
+            if (command == 0 && subcommand == 2) {
+                /* Erase all. */
+                for (address = 0; address < eeprom->size; address++) {
+                    eeprom->contents[address] = 0xffff;
+                }
+            } else if (command == 3) {
+                /* Erase word. */
+                eeprom->contents[address] = 0xffff;
+            } else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
+                if (command == 1) {
+                    /* Write word. */
+                    eeprom->contents[address] &= eeprom->data;
+                } else if (command == 0 && subcommand == 1) {
+                    /* Write all. */
+                    for (address = 0; address < eeprom->size; address++) {
+                        eeprom->contents[address] &= eeprom->data;
+                    }
+                }
+            }
+        }
+        /* Output DO is tristate, read results in 1. */
+        eedo = 1;
+    } else if (eecs && ! eeprom->eesk && eesk) {
+        /* Raising edge of clock shifts data in. */
+        if (tick == 0) {
+            /* Wait for 1st start bit. */
+            if (eedi == 0) {
+                logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");
+                tick++;
+            } else {
+                logout("wrong 1st start bit (is 1, should be 0)\n");
+                tick = 2;
+                //~ assert(!"wrong start bit");
+            }
+        } else if (tick == 1) {
+            /* Wait for 2nd start bit. */
+            if (eedi != 0) {
+                logout("Got correct 2nd start bit, getting command + address\n");
+                tick++;
+            } else {
+                logout("1st start bit is longer than needed\n");
+            }
+        } else if (tick < 2 + 2) {
+            /* Got 2 start bits, transfer 2 opcode bits. */
+            tick++;
+            command <<= 1;
+            if (eedi) {
+                command += 1;
+            }
+        } else if (tick < 2 + 2 + eeprom->addrbits) {
+            /* Got 2 start bits and 2 opcode bits, transfer all address bits. */
+            tick++;
+            address = ((address << 1) | eedi);
+            if (tick == 2 + 2 + eeprom->addrbits) {
+                logout("%s command, address = 0x%02x (value 0x%04x)\n",
+                       opstring[command], address, eeprom->contents[address]);
+                if (command == 2) {
+                    eedo = 0;
+                }
+                address = address % eeprom->size;
+                if (command == 0) {
+                    /* Command code in upper 2 bits of address. */
+                    switch (address >> (eeprom->addrbits - 2)) {
+                        case 0:
+                            logout("write disable command\n");
+                            eeprom->writeable = 0;
+                            break;
+                        case 1:
+                            logout("write all command\n");
+                            break;
+                        case 2:
+                            logout("erase all command\n");
+                            break;
+                        case 3:
+                            logout("write enable command\n");
+                            eeprom->writeable = 1;
+                            break;
+                    }
+                } else {
+                    /* Read, write or erase word. */
+                    eeprom->data = eeprom->contents[address];
+                }
+            }
+        } else if (tick < 2 + 2 + eeprom->addrbits + 16) {
+            /* Transfer 16 data bits. */
+            tick++;
+            if (command == 2) {
+                /* Read word. */
+                eedo = ((eeprom->data & 0x8000) != 0);
+            }
+            eeprom->data <<= 1;
+            eeprom->data += eedi;
+        } else {
+            logout("additional unneeded tick, not processed\n");
+        }
+    }
+    /* Save status of EEPROM. */
+    eeprom->tick = tick;
+    eeprom->eecs = eecs;
+    eeprom->eesk = eesk;
+    eeprom->eedo = eedo;
+    eeprom->address = address;
+    eeprom->command = command;
+}
+
+uint16_t eeprom93xx_read(eeprom_t *eeprom)
+{
+    /* Return status of pin DO (0 or 1). */
+    logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo);
+    return (eeprom->eedo);
+}
+
+#if 0
+void eeprom93xx_reset(eeprom_t *eeprom)
+{
+    /* prepare eeprom */
+    logout("eeprom = 0x%p\n", eeprom);
+    eeprom->tick = 0;
+    eeprom->command = 0;
+}
+#endif
+
+eeprom_t *eeprom93xx_new(uint16_t nwords)
+{
+    /* Add a new EEPROM (with 16, 64 or 256 words). */
+    eeprom_t *eeprom;
+    uint8_t addrbits;
+
+    switch (nwords) {
+        case 16:
+        case 64:
+            addrbits = 6;
+            break;
+        case 128:
+        case 256:
+            addrbits = 8;
+            break;
+        default:
+            assert(!"Unsupported EEPROM size, fallback to 64 words!");
+            nwords = 64;
+            addrbits = 6;
+    }
+
+    eeprom = (eeprom_t *)qemu_mallocz(sizeof(*eeprom) + nwords * 2);
+    eeprom->size = nwords;
+    eeprom->addrbits = addrbits;
+    /* Output DO is tristate, read results in 1. */
+    eeprom->eedo = 1;
+    logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
+    register_savevm("eeprom", eeprom_instance, eeprom_version,
+                    eeprom_save, eeprom_load, eeprom);
+    return eeprom;
+}
+
+void eeprom93xx_free(eeprom_t *eeprom)
+{
+    /* Destroy EEPROM. */
+    logout("eeprom = 0x%p\n", eeprom);
+    qemu_free(eeprom);
+}
+
+uint16_t *eeprom93xx_data(eeprom_t *eeprom)
+{
+    /* Get EEPROM data array. */
+    return &eeprom->contents[0];
+}
+
+/* eof */
diff --git a/hw/eeprom93xx.h b/hw/eeprom93xx.h
new file mode 100644
index 0000000..fde4912
--- /dev/null
+++ b/hw/eeprom93xx.h
@@ -0,0 +1,43 @@
+/*
+ * QEMU EEPROM 93xx emulation
+ *
+ * Copyright (c) 2006-2007 Stefan Weil
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef EEPROM93XX_H
+#define EEPROM93XX_H
+
+#include "vl.h"
+
+typedef struct _eeprom_t eeprom_t;
+
+/* Create a new EEPROM with (nwords * 2) bytes. */
+eeprom_t *eeprom93xx_new(uint16_t nwords);
+
+/* Destroy an existing EEPROM. */
+void eeprom93xx_free(eeprom_t *eeprom);
+
+/* Read from the EEPROM. */
+uint16_t eeprom93xx_read(eeprom_t *eeprom);
+
+/* Write to the EEPROM. */
+void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi);
+
+/* Get EEPROM data array. */
+uint16_t *eeprom93xx_data(eeprom_t *eeprom);
+
+#endif /* EEPROM93XX_H */
diff --git a/hw/es1370.c b/hw/es1370.c
index 0d2d861..d607a94 100644
--- a/hw/es1370.c
+++ b/hw/es1370.c
@@ -324,7 +324,7 @@
     else {
         s->status = new_status & ~STAT_INTR;
     }
-    pci_set_irq (s->pci_dev, 0, !!level);
+    qemu_set_irq(s->pci_dev->irq[0], !!level);
 }
 
 static void es1370_reset (ES1370State *s)
@@ -350,7 +350,7 @@
             s->dac_voice[i] = NULL;
         }
     }
-    pci_set_irq (s->pci_dev, 0, 0);
+    qemu_irq_lower(s->pci_dev->irq[0]);
 }
 
 static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
diff --git a/hw/esp.c b/hw/esp.c
index fea08d8..943a159 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -1,8 +1,8 @@
 /*
  * QEMU ESP/NCR53C9x emulation
- * 
+ *
  * Copyright (c) 2005-2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -41,7 +41,9 @@
 #define DPRINTF(fmt, args...)
 #endif
 
-#define ESP_MAXREG 0x3f
+#define ESP_MASK 0x3f
+#define ESP_REGS 16
+#define ESP_SIZE (ESP_REGS * 4)
 #define TI_BUFSZ 32
 /* The HBA is ID 7, so for simplicitly limit to 7 devices.  */
 #define ESP_MAX_DEVS      7
@@ -49,9 +51,10 @@
 typedef struct ESPState ESPState;
 
 struct ESPState {
+    qemu_irq irq;
     BlockDriverState **bd;
-    uint8_t rregs[ESP_MAXREG];
-    uint8_t wregs[ESP_MAXREG];
+    uint8_t rregs[ESP_REGS];
+    uint8_t wregs[ESP_REGS];
     int32_t ti_size;
     uint32_t ti_rptr, ti_wptr;
     uint8_t ti_buf[TI_BUFSZ];
@@ -124,7 +127,7 @@
 	s->rregs[4] = STAT_IN;
 	s->rregs[5] = INTR_DC;
 	s->rregs[6] = SEQ_0;
-	espdma_raise_irq(s->dma_opaque);
+	qemu_irq_raise(s->irq);
 	return 0;
     }
     s->current_dev = s->scsi_dev[target];
@@ -154,7 +157,7 @@
     }
     s->rregs[5] = INTR_BS | INTR_FC;
     s->rregs[6] = SEQ_CD;
-    espdma_raise_irq(s->dma_opaque);
+    qemu_irq_raise(s->irq);
 }
 
 static void handle_satn(ESPState *s)
@@ -176,7 +179,7 @@
         s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
         s->rregs[5] = INTR_BS | INTR_FC;
         s->rregs[6] = SEQ_CD;
-        espdma_raise_irq(s->dma_opaque);
+        qemu_irq_raise(s->irq);
     }
 }
 
@@ -196,7 +199,7 @@
 	s->ti_wptr = 0;
 	s->rregs[7] = 2;
     }
-    espdma_raise_irq(s->dma_opaque);
+    qemu_irq_raise(s->irq);
 }
 
 static void esp_dma_done(ESPState *s)
@@ -207,7 +210,7 @@
     s->rregs[7] = 0;
     s->rregs[0] = 0;
     s->rregs[1] = 0;
-    espdma_raise_irq(s->dma_opaque);
+    qemu_irq_raise(s->irq);
 }
 
 static void esp_do_dma(ESPState *s)
@@ -327,12 +330,12 @@
     }
 }
 
-void esp_reset(void *opaque)
+static void esp_reset(void *opaque)
 {
     ESPState *s = opaque;
 
-    memset(s->rregs, 0, ESP_MAXREG);
-    memset(s->wregs, 0, ESP_MAXREG);
+    memset(s->rregs, 0, ESP_REGS);
+    memset(s->wregs, 0, ESP_REGS);
     s->rregs[0x0e] = 0x4; // Indicate fas100a
     s->ti_size = 0;
     s->ti_rptr = 0;
@@ -341,12 +344,18 @@
     s->do_cmd = 0;
 }
 
+static void parent_esp_reset(void *opaque, int irq, int level)
+{
+    if (level)
+        esp_reset(opaque);
+}
+
 static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
 {
     ESPState *s = opaque;
     uint32_t saddr;
 
-    saddr = (addr & ESP_MAXREG) >> 2;
+    saddr = (addr & ESP_MASK) >> 2;
     DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
     switch (saddr) {
     case 2:
@@ -360,7 +369,7 @@
             } else {
                 s->rregs[2] = s->ti_buf[s->ti_rptr++];
             }
-            espdma_raise_irq(s->dma_opaque);
+            qemu_irq_raise(s->irq);
 	}
 	if (s->ti_size == 0) {
             s->ti_rptr = 0;
@@ -371,7 +380,7 @@
         // interrupt
         // Clear interrupt/error status bits
         s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE);
-	espdma_clear_irq(s->dma_opaque);
+	qemu_irq_lower(s->irq);
         break;
     default:
 	break;
@@ -384,7 +393,7 @@
     ESPState *s = opaque;
     uint32_t saddr;
 
-    saddr = (addr & ESP_MAXREG) >> 2;
+    saddr = (addr & ESP_MASK) >> 2;
     DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
     switch (saddr) {
     case 0:
@@ -434,7 +443,7 @@
 	    DPRINTF("Bus reset (%2.2x)\n", val);
 	    s->rregs[5] = INTR_RST;
             if (!(s->wregs[8] & 0x40)) {
-                espdma_raise_irq(s->dma_opaque);
+                qemu_irq_raise(s->irq);
             }
 	    break;
 	case 0x10:
@@ -461,6 +470,9 @@
 	    DPRINTF("Set ATN & stop (%2.2x)\n", val);
 	    handle_satn_stop(s);
 	    break;
+        case 0x44:
+            DPRINTF("Enable selection (%2.2x)\n", val);
+            break;
 	default:
 	    DPRINTF("Unhandled ESP command (%2.2x)\n", val);
 	    break;
@@ -501,29 +513,40 @@
 {
     ESPState *s = opaque;
 
-    qemu_put_buffer(f, s->rregs, ESP_MAXREG);
-    qemu_put_buffer(f, s->wregs, ESP_MAXREG);
+    qemu_put_buffer(f, s->rregs, ESP_REGS);
+    qemu_put_buffer(f, s->wregs, ESP_REGS);
     qemu_put_be32s(f, &s->ti_size);
     qemu_put_be32s(f, &s->ti_rptr);
     qemu_put_be32s(f, &s->ti_wptr);
     qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
+    qemu_put_be32s(f, &s->sense);
     qemu_put_be32s(f, &s->dma);
+    qemu_put_buffer(f, s->cmdbuf, TI_BUFSZ);
+    qemu_put_be32s(f, &s->cmdlen);
+    qemu_put_be32s(f, &s->do_cmd);
+    qemu_put_be32s(f, &s->dma_left);
+    // There should be no transfers in progress, so dma_counter is not saved
 }
 
 static int esp_load(QEMUFile *f, void *opaque, int version_id)
 {
     ESPState *s = opaque;
-    
-    if (version_id != 2)
-        return -EINVAL; // Cannot emulate 1
 
-    qemu_get_buffer(f, s->rregs, ESP_MAXREG);
-    qemu_get_buffer(f, s->wregs, ESP_MAXREG);
+    if (version_id != 3)
+        return -EINVAL; // Cannot emulate 2
+
+    qemu_get_buffer(f, s->rregs, ESP_REGS);
+    qemu_get_buffer(f, s->wregs, ESP_REGS);
     qemu_get_be32s(f, &s->ti_size);
     qemu_get_be32s(f, &s->ti_rptr);
     qemu_get_be32s(f, &s->ti_wptr);
     qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
+    qemu_get_be32s(f, &s->sense);
     qemu_get_be32s(f, &s->dma);
+    qemu_get_buffer(f, s->cmdbuf, TI_BUFSZ);
+    qemu_get_be32s(f, &s->cmdlen);
+    qemu_get_be32s(f, &s->do_cmd);
+    qemu_get_be32s(f, &s->dma_left);
 
     return 0;
 }
@@ -551,7 +574,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, qemu_irq irq, qemu_irq *reset)
 {
     ESPState *s;
     int esp_io_memory;
@@ -561,15 +585,18 @@
         return NULL;
 
     s->bd = bd;
+    s->irq = irq;
     s->dma_opaque = dma_opaque;
 
     esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
-    cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
+    cpu_register_physical_memory(espaddr, ESP_SIZE, esp_io_memory);
 
     esp_reset(s);
 
-    register_savevm("esp", espaddr, 2, esp_save, esp_load, s);
+    register_savevm("esp", espaddr, 3, esp_save, esp_load, s);
     qemu_register_reset(esp_reset, s);
 
+    *reset = *qemu_allocate_irqs(parent_esp_reset, s, 1);
+
     return s;
 }
diff --git a/hw/fdc.c b/hw/fdc.c
index 0012834..dcd1d46 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Floppy disk emulator (Intel 82078)
- * 
- * Copyright (c) 2003 Jocelyn Mayer
- * 
+ *
+ * Copyright (c) 2003, 2007 Jocelyn Mayer
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -217,7 +217,7 @@
     { FDRIVE_DRV_120, FDRIVE_DISK_288,  9, 40, 0,  "180 kB 5\"1/4", },
     { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1,  "410 kB 5\"1/4", },
     { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1,  "420 kB 5\"1/4", },
-    /* 320 kB 5"1/4 floppy disks */ 
+    /* 320 kB 5"1/4 floppy disks */
     { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 1,  "320 kB 5\"1/4", },
     { FDRIVE_DRV_120, FDRIVE_DISK_288,  8, 40, 0,  "160 kB 5\"1/4", },
     /* 360 kB must match 5"1/4 better than 3"1/2... */
@@ -368,9 +368,9 @@
     /* Controller's identification */
     uint8_t version;
     /* HW */
-    int irq_lvl;
+    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, 
+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] = {
@@ -485,8 +485,101 @@
     fdctrl_write_mem,
 };
 
-fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, 
-                       uint32_t io_base,
+static void fd_save (QEMUFile *f, fdrive_t *fd)
+{
+    uint8_t tmp;
+
+    tmp = fd->drflags;
+    qemu_put_8s(f, &tmp);
+    qemu_put_8s(f, &fd->head);
+    qemu_put_8s(f, &fd->track);
+    qemu_put_8s(f, &fd->sect);
+    qemu_put_8s(f, &fd->dir);
+    qemu_put_8s(f, &fd->rw);
+}
+
+static void fdc_save (QEMUFile *f, void *opaque)
+{
+    fdctrl_t *s = opaque;
+
+    qemu_put_8s(f, &s->state);
+    qemu_put_8s(f, &s->dma_en);
+    qemu_put_8s(f, &s->cur_drv);
+    qemu_put_8s(f, &s->bootsel);
+    qemu_put_buffer(f, s->fifo, FD_SECTOR_LEN);
+    qemu_put_be32s(f, &s->data_pos);
+    qemu_put_be32s(f, &s->data_len);
+    qemu_put_8s(f, &s->data_state);
+    qemu_put_8s(f, &s->data_dir);
+    qemu_put_8s(f, &s->int_status);
+    qemu_put_8s(f, &s->eot);
+    qemu_put_8s(f, &s->timer0);
+    qemu_put_8s(f, &s->timer1);
+    qemu_put_8s(f, &s->precomp_trk);
+    qemu_put_8s(f, &s->config);
+    qemu_put_8s(f, &s->lock);
+    qemu_put_8s(f, &s->pwrd);
+    fd_save(f, &s->drives[0]);
+    fd_save(f, &s->drives[1]);
+}
+
+static int fd_load (QEMUFile *f, fdrive_t *fd)
+{
+    uint8_t tmp;
+
+    qemu_get_8s(f, &tmp);
+    fd->drflags = tmp;
+    qemu_get_8s(f, &fd->head);
+    qemu_get_8s(f, &fd->track);
+    qemu_get_8s(f, &fd->sect);
+    qemu_get_8s(f, &fd->dir);
+    qemu_get_8s(f, &fd->rw);
+
+    return 0;
+}
+
+static int fdc_load (QEMUFile *f, void *opaque, int version_id)
+{
+    fdctrl_t *s = opaque;
+    int ret;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_8s(f, &s->state);
+    qemu_get_8s(f, &s->dma_en);
+    qemu_get_8s(f, &s->cur_drv);
+    qemu_get_8s(f, &s->bootsel);
+    qemu_get_buffer(f, s->fifo, FD_SECTOR_LEN);
+    qemu_get_be32s(f, &s->data_pos);
+    qemu_get_be32s(f, &s->data_len);
+    qemu_get_8s(f, &s->data_state);
+    qemu_get_8s(f, &s->data_dir);
+    qemu_get_8s(f, &s->int_status);
+    qemu_get_8s(f, &s->eot);
+    qemu_get_8s(f, &s->timer0);
+    qemu_get_8s(f, &s->timer1);
+    qemu_get_8s(f, &s->precomp_trk);
+    qemu_get_8s(f, &s->config);
+    qemu_get_8s(f, &s->lock);
+    qemu_get_8s(f, &s->pwrd);
+
+    ret = fd_load(f, &s->drives[0]);
+    if (ret == 0)
+        ret = fd_load(f, &s->drives[1]);
+
+    return ret;
+}
+
+static void fdctrl_external_reset(void *opaque)
+{
+    fdctrl_t *s = opaque;
+
+    fdctrl_reset(s, 0);
+}
+
+fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
+                       target_phys_addr_t io_base,
                        BlockDriverState **fds)
 {
     fdctrl_t *fdctrl;
@@ -497,11 +590,11 @@
     fdctrl = qemu_mallocz(sizeof(fdctrl_t));
     if (!fdctrl)
         return NULL;
-    fdctrl->result_timer = qemu_new_timer(vm_clock, 
+    fdctrl->result_timer = qemu_new_timer(vm_clock,
                                           fdctrl_result_timer, fdctrl);
 
     fdctrl->version = 0x90; /* Intel 82078 controller */
-    fdctrl->irq_lvl = irq_lvl;
+    fdctrl->irq = irq;
     fdctrl->dma_chann = dma_chann;
     fdctrl->io_base = io_base;
     fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
@@ -520,11 +613,17 @@
         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);
     for (i = 0; i < 2; i++) {
         fd_revalidate(&fdctrl->drives[i]);
     }
@@ -542,7 +641,7 @@
 static void fdctrl_reset_irq (fdctrl_t *fdctrl)
 {
     FLOPPY_DPRINTF("Reset interrupt\n");
-    pic_set_irq(fdctrl->irq_lvl, 0);
+    qemu_set_irq(fdctrl->irq, 0);
     fdctrl->state &= ~FD_CTRL_INTR;
 }
 
@@ -557,7 +656,7 @@
     }
 #endif
     if (~(fdctrl->state & FD_CTRL_INTR)) {
-        pic_set_irq(fdctrl->irq_lvl, 1);
+        qemu_set_irq(fdctrl->irq, 1);
         fdctrl->state |= FD_CTRL_INTR;
     }
     FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
@@ -743,7 +842,7 @@
 static int fdctrl_media_changed(fdrive_t *drv)
 {
     int ret;
-    if (!drv->bs) 
+    if (!drv->bs)
         return 0;
     ret = bdrv_media_changed(drv->bs);
     if (ret) {
@@ -1042,7 +1141,7 @@
 		cur_drv->sect = 1;
 		if (FD_MULTI_TRACK(fdctrl->data_state)) {
 		    if (cur_drv->head == 0 &&
-			(cur_drv->flags & FDISK_DBL_SIDES) != 0) {	
+			(cur_drv->flags & FDISK_DBL_SIDES) != 0) {
                         cur_drv->head = 1;
                     } else {
                         cur_drv->head = 0;
@@ -1169,7 +1268,7 @@
     memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
     if (cur_drv->bs == NULL ||
         bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
-        FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv));
+        FLOPPY_ERROR("formatting sector %d\n", fd_sector(cur_drv));
         fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
     } else {
 	if (cur_drv->sect == cur_drv->last_sect) {
@@ -1633,7 +1732,7 @@
             FLOPPY_DPRINTF("treat READ_ID command\n");
             /* XXX: should set main status register to busy */
             cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
-            qemu_mod_timer(fdctrl->result_timer, 
+            qemu_mod_timer(fdctrl->result_timer,
                            qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
             break;
         case 0x4C:
@@ -1744,5 +1843,13 @@
 static void fdctrl_result_timer(void *opaque)
 {
     fdctrl_t *fdctrl = opaque;
+    fdrive_t *cur_drv = get_cur_drv(fdctrl);
+    /* Pretend we are spinning.
+     * This is needed for Coherent, which uses READ ID to check for
+     * sector interleaving.
+     */
+    if (cur_drv->last_sect != 0) {
+        cur_drv->sect = (cur_drv->sect % cur_drv->last_sect) + 1;
+    }
     fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
 }
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
index 4004f99..fb46051 100644
--- a/hw/grackle_pci.c
+++ b/hw/grackle_pci.c
@@ -2,7 +2,7 @@
  * QEMU Grackle (heathrow PPC) PCI host
  *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -80,12 +80,12 @@
     return (irq_num + (pci_dev->devfn >> 3)) & 3;
 }
 
-static void pci_grackle_set_irq(void *pic, int irq_num, int level)
+static void pci_grackle_set_irq(qemu_irq *pic, int irq_num, int level)
 {
-    heathrow_pic_set_irq(pic, irq_num + 8, level);
+    qemu_set_irq(pic[irq_num + 8], level);
 }
 
-PCIBus *pci_grackle_init(uint32_t base, void *pic)
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
 {
     GrackleState *s;
     PCIDevice *d;
@@ -95,13 +95,13 @@
     s->bus = pci_register_bus(pci_grackle_set_irq, pci_grackle_map_irq,
                               pic, 0, 0);
 
-    pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read, 
+    pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
                                             pci_grackle_config_write, s);
     pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
                                           pci_grackle_write, s);
     cpu_register_physical_memory(base, 0x1000, pci_mem_config);
     cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
-    d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice), 
+    d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice),
                             0, NULL, NULL);
     d->config[0x00] = 0x57; // vendor_id
     d->config[0x01] = 0x10;
@@ -118,12 +118,12 @@
     d->config[0x1a] = 0x00;  // subordinate_bus
     d->config[0x1c] = 0x00;
     d->config[0x1d] = 0x00;
-    
+
     d->config[0x20] = 0x00; // memory_base
     d->config[0x21] = 0x00;
     d->config[0x22] = 0x01; // memory_limit
     d->config[0x23] = 0x00;
-    
+
     d->config[0x24] = 0x00; // prefetchable_memory_base
     d->config[0x25] = 0x00;
     d->config[0x26] = 0x00; // prefetchable_memory_limit
@@ -145,12 +145,12 @@
     d->config[0x1a] = 0x1;  // subordinate_bus
     d->config[0x1c] = 0x10; // io_base
     d->config[0x1d] = 0x20; // io_limit
-    
+
     d->config[0x20] = 0x80; // memory_base
     d->config[0x21] = 0x80;
     d->config[0x22] = 0x90; // memory_limit
     d->config[0x23] = 0x80;
-    
+
     d->config[0x24] = 0x00; // prefetchable_memory_base
     d->config[0x25] = 0x84;
     d->config[0x26] = 0x00; // prefetchable_memory_limit
diff --git a/hw/gt64xxx.c b/hw/gt64xxx.c
index ccb6a7c..fbebbbe 100644
--- a/hw/gt64xxx.c
+++ b/hw/gt64xxx.c
@@ -2,7 +2,7 @@
  * QEMU GT64120 PCI host
  *
  * Copyright (c) 2006,2007 Aurelien Jarno
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -23,9 +23,18 @@
  */
 
 #include "vl.h"
+
 typedef target_phys_addr_t pci_addr_t;
 #include "pci_host.h"
 
+//#define DEBUG
+
+#ifdef DEBUG
+#define dprintf(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+
 #define GT_REGS			(0x1000 >> 2)
 
 /* CPU Configuration */
@@ -45,8 +54,6 @@
 #define GT_PCI0IOHD    		(0x050 >> 2)
 #define GT_PCI0M0LD    		(0x058 >> 2)
 #define GT_PCI0M0HD    		(0x060 >> 2)
-#define GT_ISD    		(0x068 >> 2)
-
 #define GT_PCI0M1LD    		(0x080 >> 2)
 #define GT_PCI0M1HD    		(0x088 >> 2)
 #define GT_PCI1IOLD    		(0x090 >> 2)
@@ -55,8 +62,7 @@
 #define GT_PCI1M0HD    		(0x0a8 >> 2)
 #define GT_PCI1M1LD    		(0x0b0 >> 2)
 #define GT_PCI1M1HD    		(0x0b8 >> 2)
-#define GT_PCI1M1LD    		(0x0b0 >> 2)
-#define GT_PCI1M1HD    		(0x0b8 >> 2)
+#define GT_ISD    		(0x068 >> 2)
 
 #define GT_SCS10AR    		(0x0d0 >> 2)
 #define GT_SCS32AR    		(0x0d8 >> 2)
@@ -219,21 +225,78 @@
 
 typedef PCIHostState GT64120PCIState;
 
+#define PCI_MAPPING_ENTRY(regname)            \
+    target_phys_addr_t regname ##_start;      \
+    target_phys_addr_t regname ##_length;     \
+    int regname ##_handle
+
 typedef struct GT64120State {
     GT64120PCIState *pci;
     uint32_t regs[GT_REGS];
+    PCI_MAPPING_ENTRY(PCI0IO);
+    PCI_MAPPING_ENTRY(ISD);
 } GT64120State;
 
+/* Adjust range to avoid touching space which isn't mappable via PCI */
+/* XXX: Hardcoded values for Malta: 0x1e000000 - 0x1f100000
+                                    0x1fc00000 - 0x1fd00000  */
+static void check_reserved_space (target_phys_addr_t *start,
+                                  target_phys_addr_t *length)
+{
+    target_phys_addr_t begin = *start;
+    target_phys_addr_t end = *start + *length;
+
+    if (end >= 0x1e000000LL && end < 0x1f100000LL)
+        end = 0x1e000000LL;
+    if (begin >= 0x1e000000LL && begin < 0x1f100000LL)
+        begin = 0x1f100000LL;
+    if (end >= 0x1fc00000LL && end < 0x1fd00000LL)
+        end = 0x1fc00000LL;
+    if (begin >= 0x1fc00000LL && begin < 0x1fd00000LL)
+        begin = 0x1fd00000LL;
+    /* XXX: This is broken when a reserved range splits the requested range */
+    if (end >= 0x1f100000LL && begin < 0x1e000000LL)
+        end = 0x1e000000LL;
+    if (end >= 0x1fd00000LL && begin < 0x1fc00000LL)
+        end = 0x1fc00000LL;
+
+    *start = begin;
+    *length = end - begin;
+}
+
+static void gt64120_isd_mapping(GT64120State *s)
+{
+    target_phys_addr_t start = s->regs[GT_ISD] << 21;
+    target_phys_addr_t length = 0x1000;
+
+    if (s->ISD_length)
+        cpu_register_physical_memory(s->ISD_start, s->ISD_length,
+                                     IO_MEM_UNASSIGNED);
+    check_reserved_space(&start, &length);
+    length = 0x1000;
+    /* Map new address */
+    dprintf("ISD: %x@%x -> %x@%x, %x\n", s->ISD_length, s->ISD_start,
+            length, start, s->ISD_handle);
+    s->ISD_start = start;
+    s->ISD_length = length;
+    cpu_register_physical_memory(s->ISD_start, s->ISD_length, s->ISD_handle);
+}
+
 static void gt64120_pci_mapping(GT64120State *s)
 {
-    target_phys_addr_t start, length;		   
-
     /* Update IO mapping */
     if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD])
     {
-      start = s->regs[GT_PCI0IOLD] << 21;
-      length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
-      isa_mmio_init(start, length);
+      /* Unmap old IO address */
+      if (s->PCI0IO_length)
+      {
+        cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED);
+      }
+      /* Map new IO address */
+      s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
+      s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
+      isa_mem_base = s->PCI0IO_start;
+      isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length);
     }
 }
 
@@ -267,37 +330,39 @@
     case GT_PCI0M0LD:
         s->regs[GT_PCI0M0LD]    = val & 0x00007fff;
         s->regs[GT_PCI0M0REMAP] = val & 0x000007ff;
-        gt64120_pci_mapping(s);
         break;
     case GT_PCI0M1LD:
         s->regs[GT_PCI0M1LD]    = val & 0x00007fff;
         s->regs[GT_PCI0M1REMAP] = val & 0x000007ff;
-        gt64120_pci_mapping(s);
         break;
     case GT_PCI1IOLD:
         s->regs[GT_PCI1IOLD]    = val & 0x00007fff;
         s->regs[GT_PCI1IOREMAP] = val & 0x000007ff;
-        gt64120_pci_mapping(s);
         break;
     case GT_PCI1M0LD:
         s->regs[GT_PCI1M0LD]    = val & 0x00007fff;
         s->regs[GT_PCI1M0REMAP] = val & 0x000007ff;
-        gt64120_pci_mapping(s);
         break;
     case GT_PCI1M1LD:
         s->regs[GT_PCI1M1LD]    = val & 0x00007fff;
         s->regs[GT_PCI1M1REMAP] = val & 0x000007ff;
-        gt64120_pci_mapping(s);
         break;
     case GT_PCI0IOHD:
+        s->regs[saddr] = val & 0x0000007f;
+        gt64120_pci_mapping(s);
+        break;
     case GT_PCI0M0HD:
     case GT_PCI0M1HD:
     case GT_PCI1IOHD:
     case GT_PCI1M0HD:
     case GT_PCI1M1HD:
         s->regs[saddr] = val & 0x0000007f;
-        gt64120_pci_mapping(s);
         break;
+    case GT_ISD:
+        s->regs[saddr] = val & 0x00007fff;
+        gt64120_isd_mapping(s);
+        break;
+
     case GT_PCI0IOREMAP:
     case GT_PCI0M0REMAP:
     case GT_PCI0M1REMAP:
@@ -305,7 +370,6 @@
     case GT_PCI1M0REMAP:
     case GT_PCI1M1REMAP:
         s->regs[saddr] = val & 0x000007ff;
-        gt64120_pci_mapping(s);
         break;
 
     /* CPU Error Report */
@@ -323,6 +387,45 @@
 	/* Read-only registers, do nothing */
         break;
 
+    /* SDRAM and Device Address Decode */
+    case GT_SCS0LD:
+    case GT_SCS0HD:
+    case GT_SCS1LD:
+    case GT_SCS1HD:
+    case GT_SCS2LD:
+    case GT_SCS2HD:
+    case GT_SCS3LD:
+    case GT_SCS3HD:
+    case GT_CS0LD:
+    case GT_CS0HD:
+    case GT_CS1LD:
+    case GT_CS1HD:
+    case GT_CS2LD:
+    case GT_CS2HD:
+    case GT_CS3LD:
+    case GT_CS3HD:
+    case GT_BOOTLD:
+    case GT_BOOTHD:
+    case GT_ADERR:
+    /* SDRAM Configuration */
+    case GT_SDRAM_CFG:
+    case GT_SDRAM_OPMODE:
+    case GT_SDRAM_BM:
+    case GT_SDRAM_ADDRDECODE:
+        /* Accept and ignore SDRAM interleave configuration */
+        s->regs[saddr] = val;
+        break;
+
+    /* Device Parameters */
+    case GT_DEV_B0:
+    case GT_DEV_B1:
+    case GT_DEV_B2:
+    case GT_DEV_B3:
+    case GT_DEV_BOOT:
+        /* Not implemented */
+        dprintf ("Unimplemented device register offset 0x%x\n", saddr << 2);
+        break;
+
     /* ECC */
     case GT_ECC_ERRDATALO:
     case GT_ECC_ERRDATAHI:
@@ -332,16 +435,131 @@
         /* Read-only registers, do nothing */
         break;
 
+    /* DMA Record */
+    case GT_DMA0_CNT:
+    case GT_DMA1_CNT:
+    case GT_DMA2_CNT:
+    case GT_DMA3_CNT:
+    case GT_DMA0_SA:
+    case GT_DMA1_SA:
+    case GT_DMA2_SA:
+    case GT_DMA3_SA:
+    case GT_DMA0_DA:
+    case GT_DMA1_DA:
+    case GT_DMA2_DA:
+    case GT_DMA3_DA:
+    case GT_DMA0_NEXT:
+    case GT_DMA1_NEXT:
+    case GT_DMA2_NEXT:
+    case GT_DMA3_NEXT:
+    case GT_DMA0_CUR:
+    case GT_DMA1_CUR:
+    case GT_DMA2_CUR:
+    case GT_DMA3_CUR:
+        /* Not implemented */
+        dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* DMA Channel Control */
+    case GT_DMA0_CTRL:
+    case GT_DMA1_CTRL:
+    case GT_DMA2_CTRL:
+    case GT_DMA3_CTRL:
+        /* Not implemented */
+        dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* DMA Arbiter */
+    case GT_DMA_ARB:
+        /* Not implemented */
+        dprintf ("Unimplemented DMA register offset 0x%x\n", saddr << 2);
+        break;
+
+    /* Timer/Counter */
+    case GT_TC0:
+    case GT_TC1:
+    case GT_TC2:
+    case GT_TC3:
+    case GT_TC_CONTROL:
+        /* Not implemented */
+        dprintf ("Unimplemented timer register offset 0x%x\n", saddr << 2);
+        break;
+
     /* PCI Internal */
     case GT_PCI0_CMD:
     case GT_PCI1_CMD:
         s->regs[saddr] = val & 0x0401fc0f;
         break;
+    case GT_PCI0_TOR:
+    case GT_PCI0_BS_SCS10:
+    case GT_PCI0_BS_SCS32:
+    case GT_PCI0_BS_CS20:
+    case GT_PCI0_BS_CS3BT:
+    case GT_PCI1_IACK:
+    case GT_PCI0_IACK:
+    case GT_PCI0_BARE:
+    case GT_PCI0_PREFMBR:
+    case GT_PCI0_SCS10_BAR:
+    case GT_PCI0_SCS32_BAR:
+    case GT_PCI0_CS20_BAR:
+    case GT_PCI0_CS3BT_BAR:
+    case GT_PCI0_SSCS10_BAR:
+    case GT_PCI0_SSCS32_BAR:
+    case GT_PCI0_SCS3BT_BAR:
+    case GT_PCI1_TOR:
+    case GT_PCI1_BS_SCS10:
+    case GT_PCI1_BS_SCS32:
+    case GT_PCI1_BS_CS20:
+    case GT_PCI1_BS_CS3BT:
+    case GT_PCI1_BARE:
+    case GT_PCI1_PREFMBR:
+    case GT_PCI1_SCS10_BAR:
+    case GT_PCI1_SCS32_BAR:
+    case GT_PCI1_CS20_BAR:
+    case GT_PCI1_CS3BT_BAR:
+    case GT_PCI1_SSCS10_BAR:
+    case GT_PCI1_SSCS32_BAR:
+    case GT_PCI1_SCS3BT_BAR:
+    case GT_PCI1_CFGADDR:
+    case GT_PCI1_CFGDATA:
+        /* not implemented */
+        break;
     case GT_PCI0_CFGADDR:
         s->pci->config_reg = val & 0x80fffffc;
         break;
     case GT_PCI0_CFGDATA:
-        pci_host_data_writel(s->pci, 0, val);
+        if (s->pci->config_reg & (1u << 31))
+            pci_host_data_writel(s->pci, 0, val);
+        break;
+
+    /* Interrupts */
+    case GT_INTRCAUSE:
+        /* not really implemented */
+        s->regs[saddr] = ~(~(s->regs[saddr]) | ~(val & 0xfffffffe));
+        s->regs[saddr] |= !!(s->regs[saddr] & 0xfffffffe);
+        dprintf("INTRCAUSE %x\n", val);
+        break;
+    case GT_INTRMASK:
+        s->regs[saddr] = val & 0x3c3ffffe;
+        dprintf("INTRMASK %x\n", val);
+        break;
+    case GT_PCI0_ICMASK:
+        s->regs[saddr] = val & 0x03fffffe;
+        dprintf("ICMASK %x\n", val);
+        break;
+    case GT_PCI0_SERR0MASK:
+        s->regs[saddr] = val & 0x0000003f;
+        dprintf("SERR0MASK %x\n", val);
+        break;
+
+    /* Reserved when only PCI_0 is configured. */
+    case GT_HINTRCAUSE:
+    case GT_CPU_INTSEL:
+    case GT_PCI0_INTSEL:
+    case GT_HINTRMASK:
+    case GT_PCI0_HICMASK:
+    case GT_PCI1_SERR1MASK:
+        /* not implemented */
         break;
 
     /* SDRAM Parameters */
@@ -355,9 +573,7 @@
         break;
 
     default:
-#if 0
-        printf ("gt64120_writel: Bad register offset 0x%x\n", (int)addr);
-#endif
+        dprintf ("Bad register offset 0x%x\n", (int)addr);
         break;
     }
 }
@@ -388,7 +604,7 @@
     case GT_CPUERR_DATAHI:
     case GT_CPUERR_PARITY:
         /* Emulated memory has no error, always return the initial
-           values */ 
+           values */
         val = s->regs[saddr];
         break;
 
@@ -398,7 +614,7 @@
         /* Reading those register should empty all FIFO on the PCI
            bus, which are not emulated. The return value should be
            a random value that should be ignored. */
-        val = 0xc000ffee; 
+        val = 0xc000ffee;
         break;
 
     /* ECC */
@@ -408,11 +624,23 @@
     case GT_ECC_CALC:
     case GT_ECC_ERRADDR:
         /* Emulated memory has no error, always return the initial
-           values */ 
+           values */
         val = s->regs[saddr];
         break;
 
     case GT_CPU:
+    case GT_SCS10LD:
+    case GT_SCS10HD:
+    case GT_SCS32LD:
+    case GT_SCS32HD:
+    case GT_CS20LD:
+    case GT_CS20HD:
+    case GT_CS3BOOTLD:
+    case GT_CS3BOOTHD:
+    case GT_SCS10AR:
+    case GT_SCS32AR:
+    case GT_CS20R:
+    case GT_CS3BOOTR:
     case GT_PCI0IOLD:
     case GT_PCI0M0LD:
     case GT_PCI0M1LD:
@@ -425,21 +653,51 @@
     case GT_PCI1IOHD:
     case GT_PCI1M0HD:
     case GT_PCI1M1HD:
-    case GT_PCI0_CMD:
-    case GT_PCI1_CMD:
     case GT_PCI0IOREMAP:
     case GT_PCI0M0REMAP:
     case GT_PCI0M1REMAP:
     case GT_PCI1IOREMAP:
     case GT_PCI1M0REMAP:
     case GT_PCI1M1REMAP:
+    case GT_ISD:
         val = s->regs[saddr];
         break;
     case GT_PCI0_IACK:
-        /* Read the IRQ number */ 
+        /* Read the IRQ number */
         val = pic_read_irq(isa_pic);
         break;
 
+    /* SDRAM and Device Address Decode */
+    case GT_SCS0LD:
+    case GT_SCS0HD:
+    case GT_SCS1LD:
+    case GT_SCS1HD:
+    case GT_SCS2LD:
+    case GT_SCS2HD:
+    case GT_SCS3LD:
+    case GT_SCS3HD:
+    case GT_CS0LD:
+    case GT_CS0HD:
+    case GT_CS1LD:
+    case GT_CS1HD:
+    case GT_CS2LD:
+    case GT_CS2HD:
+    case GT_CS3LD:
+    case GT_CS3HD:
+    case GT_BOOTLD:
+    case GT_BOOTHD:
+    case GT_ADERR:
+        val = s->regs[saddr];
+        break;
+
+    /* SDRAM Configuration */
+    case GT_SDRAM_CFG:
+    case GT_SDRAM_OPMODE:
+    case GT_SDRAM_BM:
+    case GT_SDRAM_ADDRDECODE:
+        val = s->regs[saddr];
+        break;
+
     /* SDRAM Parameters */
     case GT_SDRAM_B0:
     case GT_SDRAM_B1:
@@ -450,27 +708,146 @@
         val = s->regs[saddr];
         break;
 
+    /* Device Parameters */
+    case GT_DEV_B0:
+    case GT_DEV_B1:
+    case GT_DEV_B2:
+    case GT_DEV_B3:
+    case GT_DEV_BOOT:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Record */
+    case GT_DMA0_CNT:
+    case GT_DMA1_CNT:
+    case GT_DMA2_CNT:
+    case GT_DMA3_CNT:
+    case GT_DMA0_SA:
+    case GT_DMA1_SA:
+    case GT_DMA2_SA:
+    case GT_DMA3_SA:
+    case GT_DMA0_DA:
+    case GT_DMA1_DA:
+    case GT_DMA2_DA:
+    case GT_DMA3_DA:
+    case GT_DMA0_NEXT:
+    case GT_DMA1_NEXT:
+    case GT_DMA2_NEXT:
+    case GT_DMA3_NEXT:
+    case GT_DMA0_CUR:
+    case GT_DMA1_CUR:
+    case GT_DMA2_CUR:
+    case GT_DMA3_CUR:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Channel Control */
+    case GT_DMA0_CTRL:
+    case GT_DMA1_CTRL:
+    case GT_DMA2_CTRL:
+    case GT_DMA3_CTRL:
+        val = s->regs[saddr];
+        break;
+
+    /* DMA Arbiter */
+    case GT_DMA_ARB:
+        val = s->regs[saddr];
+        break;
+
+    /* Timer/Counter */
+    case GT_TC0:
+    case GT_TC1:
+    case GT_TC2:
+    case GT_TC3:
+    case GT_TC_CONTROL:
+        val = s->regs[saddr];
+        break;
+
     /* PCI Internal */
     case GT_PCI0_CFGADDR:
         val = s->pci->config_reg;
         break;
     case GT_PCI0_CFGDATA:
-        val = pci_host_data_readl(s->pci, 0);
+        if (!(s->pci->config_reg & (1u << 31)))
+            val = 0xffffffff;
+        else
+            val = pci_host_data_readl(s->pci, 0);
+        break;
+
+    case GT_PCI0_CMD:
+    case GT_PCI0_TOR:
+    case GT_PCI0_BS_SCS10:
+    case GT_PCI0_BS_SCS32:
+    case GT_PCI0_BS_CS20:
+    case GT_PCI0_BS_CS3BT:
+    case GT_PCI1_IACK:
+    case GT_PCI0_BARE:
+    case GT_PCI0_PREFMBR:
+    case GT_PCI0_SCS10_BAR:
+    case GT_PCI0_SCS32_BAR:
+    case GT_PCI0_CS20_BAR:
+    case GT_PCI0_CS3BT_BAR:
+    case GT_PCI0_SSCS10_BAR:
+    case GT_PCI0_SSCS32_BAR:
+    case GT_PCI0_SCS3BT_BAR:
+    case GT_PCI1_CMD:
+    case GT_PCI1_TOR:
+    case GT_PCI1_BS_SCS10:
+    case GT_PCI1_BS_SCS32:
+    case GT_PCI1_BS_CS20:
+    case GT_PCI1_BS_CS3BT:
+    case GT_PCI1_BARE:
+    case GT_PCI1_PREFMBR:
+    case GT_PCI1_SCS10_BAR:
+    case GT_PCI1_SCS32_BAR:
+    case GT_PCI1_CS20_BAR:
+    case GT_PCI1_CS3BT_BAR:
+    case GT_PCI1_SSCS10_BAR:
+    case GT_PCI1_SSCS32_BAR:
+    case GT_PCI1_SCS3BT_BAR:
+    case GT_PCI1_CFGADDR:
+    case GT_PCI1_CFGDATA:
+        val = s->regs[saddr];
+        break;
+
+    /* Interrupts */
+    case GT_INTRCAUSE:
+        val = s->regs[saddr];
+        dprintf("INTRCAUSE %x\n", val);
+        break;
+    case GT_INTRMASK:
+        val = s->regs[saddr];
+        dprintf("INTRMASK %x\n", val);
+        break;
+    case GT_PCI0_ICMASK:
+        val = s->regs[saddr];
+        dprintf("ICMASK %x\n", val);
+        break;
+    case GT_PCI0_SERR0MASK:
+        val = s->regs[saddr];
+        dprintf("SERR0MASK %x\n", val);
+        break;
+
+    /* Reserved when only PCI_0 is configured. */
+    case GT_HINTRCAUSE:
+    case GT_CPU_INTSEL:
+    case GT_PCI0_INTSEL:
+    case GT_HINTRMASK:
+    case GT_PCI0_HICMASK:
+    case GT_PCI1_SERR1MASK:
+        val = s->regs[saddr];
         break;
 
     default:
         val = s->regs[saddr];
-#if 0
-        printf ("gt64120_readl: Bad register offset 0x%x\n", (int)addr);
-#endif
+        dprintf ("Bad register offset 0x%x\n", (int)addr);
         break;
     }
 
 #ifdef TARGET_WORDS_BIGENDIAN
-    return bswap32(val);
-#else
-    return val;
+    val = bswap32(val);
 #endif
+    return val;
 }
 
 static CPUWriteMemoryFunc *gt64120_write[] = {
@@ -497,10 +874,10 @@
         return 3;
       /* AMD 79C973 Ethernet */
       case 11:
-        return 0;
+        return 1;
       /* Crystal 4281 Sound */
       case 12:
-        return 0;
+        return 2;
       /* PCI slot 1 to 4 */
       case 18 ... 21:
         return ((slot - 18) + irq_num) & 0x03;
@@ -513,7 +890,7 @@
 extern PCIDevice *piix4_dev;
 static int pci_irq_levels[4];
 
-static void pci_gt64120_set_irq(void *pic, int irq_num, int level)
+static void pci_gt64120_set_irq(qemu_irq *pic, int irq_num, int level)
 {
     int i, pic_irq, pic_level;
 
@@ -530,7 +907,7 @@
             if (pic_irq == piix4_dev->config[0x60 + i])
                 pic_level |= pci_irq_levels[i];
         }
-        pic_set_irq(pic_irq, pic_level);
+        qemu_set_irq(pic[pic_irq], pic_level);
     }
 }
 
@@ -539,19 +916,31 @@
 {
     GT64120State *s = opaque;
 
+    /* FIXME: Malta specific hw assumptions ahead */
+
     /* CPU Configuration */
 #ifdef TARGET_WORDS_BIGENDIAN
     s->regs[GT_CPU]           = 0x00000000;
 #else
-    s->regs[GT_CPU]           = 0x00000800;
+    s->regs[GT_CPU]           = 0x00001000;
 #endif
-    s->regs[GT_MULTI]         = 0x00000000;
+    s->regs[GT_MULTI]         = 0x00000003;
 
-    /* CPU Address decode FIXME: not complete*/
+    /* CPU Address decode */
+    s->regs[GT_SCS10LD]       = 0x00000000;
+    s->regs[GT_SCS10HD]       = 0x00000007;
+    s->regs[GT_SCS32LD]       = 0x00000008;
+    s->regs[GT_SCS32HD]       = 0x0000000f;
+    s->regs[GT_CS20LD]        = 0x000000e0;
+    s->regs[GT_CS20HD]        = 0x00000070;
+    s->regs[GT_CS3BOOTLD]     = 0x000000f8;
+    s->regs[GT_CS3BOOTHD]     = 0x0000007f;
+
     s->regs[GT_PCI0IOLD]      = 0x00000080;
     s->regs[GT_PCI0IOHD]      = 0x0000000f;
     s->regs[GT_PCI0M0LD]      = 0x00000090;
     s->regs[GT_PCI0M0HD]      = 0x0000001f;
+    s->regs[GT_ISD]           = 0x000000a0;
     s->regs[GT_PCI0M1LD]      = 0x00000790;
     s->regs[GT_PCI0M1HD]      = 0x0000001f;
     s->regs[GT_PCI1IOLD]      = 0x00000100;
@@ -560,6 +949,12 @@
     s->regs[GT_PCI1M0HD]      = 0x0000001f;
     s->regs[GT_PCI1M1LD]      = 0x00000120;
     s->regs[GT_PCI1M1HD]      = 0x0000002f;
+
+    s->regs[GT_SCS10AR]       = 0x00000000;
+    s->regs[GT_SCS32AR]       = 0x00000008;
+    s->regs[GT_CS20R]         = 0x000000e0;
+    s->regs[GT_CS3BOOTR]      = 0x000000f8;
+
     s->regs[GT_PCI0IOREMAP]   = 0x00000080;
     s->regs[GT_PCI0M0REMAP]   = 0x00000090;
     s->regs[GT_PCI0M1REMAP]   = 0x00000790;
@@ -574,6 +969,43 @@
     s->regs[GT_CPUERR_DATAHI] = 0xffffffff;
     s->regs[GT_CPUERR_PARITY] = 0x000000ff;
 
+    /* CPU Sync Barrier */
+    s->regs[GT_PCI0SYNC]      = 0x00000000;
+    s->regs[GT_PCI1SYNC]      = 0x00000000;
+
+    /* SDRAM and Device Address Decode */
+    s->regs[GT_SCS0LD]        = 0x00000000;
+    s->regs[GT_SCS0HD]        = 0x00000007;
+    s->regs[GT_SCS1LD]        = 0x00000008;
+    s->regs[GT_SCS1HD]        = 0x0000000f;
+    s->regs[GT_SCS2LD]        = 0x00000010;
+    s->regs[GT_SCS2HD]        = 0x00000017;
+    s->regs[GT_SCS3LD]        = 0x00000018;
+    s->regs[GT_SCS3HD]        = 0x0000001f;
+    s->regs[GT_CS0LD]         = 0x000000c0;
+    s->regs[GT_CS0HD]         = 0x000000c7;
+    s->regs[GT_CS1LD]         = 0x000000c8;
+    s->regs[GT_CS1HD]         = 0x000000cf;
+    s->regs[GT_CS2LD]         = 0x000000d0;
+    s->regs[GT_CS2HD]         = 0x000000df;
+    s->regs[GT_CS3LD]         = 0x000000f0;
+    s->regs[GT_CS3HD]         = 0x000000fb;
+    s->regs[GT_BOOTLD]        = 0x000000fc;
+    s->regs[GT_BOOTHD]        = 0x000000ff;
+    s->regs[GT_ADERR]         = 0xffffffff;
+
+    /* SDRAM Configuration */
+    s->regs[GT_SDRAM_CFG]     = 0x00000200;
+    s->regs[GT_SDRAM_OPMODE]  = 0x00000000;
+    s->regs[GT_SDRAM_BM]      = 0x00000007;
+    s->regs[GT_SDRAM_ADDRDECODE] = 0x00000002;
+
+    /* SDRAM Parameters */
+    s->regs[GT_SDRAM_B0]      = 0x00000005;
+    s->regs[GT_SDRAM_B1]      = 0x00000005;
+    s->regs[GT_SDRAM_B2]      = 0x00000005;
+    s->regs[GT_SDRAM_B3]      = 0x00000005;
+
     /* ECC */
     s->regs[GT_ECC_ERRDATALO] = 0x00000000;
     s->regs[GT_ECC_ERRDATAHI] = 0x00000000;
@@ -581,68 +1013,155 @@
     s->regs[GT_ECC_CALC]      = 0x00000000;
     s->regs[GT_ECC_ERRADDR]   = 0x00000000;
 
-    /* SDRAM Parameters */
-    s->regs[GT_SDRAM_B0]      = 0x00000005;    
-    s->regs[GT_SDRAM_B1]      = 0x00000005;    
-    s->regs[GT_SDRAM_B2]      = 0x00000005;    
-    s->regs[GT_SDRAM_B3]      = 0x00000005;    
+    /* Device Parameters */
+    s->regs[GT_DEV_B0]        = 0x386fffff;
+    s->regs[GT_DEV_B1]        = 0x386fffff;
+    s->regs[GT_DEV_B2]        = 0x386fffff;
+    s->regs[GT_DEV_B3]        = 0x386fffff;
+    s->regs[GT_DEV_BOOT]      = 0x146fffff;
 
-    /* PCI Internal FIXME: not complete*/
+    /* DMA registers are all zeroed at reset */
+
+    /* Timer/Counter */
+    s->regs[GT_TC0]           = 0xffffffff;
+    s->regs[GT_TC1]           = 0x00ffffff;
+    s->regs[GT_TC2]           = 0x00ffffff;
+    s->regs[GT_TC3]           = 0x00ffffff;
+    s->regs[GT_TC_CONTROL]    = 0x00000000;
+
+    /* PCI Internal */
 #ifdef TARGET_WORDS_BIGENDIAN
     s->regs[GT_PCI0_CMD]      = 0x00000000;
-    s->regs[GT_PCI1_CMD]      = 0x00000000;
 #else
     s->regs[GT_PCI0_CMD]      = 0x00010001;
+#endif
+    s->regs[GT_PCI0_TOR]      = 0x0000070f;
+    s->regs[GT_PCI0_BS_SCS10] = 0x00fff000;
+    s->regs[GT_PCI0_BS_SCS32] = 0x00fff000;
+    s->regs[GT_PCI0_BS_CS20]  = 0x01fff000;
+    s->regs[GT_PCI0_BS_CS3BT] = 0x00fff000;
+    s->regs[GT_PCI1_IACK]     = 0x00000000;
+    s->regs[GT_PCI0_IACK]     = 0x00000000;
+    s->regs[GT_PCI0_BARE]     = 0x0000000f;
+    s->regs[GT_PCI0_PREFMBR]  = 0x00000040;
+    s->regs[GT_PCI0_SCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI0_SCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI0_CS20_BAR] = 0x1c000000;
+    s->regs[GT_PCI0_CS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI0_SSCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI0_SSCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI0_SCS3BT_BAR] = 0x1f000000;
+#ifdef TARGET_WORDS_BIGENDIAN
+    s->regs[GT_PCI1_CMD]      = 0x00000000;
+#else
     s->regs[GT_PCI1_CMD]      = 0x00010001;
 #endif
-    s->regs[GT_PCI0_IACK]     = 0x00000000;
-    s->regs[GT_PCI1_IACK]     = 0x00000000;
+    s->regs[GT_PCI1_TOR]      = 0x0000070f;
+    s->regs[GT_PCI1_BS_SCS10] = 0x00fff000;
+    s->regs[GT_PCI1_BS_SCS32] = 0x00fff000;
+    s->regs[GT_PCI1_BS_CS20]  = 0x01fff000;
+    s->regs[GT_PCI1_BS_CS3BT] = 0x00fff000;
+    s->regs[GT_PCI1_BARE]     = 0x0000000f;
+    s->regs[GT_PCI1_PREFMBR]  = 0x00000040;
+    s->regs[GT_PCI1_SCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI1_SCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI1_CS20_BAR] = 0x1c000000;
+    s->regs[GT_PCI1_CS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI1_SSCS10_BAR] = 0x00000000;
+    s->regs[GT_PCI1_SSCS32_BAR] = 0x01000000;
+    s->regs[GT_PCI1_SCS3BT_BAR] = 0x1f000000;
+    s->regs[GT_PCI1_CFGADDR]  = 0x00000000;
+    s->regs[GT_PCI1_CFGDATA]  = 0x00000000;
+    s->regs[GT_PCI0_CFGADDR]  = 0x00000000;
+    s->regs[GT_PCI0_CFGDATA]  = 0x00000000;
 
+    /* Interrupt registers are all zeroed at reset */
+
+    gt64120_isd_mapping(s);
     gt64120_pci_mapping(s);
 }
 
-PCIBus *pci_gt64120_init(void *pic)
+static uint32_t gt64120_read_config(PCIDevice *d, uint32_t address, int len)
+{
+    uint32_t val = pci_default_read_config(d, address, len);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    return val;
+}
+
+static void gt64120_write_config(PCIDevice *d, uint32_t address, uint32_t val,
+                                 int len)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    pci_default_write_config(d, address, val, len);
+}
+
+static void gt64120_save(QEMUFile* f, void *opaque)
+{
+    PCIDevice *d = opaque;
+    pci_device_save(d, f);
+}
+
+static int gt64120_load(QEMUFile* f, void *opaque, int version_id)
+{
+    PCIDevice *d = opaque;
+    int ret;
+
+    if (version_id != 1)
+        return -EINVAL;
+    ret = pci_device_load(d, f);
+    if (ret < 0)
+        return ret;
+    return 0;
+}
+
+PCIBus *pci_gt64120_init(qemu_irq *pic)
 {
     GT64120State *s;
     PCIDevice *d;
-    int gt64120;
 
     s = qemu_mallocz(sizeof(GT64120State));
     s->pci = qemu_mallocz(sizeof(GT64120PCIState));
-    gt64120_reset(s);
 
     s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq,
                                    pic, 144, 4);
-
-    gt64120 = cpu_register_io_memory(0, gt64120_read,
-                                     gt64120_write, s);
-    cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120);
-
+    s->ISD_handle = cpu_register_io_memory(0, gt64120_read, gt64120_write, s);
     d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
-                            0, NULL, NULL);
+                            0, gt64120_read_config, gt64120_write_config);
 
-    d->config[0x00] = 0xab; // vendor_id
+    /* FIXME: Malta specific hw assumptions ahead */
+
+    d->config[0x00] = 0xab; /* vendor_id */
     d->config[0x01] = 0x11;
-    d->config[0x02] = 0x46; // device_id
-    d->config[0x03] = 0x20;
-    d->config[0x04] = 0x06;
+    d->config[0x02] = 0x20; /* device_id */
+    d->config[0x03] = 0x46;
+
+    d->config[0x04] = 0x00;
     d->config[0x05] = 0x00;
     d->config[0x06] = 0x80;
-    d->config[0x07] = 0xa2;
+    d->config[0x07] = 0x02;
+
     d->config[0x08] = 0x10;
     d->config[0x09] = 0x00;
-    d->config[0x0A] = 0x80;
-    d->config[0x0B] = 0x05;
-    d->config[0x0C] = 0x08;
-    d->config[0x0D] = 0x40;
-    d->config[0x0E] = 0x00;
-    d->config[0x0F] = 0x00;
-    d->config[0x17] = 0x08;
+    d->config[0x0A] = 0x00;
+    d->config[0x0B] = 0x06;
+
+    d->config[0x10] = 0x08;
+    d->config[0x14] = 0x08;
+    d->config[0x17] = 0x01;
     d->config[0x1B] = 0x1c;
     d->config[0x1F] = 0x1f;
     d->config[0x23] = 0x14;
+    d->config[0x24] = 0x01;
     d->config[0x27] = 0x14;
     d->config[0x3D] = 0x01;
 
+    gt64120_reset(s);
+
+    register_savevm("GT64120 PCI Bus", 0, 1, gt64120_save, gt64120_load, d);
+
     return s->pci->bus;
 }
diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c
index 4980cef..96eb656 100644
--- a/hw/heathrow_pic.c
+++ b/hw/heathrow_pic.c
@@ -1,8 +1,8 @@
 /*
  * Heathrow PIC support (standard PowerMac PIC)
- * 
+ *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -32,9 +32,9 @@
     uint32_t level_triggered;
 } HeathrowPIC;
 
-struct HeathrowPICS {
+typedef struct HeathrowPICS {
     HeathrowPIC pics[2];
-};
+} HeathrowPICS;
 
 static inline int check_irq(HeathrowPIC *pic)
 {
@@ -88,7 +88,7 @@
     HeathrowPIC *pic;
     unsigned int n;
     uint32_t value;
-    
+
     n = ((addr & 0xfff) - 0x10) >> 4;
     if (n >= 2) {
         value = 0;
@@ -130,7 +130,7 @@
 };
 
 
-void heathrow_pic_set_irq(void *opaque, int num, int level)
+static void heathrow_pic_set_irq(void *opaque, int num, int level)
 {
     HeathrowPICS *s = opaque;
     HeathrowPIC *pic;
@@ -156,13 +156,13 @@
     heathrow_pic_update(s);
 }
 
-HeathrowPICS *heathrow_pic_init(int *pmem_index)
+qemu_irq *heathrow_pic_init(int *pmem_index)
 {
     HeathrowPICS *s;
-    
+
     s = qemu_mallocz(sizeof(HeathrowPICS));
     s->pics[0].level_triggered = 0;
     s->pics[1].level_triggered = 0x1ff00000;
     *pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s);
-    return s;
+    return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
 }
diff --git a/hw/hypercall.c b/hw/hypercall.c
index d6f9c9a..7210f32 100644
--- a/hw/hypercall.c
+++ b/hw/hypercall.c
@@ -194,7 +194,7 @@
 static void hypercall_update_irq(HypercallState *s)
 {
     /* PCI irq */
-    pci_set_irq(s->pci_dev, 0, !(s->hcr & HCR_DI));
+    qemu_set_irq(s->pci_dev->irq[0], !(s->hcr & HCR_DI));
 }
 
 static void hc_save(QEMUFile* f,void* opaque)
diff --git a/hw/i2c.c b/hw/i2c.c
new file mode 100644
index 0000000..f0d117c
--- /dev/null
+++ b/hw/i2c.c
@@ -0,0 +1,148 @@
+/*
+ * QEMU I2C bus interface.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+#include "vl.h"
+
+struct i2c_bus
+{
+    i2c_slave *current_dev;
+    i2c_slave *dev;
+};
+
+/* Create a new I2C bus.  */
+i2c_bus *i2c_init_bus(void)
+{
+    i2c_bus *bus;
+
+    bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus));
+    return bus;
+}
+
+/* Create a new slave device.  */
+i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size)
+{
+    i2c_slave *dev;
+
+    if (size < sizeof(i2c_slave))
+        cpu_abort(cpu_single_env, "I2C struct too small");
+
+    dev = (i2c_slave *)qemu_mallocz(size);
+    dev->address = address;
+    dev->next = bus->dev;
+    bus->dev = dev;
+
+    return dev;
+}
+
+void i2c_set_slave_address(i2c_slave *dev, int address)
+{
+    dev->address = address;
+}
+
+/* Return nonzero if bus is busy.  */
+int i2c_bus_busy(i2c_bus *bus)
+{
+    return bus->current_dev != NULL;
+}
+
+/* Returns nonzero if the bus is already busy, or is the address is not
+   valid.  */
+/* TODO: Make this handle multiple masters.  */
+int i2c_start_transfer(i2c_bus *bus, int address, int recv)
+{
+    i2c_slave *dev;
+
+    for (dev = bus->dev; dev; dev = dev->next) {
+        if (dev->address == address)
+            break;
+    }
+
+    if (!dev)
+        return 1;
+
+    /* If the bus is already busy, assume this is a repeated
+       start condition.  */
+    bus->current_dev = dev;
+    dev->event(dev, recv ? I2C_START_RECV : I2C_START_SEND);
+    return 0;
+}
+
+void i2c_end_transfer(i2c_bus *bus)
+{
+    i2c_slave *dev = bus->current_dev;
+
+    if (!dev)
+        return;
+
+    dev->event(dev, I2C_FINISH);
+
+    bus->current_dev = NULL;
+}
+
+int i2c_send(i2c_bus *bus, uint8_t data)
+{
+    i2c_slave *dev = bus->current_dev;
+
+    if (!dev)
+        return -1;
+
+    return dev->send(dev, data);
+}
+
+int i2c_recv(i2c_bus *bus)
+{
+    i2c_slave *dev = bus->current_dev;
+
+    if (!dev)
+        return -1;
+
+    return dev->recv(dev);
+}
+
+void i2c_nack(i2c_bus *bus)
+{
+    i2c_slave *dev = bus->current_dev;
+
+    if (!dev)
+        return;
+
+    dev->event(dev, I2C_NACK);
+}
+
+void i2c_bus_save(QEMUFile *f, i2c_bus *bus)
+{
+    qemu_put_byte(f, bus->current_dev ? bus->current_dev->address : 0x00);
+}
+
+void i2c_bus_load(QEMUFile *f, i2c_bus *bus)
+{
+    i2c_slave *dev;
+    uint8_t address = qemu_get_byte(f);
+
+    if (address) {
+        for (dev = bus->dev; dev; dev = dev->next)
+            if (dev->address == address) {
+                bus->current_dev = dev;
+                return;
+            }
+
+        fprintf(stderr, "%s: I2C slave with address %02x disappeared\n",
+                __FUNCTION__, address);
+    }
+}
+
+void i2c_slave_save(QEMUFile *f, i2c_slave *dev)
+{
+    qemu_put_byte(f, dev->address);
+}
+
+void i2c_slave_load(QEMUFile *f, i2c_slave *dev)
+{
+    dev->address = qemu_get_byte(f);
+}
diff --git a/hw/i2c.h b/hw/i2c.h
new file mode 100644
index 0000000..9330ae8
--- /dev/null
+++ b/hw/i2c.h
@@ -0,0 +1,67 @@
+#ifndef QEMU_I2C_H
+#define QEMU_I2C_H
+
+/* The QEMU I2C implementation only supports simple transfers that complete
+   immediately.  It does not support slave devices that need to be able to
+   defer their response (eg. CPU slave interfaces where the data is supplied
+   by the device driver in response to an interrupt).  */
+
+enum i2c_event {
+    I2C_START_RECV,
+    I2C_START_SEND,
+    I2C_FINISH,
+    I2C_NACK /* Masker NACKed a receive byte.  */
+};
+
+typedef struct i2c_slave i2c_slave;
+
+/* Master to slave.  */
+typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data);
+/* Slave to master.  */
+typedef int (*i2c_recv_cb)(i2c_slave *s);
+/* Notify the slave of a bus state change.  */
+typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event);
+
+struct i2c_slave
+{
+    /* Callbacks to be set by the device.  */
+    i2c_event_cb event;
+    i2c_recv_cb recv;
+    i2c_send_cb send;
+
+    /* Remaining fields for internal use by the I2C code.  */
+    int address;
+    void *next;
+};
+
+typedef struct i2c_bus i2c_bus;
+
+i2c_bus *i2c_init_bus(void);
+i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size);
+void i2c_set_slave_address(i2c_slave *dev, int address);
+int i2c_bus_busy(i2c_bus *bus);
+int i2c_start_transfer(i2c_bus *bus, int address, int recv);
+void i2c_end_transfer(i2c_bus *bus);
+void i2c_nack(i2c_bus *bus);
+int i2c_send(i2c_bus *bus, uint8_t data);
+int i2c_recv(i2c_bus *bus);
+void i2c_bus_save(QEMUFile *f, i2c_bus *bus);
+void i2c_bus_load(QEMUFile *f, i2c_bus *bus);
+void i2c_slave_save(QEMUFile *f, i2c_slave *dev);
+void i2c_slave_load(QEMUFile *f, i2c_slave *dev);
+
+/* max7310.c */
+i2c_slave *max7310_init(i2c_bus *bus);
+void max7310_reset(i2c_slave *i2c);
+qemu_irq *max7310_gpio_in_get(i2c_slave *i2c);
+void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler);
+
+/* wm8750.c */
+i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio);
+void wm8750_reset(i2c_slave *i2c);
+void wm8750_data_req_set(i2c_slave *i2c,
+                void (*data_req)(void *, int, int), void *opaque);
+void wm8750_dac_dat(void *opaque, uint32_t sample);
+uint32_t wm8750_adc_dat(void *opaque);
+
+#endif
diff --git a/hw/i8254.c b/hw/i8254.c
index 29dadee..8480a9a 100644
--- a/hw/i8254.c
+++ b/hw/i8254.c
@@ -1,8 +1,8 @@
 /*
  * QEMU 8253/8254 interval timer emulation
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -47,7 +47,7 @@
     /* irq handling */
     int64_t next_transition_time;
     QEMUTimer *irq_timer;
-    int irq;
+    qemu_irq irq;
 } PITChannelState;
 
 struct PITState {
@@ -121,7 +121,7 @@
 }
 
 /* return -1 if no transition will occur.  */
-static int64_t pit_get_next_transition_time(PITChannelState *s, 
+static int64_t pit_get_next_transition_time(PITChannelState *s,
                                             int64_t current_time)
 {
     uint64_t d, next_time, base;
@@ -147,7 +147,7 @@
     case 3:
         base = (d / s->count) * s->count;
         period2 = ((s->count + 1) >> 1);
-        if ((d - base) < period2) 
+        if ((d - base) < period2)
             next_time = base + period2;
         else
             next_time = base + s->count;
@@ -309,7 +309,7 @@
     PITState *pit = opaque;
     int ret, count;
     PITChannelState *s;
-    
+
     addr &= 3;
     s = &pit->channels[addr];
     if (s->status_latched) {
@@ -369,7 +369,7 @@
         return;
     expire_time = pit_get_next_transition_time(s, current_time);
     irq_level = pit_get_out1(s, current_time);
-    pic_set_irq(s->irq, irq_level);
+    qemu_set_irq(s->irq, irq_level);
     if (time_drift_fix && irq_level==1) {
         /* FIXME: fine tune timer_max_fix (max fix per tick). 
          *        Should it be 1 (double time), 2 , 4, 10 ? 
@@ -390,7 +390,7 @@
     }
 #ifdef DEBUG_PIT
     printf("irq_level=%d next_delay=%f\n",
-           irq_level, 
+           irq_level,
            (double)(expire_time - current_time) / ticks_per_sec);
 #endif
     s->next_transition_time = expire_time;
@@ -412,7 +412,7 @@
     PITState *pit = opaque;
     PITChannelState *s;
     int i;
-    
+
     for(i = 0; i < 3; i++) {
         s = &pit->channels[i];
         qemu_put_be32s(f, &s->count);
@@ -440,7 +440,7 @@
     PITState *pit = opaque;
     PITChannelState *s;
     int i;
-    
+
     if (version_id != 1)
         return -EINVAL;
 
@@ -481,7 +481,7 @@
     }
 }
 
-PITState *pit_init(int base, int irq)
+PITState *pit_init(int base, qemu_irq irq)
 {
     PITState *pit = &pit_state;
     PITChannelState *s;
diff --git a/hw/i8259.c b/hw/i8259.c
index 6e85310..f8a80b4 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -1,8 +1,8 @@
 /*
  * QEMU 8259 interrupt controller emulation
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -44,6 +44,7 @@
     uint8_t rotate_on_auto_eoi;
     uint8_t special_fully_nested_mode;
     uint8_t init4; /* true if 4 byte init */
+    uint8_t single_mode; /* true if slave pic is not initialized */
     uint8_t elcr; /* PIIX edge/trigger selection*/
     uint8_t elcr_mask;
     PicState2 *pics_state;
@@ -53,7 +54,7 @@
     /* 0 is master pic, 1 is slave pic */
     /* XXX: better separation between the two pics */
     PicState pics[2];
-    IRQRequestFunc *irq_request;
+    qemu_irq parent_irq;
     void *irq_request_opaque;
     /* IOAPIC callback support */
     SetIRQFunc *alt_irq_func;
@@ -151,21 +152,21 @@
         {
             int i;
             for(i = 0; i < 2; i++) {
-                printf("pic%d: imr=%x irr=%x padd=%d\n", 
-                       i, s->pics[i].imr, s->pics[i].irr, 
+                printf("pic%d: imr=%x irr=%x padd=%d\n",
+                       i, s->pics[i].imr, s->pics[i].irr,
                        s->pics[i].priority_add);
-                
+
             }
         }
         printf("pic: cpu_interrupt\n");
 #endif
-        s->irq_request(s->irq_request_opaque, 1);
+        qemu_irq_raise(s->parent_irq);
     }
 
 /* all targets should do this rather than acking the IRQ in the cpu */
 #if defined(TARGET_MIPS)
     else {
-        s->irq_request(s->irq_request_opaque, 0);
+        qemu_irq_lower(s->parent_irq);
     }
 #endif
 }
@@ -174,7 +175,7 @@
 int64_t irq_time[16];
 #endif
 
-void pic_set_irq_new(void *opaque, int irq, int level)
+void i8259_set_irq(void *opaque, int irq, int level)
 {
     PicState2 *s = opaque;
 #ifdef USE_KVM
@@ -187,7 +188,7 @@
 #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
     if (level != irq_level[irq]) {
 #if defined(DEBUG_PIC)
-        printf("pic_set_irq: irq=%d level=%d\n", irq, level);
+        printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
 #endif
         irq_level[irq] = level;
 #ifdef DEBUG_IRQ_COUNT
@@ -208,12 +209,6 @@
     pic_update_irq(s);
 }
 
-/* obsolete function */
-void pic_set_irq(int irq, int level)
-{
-    pic_set_irq_new(isa_pic, irq, level);
-}
-
 /* acknowledge interrupt 'irq' */
 static inline void pic_intack(PicState *s, int irq)
 {
@@ -223,19 +218,11 @@
     } else {
         s->isr |= (1 << irq);
     }
+
     /* We don't clear a level sensitive interrupt here */
     if (!(s->elcr & (1 << irq)))
         s->irr &= ~(1 << irq);
 
-    if (time_drift_fix && irq == 0) {
-        extern int64_t timer_acks, timer_ints_to_push;
-        timer_acks++;
-        if (timer_ints_to_push > 0) {
-            timer_ints_to_push--;
-            pic_set_irq(0, 0); /* set it low (edge irq)*/
-            pic_set_irq(0, 1); /* interrupt again */
-        }
-    }
 }
 
 int pic_read_irq(PicState2 *s)
@@ -244,6 +231,17 @@
 
     irq = pic_get_irq(&s->pics[0]);
     if (irq >= 0) {
+
+	if (time_drift_fix && irq == 0) {
+	    extern int64_t timer_acks, timer_ints_to_push;
+	    timer_acks++;
+	    if (timer_ints_to_push > 0) {
+		timer_ints_to_push--;
+		qemu_irq_lower(s->parent_irq);
+		qemu_irq_raise(s->parent_irq);
+	    }
+	}
+
         pic_intack(&s->pics[0], irq);
         if (irq == 2) {
             irq2 = pic_get_irq(&s->pics[1]);
@@ -264,10 +262,10 @@
         intno = s->pics[0].irq_base + irq;
     }
     pic_update_irq(s);
-        
+
 #ifdef DEBUG_IRQ_LATENCY
-    printf("IRQ%d latency=%0.3fus\n", 
-           irq, 
+    printf("IRQ%d latency=%0.3fus\n",
+           irq,
            (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
 #endif
 #if defined(DEBUG_PIC)
@@ -294,6 +292,7 @@
     s->rotate_on_auto_eoi = 0;
     s->special_fully_nested_mode = 0;
     s->init4 = 0;
+    s->single_mode = 0;
     /* Note: ELCR is not reset */
 }
 
@@ -311,11 +310,10 @@
             /* init */
             pic_reset(s);
             /* deassert a pending interrupt */
-            s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
+            qemu_irq_lower(s->pics_state->parent_irq);
             s->init_state = 1;
             s->init4 = val & 1;
-            if (val & 0x02)
-                hw_error("single mode not supported");
+            s->single_mode = val & 2;
             if (val & 0x08)
                 hw_error("level sensitive irq not supported");
         } else if (val & 0x08) {
@@ -372,7 +370,7 @@
             break;
         case 1:
             s->irq_base = val & 0xf8;
-            s->init_state = 2;
+            s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
             break;
         case 2:
             if (s->init4) {
@@ -450,7 +448,7 @@
         ret = pic_poll_read(&s->pics[1], 0x80) + 8;
     /* Prepare for ISR read */
     s->pics[0].read_reg_select = 1;
-    
+
     return ret;
 }
 
@@ -540,7 +538,7 @@
         kvm_kernel_pic_save_to_user(s);
     }
 #endif
-    
+
     qemu_put_8s(f, &s->last_irr);
     qemu_put_8s(f, &s->irr);
     qemu_put_8s(f, &s->imr);
@@ -555,13 +553,14 @@
     qemu_put_8s(f, &s->rotate_on_auto_eoi);
     qemu_put_8s(f, &s->special_fully_nested_mode);
     qemu_put_8s(f, &s->init4);
+    qemu_put_8s(f, &s->single_mode);
     qemu_put_8s(f, &s->elcr);
 }
 
 static int pic_load(QEMUFile *f, void *opaque, int version_id)
 {
     PicState *s = opaque;
-    
+
     if (version_id != 1)
         return -EINVAL;
 
@@ -579,6 +578,7 @@
     qemu_get_8s(f, &s->rotate_on_auto_eoi);
     qemu_get_8s(f, &s->special_fully_nested_mode);
     qemu_get_8s(f, &s->init4);
+    qemu_get_8s(f, &s->single_mode);
     qemu_get_8s(f, &s->elcr);
 
 #ifdef USE_KVM
@@ -607,15 +607,15 @@
 {
     int i;
     PicState *s;
-    
+
     if (!isa_pic)
         return;
 
     for(i=0;i<2;i++) {
         s = &isa_pic->pics[i];
         term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
-                    i, s->irr, s->imr, s->isr, s->priority_add, 
-                    s->irq_base, s->read_reg_select, s->elcr, 
+                    i, s->irr, s->imr, s->isr, s->priority_add,
+                    s->irq_base, s->read_reg_select, s->elcr,
                     s->special_fully_nested_mode);
     }
 }
@@ -637,9 +637,10 @@
 #endif
 }
 
-PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
+qemu_irq *i8259_init(qemu_irq parent_irq)
 {
     PicState2 *s;
+
     s = qemu_mallocz(sizeof(PicState2));
     if (!s)
         return NULL;
@@ -647,11 +648,11 @@
     pic_init1(0xa0, 0x4d1, &s->pics[1]);
     s->pics[0].elcr_mask = 0xf8;
     s->pics[1].elcr_mask = 0xde;
-    s->irq_request = irq_request;
-    s->irq_request_opaque = irq_request_opaque;
+    s->parent_irq = parent_irq;
     s->pics[0].pics_state = s;
     s->pics[1].pics_state = s;
-    return s;
+    isa_pic = s;
+    return qemu_allocate_irqs(i8259_set_irq, s, 16);
 }
 
 void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
diff --git a/hw/ide.c b/hw/ide.c
index 6967d33..329d053 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -1,8 +1,9 @@
 /*
  * QEMU IDE disk and CD-ROM Emulator
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ * Copyright (c) 2006 Openedhand Ltd.
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -131,6 +132,7 @@
 #define WIN_SPECIFY			0x91 /* set drive geometry translation */
 #define WIN_DOWNLOAD_MICROCODE		0x92
 #define WIN_STANDBYNOW2			0x94
+#define CFA_IDLEIMMEDIATE		0x95 /* force drive to become "ready" */
 #define WIN_STANDBY2			0x96
 #define WIN_SETIDLE2			0x97
 #define WIN_CHECKPOWERMODE2		0x98
@@ -142,7 +144,8 @@
 #define WIN_PIDENTIFY			0xA1 /* identify ATAPI device	*/
 #define WIN_QUEUED_SERVICE		0xA2
 #define WIN_SMART			0xB0 /* self-monitoring and reporting */
-#define CFA_ERASE_SECTORS       	0xC0
+#define CFA_ACCESS_METADATA_STORAGE	0xB8
+#define CFA_ERASE_SECTORS       	0xC0 /* microdrives implement as NOP */
 #define WIN_MULTREAD			0xC4 /* read sectors using multiple mode*/
 #define WIN_MULTWRITE			0xC5 /* write sectors using multiple mode */
 #define WIN_SETMULT			0xC6 /* enable/disable multiple mode */
@@ -153,7 +156,7 @@
 #define WIN_WRITEDMA_ONCE		0xCB /* 28-Bit - without retries */
 #define WIN_WRITEDMA_QUEUED		0xCC /* write sectors using Queued DMA transfers */
 #define CFA_WRITE_MULTI_WO_ERASE	0xCD /* CFA Write multiple without erase */
-#define WIN_GETMEDIASTATUS		0xDA	
+#define WIN_GETMEDIASTATUS		0xDA
 #define WIN_ACKMEDIACHANGE		0xDB /* ATA-1, ATA-2 vendor */
 #define WIN_POSTBOOT			0xDC
 #define WIN_PREBOOT			0xDD
@@ -176,11 +179,13 @@
 #define WIN_IDENTIFY_DMA		0xEE /* same as WIN_IDENTIFY, but DMA */
 #define WIN_SETFEATURES			0xEF /* set special drive features */
 #define EXABYTE_ENABLE_NEST		0xF0
+#define IBM_SENSE_CONDITION		0xF0 /* measure disk temperature */
 #define WIN_SECURITY_SET_PASS		0xF1
 #define WIN_SECURITY_UNLOCK		0xF2
 #define WIN_SECURITY_ERASE_PREPARE	0xF3
 #define WIN_SECURITY_ERASE_UNIT		0xF4
 #define WIN_SECURITY_FREEZE_LOCK	0xF5
+#define CFA_WEAR_LEVEL			0xF5 /* microdrives implement as NOP */
 #define WIN_SECURITY_DISABLE		0xF6
 #define WIN_READ_NATIVE_MAX		0xF8 /* return the native maximum address */
 #define WIN_SET_MAX			0xF9
@@ -243,12 +248,12 @@
 #define GPCMD_VERIFY_10			    0x2f
 #define GPCMD_WRITE_10			    0x2a
 #define GPCMD_WRITE_AND_VERIFY_10	    0x2e
-/* This is listed as optional in ATAPI 2.6, but is (curiously) 
+/* This is listed as optional in ATAPI 2.6, but is (curiously)
  * missing from Mt. Fuji, Table 57.  It _is_ mentioned in Mt. Fuji
  * Table 377 as an MMC command for SCSi devices though...  Most ATAPI
  * drives support it. */
 #define GPCMD_SET_SPEED			    0xbb
-/* This seems to be a SCSI specific CD-ROM opcode 
+/* This seems to be a SCSI specific CD-ROM opcode
  * to play data at track/index */
 #define GPCMD_PLAYAUDIO_TI		    0x48
 /*
@@ -256,6 +261,7 @@
  * older drives only.
  */
 #define GPCMD_GET_MEDIA_STATUS		    0xda
+#define GPCMD_MODE_SENSE_6		    0x1a
 
 /* Mode page codes for mode sense/set */
 #define GPMODE_R_W_ERROR_PAGE		0x01
@@ -282,6 +288,12 @@
 #define ASC_MEDIUM_NOT_PRESENT               0x3a
 #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED  0x39
 
+#define CFA_NO_ERROR            0x00
+#define CFA_MISC_ERROR          0x09
+#define CFA_INVALID_COMMAND     0x20
+#define CFA_INVALID_ADDRESS     0x21
+#define CFA_ADDRESS_OVERFLOW    0x2f
+
 #define SENSE_NONE            0
 #define SENSE_NOT_READY       2
 #define SENSE_ILLEGAL_REQUEST 5
@@ -295,14 +307,13 @@
 typedef struct IDEState {
     /* ide config */
     int is_cdrom;
+    int is_cf;
     int cylinders, heads, sectors;
     int64_t nb_sectors;
     int mult_sectors;
     int identify_set;
     uint16_t identify_data[256];
-    SetIRQFunc *set_irq;
-    void *irq_opaque;
-    int irq;
+    qemu_irq irq;
     PCIDevice *pci_dev;
     struct BMDMAState *bmdma;
     int drive_serial;
@@ -328,7 +339,7 @@
     /* set for lba48 access */
     uint8_t lba48;
     /* depends on bit 4 in select, only meaningful for drive 0 */
-    struct IDEState *cur_drive; 
+    struct IDEState *cur_drive;
     BlockDriverState *bs;
     /* ATAPI specific */
     uint8_t sense_key;
@@ -349,6 +360,12 @@
     uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
     QEMUTimer *sector_write_timer; /* only used for win2k instal hack */
     uint32_t irq_count; /* counts IRQs when using win2k install hack */
+    /* CF-ATA extended error */
+    uint8_t ext_error;
+    /* CF-ATA metadata storage */
+    uint32_t mdata_size;
+    uint8_t *mdata_storage;
+    int media_changed;
 } IDEState;
 
 #define BM_STATUS_DMAING 0x01
@@ -360,6 +377,7 @@
 
 #define IDE_TYPE_PIIX3   0
 #define IDE_TYPE_CMD646  1
+#define IDE_TYPE_PIIX4   2
 
 /* CMD646 specific */
 #define MRDMODE		0x71
@@ -374,7 +392,7 @@
     uint8_t cmd;
     uint8_t status;
     uint32_t addr;
-    
+
     struct PCIIDEState *pci_dev;
     /* current transfer state */
     uint32_t cur_addr;
@@ -439,11 +457,11 @@
     memset(s->io_buffer, 0, 512);
     p = (uint16_t *)s->io_buffer;
     put_le16(p + 0, 0x0040);
-    put_le16(p + 1, s->cylinders); 
+    put_le16(p + 1, s->cylinders);
     put_le16(p + 3, s->heads);
     put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
     put_le16(p + 5, 512); /* XXX: retired, remove ? */
-    put_le16(p + 6, s->sectors); 
+    put_le16(p + 6, s->sectors);
     snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
     padstr((uint8_t *)(p + 10), buf, 20); /* serial number */
     put_le16(p + 20, 3); /* XXX: retired, remove ? */
@@ -451,7 +469,7 @@
     put_le16(p + 22, 4); /* ecc bytes */
     padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
     padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */
-#if MAX_MULT_SECTORS > 1    
+#if MAX_MULT_SECTORS > 1
     put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
 #endif
     put_le16(p + 48, 1); /* dword I/O */
@@ -544,6 +562,74 @@
     s->identify_set = 1;
 }
 
+static void ide_cfata_identify(IDEState *s)
+{
+    uint16_t *p;
+    uint32_t cur_sec;
+    char buf[20];
+
+    p = (uint16_t *) s->identify_data;
+    if (s->identify_set)
+        goto fill_buffer;
+
+    memset(p, 0, sizeof(s->identify_data));
+
+    cur_sec = s->cylinders * s->heads * s->sectors;
+
+    put_le16(p + 0, 0x848a);			/* CF Storage Card signature */
+    put_le16(p + 1, s->cylinders);		/* Default cylinders */
+    put_le16(p + 3, s->heads);			/* Default heads */
+    put_le16(p + 6, s->sectors);		/* Default sectors per track */
+    put_le16(p + 7, s->nb_sectors >> 16);	/* Sectors per card */
+    put_le16(p + 8, s->nb_sectors);		/* Sectors per card */
+    snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
+    padstr((uint8_t *)(p + 10), buf, 20);	/* Serial number in ASCII */
+    put_le16(p + 22, 0x0004);			/* ECC bytes */
+    padstr((uint8_t *) (p + 23), QEMU_VERSION, 8);	/* Firmware Revision */
+    padstr((uint8_t *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
+#if MAX_MULT_SECTORS > 1
+    put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
+#else
+    put_le16(p + 47, 0x0000);
+#endif
+    put_le16(p + 49, 0x0f00);			/* Capabilities */
+    put_le16(p + 51, 0x0002);			/* PIO cycle timing mode */
+    put_le16(p + 52, 0x0001);			/* DMA cycle timing mode */
+    put_le16(p + 53, 0x0003);			/* Translation params valid */
+    put_le16(p + 54, s->cylinders);		/* Current cylinders */
+    put_le16(p + 55, s->heads);			/* Current heads */
+    put_le16(p + 56, s->sectors);		/* Current sectors */
+    put_le16(p + 57, cur_sec);			/* Current capacity */
+    put_le16(p + 58, cur_sec >> 16);		/* Current capacity */
+    if (s->mult_sectors)			/* Multiple sector setting */
+        put_le16(p + 59, 0x100 | s->mult_sectors);
+    put_le16(p + 60, s->nb_sectors);		/* Total LBA sectors */
+    put_le16(p + 61, s->nb_sectors >> 16);	/* Total LBA sectors */
+    put_le16(p + 63, 0x0203);			/* Multiword DMA capability */
+    put_le16(p + 64, 0x0001);			/* Flow Control PIO support */
+    put_le16(p + 65, 0x0096);			/* Min. Multiword DMA cycle */
+    put_le16(p + 66, 0x0096);			/* Rec. Multiword DMA cycle */
+    put_le16(p + 68, 0x00b4);			/* Min. PIO cycle time */
+    put_le16(p + 82, 0x400c);			/* Command Set supported */
+    put_le16(p + 83, 0x7068);			/* Command Set supported */
+    put_le16(p + 84, 0x4000);			/* Features supported */
+    put_le16(p + 85, 0x000c);			/* Command Set enabled */
+    put_le16(p + 86, 0x7044);			/* Command Set enabled */
+    put_le16(p + 87, 0x4000);			/* Features enabled */
+    put_le16(p + 91, 0x4060);			/* Current APM level */
+    put_le16(p + 129, 0x0002);			/* Current features option */
+    put_le16(p + 130, 0x0005);			/* Reassigned sectors */
+    put_le16(p + 131, 0x0001);			/* Initial power mode */
+    put_le16(p + 132, 0x0000);			/* User signature */
+    put_le16(p + 160, 0x8100);			/* Power requirement */
+    put_le16(p + 161, 0x8001);			/* CF command set */
+
+    s->identify_set = 1;
+
+fill_buffer:
+    memcpy(s->io_buffer, p, sizeof(s->identify_data));
+}
+
 static void ide_set_signature(IDEState *s)
 {
     s->select &= 0xf0; /* clear head */
@@ -575,12 +661,12 @@
         if (bm) {
             bm->status |= BM_STATUS_INT;
         }
-        s->set_irq(s->irq_opaque, s->irq, 1);
+        qemu_irq_raise(s->irq);
     }
 }
 
 /* prepare data transfer and tell what to do after */
-static void ide_transfer_start(IDEState *s, uint8_t *buf, int size, 
+static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
                                EndTransferFunc *end_transfer_func)
 {
     s->end_transfer_func = end_transfer_func;
@@ -685,7 +771,7 @@
 
     for(;;) {
         l = s->io_buffer_size - s->io_buffer_index;
-        if (l <= 0) 
+        if (l <= 0)
             break;
         if (bm->cur_prd_len == 0) {
             /* end of table (with a fail safe of one page) */
@@ -707,10 +793,10 @@
             l = bm->cur_prd_len;
         if (l > 0) {
             if (is_write) {
-                cpu_physical_memory_write(bm->cur_prd_addr, 
+                cpu_physical_memory_write(bm->cur_prd_addr,
                                           s->io_buffer + s->io_buffer_index, l);
             } else {
-                cpu_physical_memory_read(bm->cur_prd_addr, 
+                cpu_physical_memory_read(bm->cur_prd_addr,
                                           s->io_buffer + s->io_buffer_index, l);
             }
             bm->cur_prd_addr += l;
@@ -761,7 +847,7 @@
 #ifdef DEBUG_AIO
     printf("aio_read: sector_num=%lld n=%d\n", sector_num, n);
 #endif
-    bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n, 
+    bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n,
                               ide_read_dma_cb, bm);
 }
 
@@ -779,10 +865,44 @@
     ide_set_irq(s);
 }
 
+static void ide_sector_write_aio_cb(void *opaque, int ret)
+{
+    BMDMAState *bm = opaque;
+    IDEState *s = bm->ide_if;
+
+#ifdef TARGET_I386
+    if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
+	/* It seems there is a bug in the Windows 2000 installer HDD
+	   IDE driver which fills the disk with empty logs when the
+	   IDE write IRQ comes too early. This hack tries to correct
+	   that at the expense of slower write performances. Use this
+	   option _only_ to install Windows 2000. You must disable it
+	   for normal use. */
+	qemu_mod_timer(s->sector_write_timer,
+		       qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
+    } else
+#endif
+    {
+	ide_set_irq(s);
+    }
+    bm->aiocb = NULL;
+}
+
 static void ide_sector_write(IDEState *s)
 {
+    BMDMAState *bm;
     int64_t sector_num;
-    int ret, n, n1;
+    int n, n1;
+
+    s->io_buffer_index = 0;
+    s->io_buffer_size = 0;
+    bm = s->bmdma;
+    if(bm == NULL) {
+	bm = qemu_mallocz(sizeof(BMDMAState));
+	s->bmdma = bm;
+    }
+    bm->ide_if = s;
+    bm->dma_cb = ide_sector_write_aio_cb;
 
     s->status = READY_STAT | SEEK_STAT;
     sector_num = ide_get_sector(s);
@@ -792,10 +912,9 @@
     n = s->nsector;
     if (n > s->req_nb_sectors)
         n = s->req_nb_sectors;
-    ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
     s->nsector -= n;
     if (s->nsector == 0) {
-        /* no more sector to write */
+        /* no more sectors to write */
         ide_transfer_stop(s);
     } else {
         n1 = s->nsector;
@@ -804,22 +923,9 @@
         ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
     }
     ide_set_sector(s, sector_num + n);
-    
-#ifdef TARGET_I386
-    if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
-        /* It seems there is a bug in the Windows 2000 installer HDD
-           IDE driver which fills the disk with empty logs when the
-           IDE write IRQ comes too early. This hack tries to correct
-           that at the expense of slower write performances. Use this
-           option _only_ to install Windows 2000. You must disable it
-           for normal use. */
-        qemu_mod_timer(s->sector_write_timer, 
-                       qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
-    } else 
-#endif
-    {
-        ide_set_irq(s);
-    }
+
+    bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
+			       ide_sector_write_aio_cb, bm);
 }
 
 /* XXX: handle errors */
@@ -863,7 +969,7 @@
 #ifdef DEBUG_AIO
     printf("aio_write: sector_num=%lld n=%d\n", sector_num, n);
 #endif
-    bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n, 
+    bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
                                ide_write_dma_cb, bm);
 }
 
@@ -945,7 +1051,7 @@
     memset(buf, 0, 288);
 }
 
-static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf, 
+static int cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
                            int sector_size)
 {
     int ret;
@@ -971,10 +1077,10 @@
 {
     /* XXX: handle more errors */
     if (ret == -ENOMEDIUM) {
-        ide_atapi_cmd_error(s, SENSE_NOT_READY, 
+        ide_atapi_cmd_error(s, SENSE_NOT_READY,
                             ASC_MEDIUM_NOT_PRESENT);
     } else {
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, 
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
                             ASC_LOGICAL_BLOCK_OOR);
     }
 }
@@ -984,7 +1090,7 @@
 {
     int byte_count_limit, size, ret;
 #ifdef DEBUG_IDE_ATAPI
-    printf("reply: tx_size=%d elem_tx_size=%d index=%d\n", 
+    printf("reply: tx_size=%d elem_tx_size=%d index=%d\n",
            s->packet_transfer_size,
            s->elementary_transfer_size,
            s->io_buffer_index);
@@ -1016,7 +1122,7 @@
             size = s->cd_sector_size - s->io_buffer_index;
             if (size > s->elementary_transfer_size)
                 size = s->elementary_transfer_size;
-            ide_transfer_start(s, s->io_buffer + s->io_buffer_index, 
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index,
                                size, ide_atapi_cmd_reply_end);
             s->packet_transfer_size -= size;
             s->elementary_transfer_size -= size;
@@ -1045,7 +1151,7 @@
                 if (size > (s->cd_sector_size - s->io_buffer_index))
                     size = (s->cd_sector_size - s->io_buffer_index);
             }
-            ide_transfer_start(s, s->io_buffer + s->io_buffer_index, 
+            ide_transfer_start(s, s->io_buffer + s->io_buffer_index,
                                size, ide_atapi_cmd_reply_end);
             s->packet_transfer_size -= size;
             s->elementary_transfer_size -= size;
@@ -1140,7 +1246,7 @@
         bm->aiocb = NULL;
         return;
     }
-    
+
     s->io_buffer_index = 0;
     if (s->cd_sector_size == 2352) {
         n = 1;
@@ -1156,12 +1262,12 @@
 #ifdef DEBUG_AIO
     printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
 #endif
-    bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2, 
-                              s->io_buffer + data_offset, n * 4, 
+    bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2,
+                              s->io_buffer + data_offset, n * 4,
                               ide_atapi_cmd_read_dma_cb, bm);
     if (!bm->aiocb) {
         /* Note: media not present is the most likely case */
-        ide_atapi_cmd_error(s, SENSE_NOT_READY, 
+        ide_atapi_cmd_error(s, SENSE_NOT_READY,
                             ASC_MEDIUM_NOT_PRESENT);
         goto eot;
     }
@@ -1183,7 +1289,7 @@
     ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
 }
 
-static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors, 
+static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
                                int sector_size)
 {
 #ifdef DEBUG_IDE_ATAPI
@@ -1220,14 +1326,18 @@
         if (bdrv_is_inserted(s->bs)) {
             ide_atapi_cmd_ok(s);
         } else {
-            ide_atapi_cmd_error(s, SENSE_NOT_READY, 
+            ide_atapi_cmd_error(s, SENSE_NOT_READY,
                                 ASC_MEDIUM_NOT_PRESENT);
         }
         break;
+    case GPCMD_MODE_SENSE_6:
     case GPCMD_MODE_SENSE_10:
         {
             int action, code;
-            max_len = ube16_to_cpu(packet + 7);
+            if (packet[0] == GPCMD_MODE_SENSE_10)
+                max_len = ube16_to_cpu(packet + 7);
+            else
+                max_len = packet[4];
             action = packet[2] >> 6;
             code = packet[2] & 0x3f;
             switch(action) {
@@ -1263,9 +1373,9 @@
 
                     buf[8] = 0x2a;
                     buf[9] = 0x12;
-                    buf[10] = 0x00;
+                    buf[10] = 0x08;
                     buf[11] = 0x00;
-                    
+
                     buf[12] = 0x70;
                     buf[13] = 3 << 5;
                     buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
@@ -1293,7 +1403,7 @@
                 goto error_cmd;
             default:
             case 3: /* saved values */
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, 
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
                                     ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
                 break;
             }
@@ -1313,7 +1423,7 @@
             bdrv_set_locked(s->bs, packet[4] & 1);
             ide_atapi_cmd_ok(s);
         } else {
-            ide_atapi_cmd_error(s, SENSE_NOT_READY, 
+            ide_atapi_cmd_error(s, SENSE_NOT_READY,
                                 ASC_MEDIUM_NOT_PRESENT);
         }
         break;
@@ -1359,7 +1469,7 @@
                 ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
                 break;
             default:
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, 
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
                                     ASC_INV_FIELD_IN_CMD_PACKET);
                 break;
             }
@@ -1373,13 +1483,13 @@
             bdrv_get_geometry(s->bs, &total_sectors);
             total_sectors >>= 2;
             if (total_sectors <= 0) {
-                ide_atapi_cmd_error(s, SENSE_NOT_READY, 
+                ide_atapi_cmd_error(s, SENSE_NOT_READY,
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
             }
             lba = ube32_to_cpu(packet + 2);
             if (lba >= total_sectors) {
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, 
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
                                     ASC_LOGICAL_BLOCK_OOR);
                 break;
             }
@@ -1391,7 +1501,7 @@
             int start, eject;
             start = packet[4] & 1;
             eject = (packet[4] >> 1) & 1;
-            
+
             if (eject && !start) {
                 /* eject the disk */
                 bdrv_eject(s->bs, 1);
@@ -1423,7 +1533,7 @@
             bdrv_get_geometry(s->bs, &total_sectors);
             total_sectors >>= 2;
             if (total_sectors <= 0) {
-                ide_atapi_cmd_error(s, SENSE_NOT_READY, 
+                ide_atapi_cmd_error(s, SENSE_NOT_READY,
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
             }
@@ -1454,7 +1564,7 @@
                 break;
             default:
             error_cmd:
-                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, 
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
                                     ASC_INV_FIELD_IN_CMD_PACKET);
                 break;
             }
@@ -1467,7 +1577,7 @@
             bdrv_get_geometry(s->bs, &total_sectors);
             total_sectors >>= 2;
             if (total_sectors <= 0) {
-                ide_atapi_cmd_error(s, SENSE_NOT_READY, 
+                ide_atapi_cmd_error(s, SENSE_NOT_READY,
                                     ASC_MEDIUM_NOT_PRESENT);
                 break;
             }
@@ -1477,13 +1587,57 @@
             ide_atapi_cmd_reply(s, 8, 8);
         }
         break;
+    case GPCMD_READ_DVD_STRUCTURE:
+        {
+            int media = packet[1];
+            int layer = packet[6];
+            int format = packet[2];
+            int64_t total_sectors;
+
+            if (media != 0 || layer != 0)
+            {
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET);
+            }
+
+            switch (format) {
+                case 0:
+                    bdrv_get_geometry(s->bs, &total_sectors);
+                    total_sectors >>= 2;
+
+                    memset(buf, 0, 2052);
+
+                    buf[4] = 1;   // DVD-ROM, part version 1
+                    buf[5] = 0xf; // 120mm disc, maximum rate unspecified
+                    buf[6] = 0;   // one layer, embossed data
+                    buf[7] = 0;
+
+                    cpu_to_ube32(buf + 8, 0);
+                    cpu_to_ube32(buf + 12, total_sectors - 1);
+                    cpu_to_ube32(buf + 16, total_sectors - 1);
+
+                    cpu_to_be16wu((uint16_t *)buf, 2048 + 4);
+
+                    ide_atapi_cmd_reply(s, 2048 + 3, 2048 + 4);
+                    break;
+
+                default:
+                    ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                        ASC_INV_FIELD_IN_CMD_PACKET);
+                    break;
+            }
+        }
+        break;
+    case GPCMD_SET_SPEED:
+        ide_atapi_cmd_ok(s);
+        break;
     case GPCMD_INQUIRY:
         max_len = packet[4];
         buf[0] = 0x05; /* CD-ROM */
         buf[1] = 0x80; /* removable */
         buf[2] = 0x00; /* ISO */
         buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
-        buf[4] = 31; /* additionnal length */
+        buf[4] = 31; /* additional length */
         buf[5] = 0; /* reserved */
         buf[6] = 0; /* reserved */
         buf[7] = 0; /* reserved */
@@ -1492,13 +1646,89 @@
         padstr8(buf + 32, 4, QEMU_VERSION);
         ide_atapi_cmd_reply(s, 36, max_len);
         break;
+    case GPCMD_GET_CONFIGURATION:
+        {
+            int64_t total_sectors;
+
+            /* only feature 0 is supported */
+            if (packet[2] != 0 || packet[3] != 0) {
+                ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
+                                    ASC_INV_FIELD_IN_CMD_PACKET);
+                break;
+            }
+            memset(buf, 0, 32);
+            bdrv_get_geometry(s->bs, &total_sectors);
+            buf[3] = 16;
+            buf[7] = total_sectors <= 1433600 ? 0x08 : 0x10; /* current profile */
+            buf[10] = 0x10 | 0x1;
+            buf[11] = 0x08; /* size of profile list */
+            buf[13] = 0x10; /* DVD-ROM profile */
+            buf[14] = buf[7] == 0x10; /* (in)active */
+            buf[17] = 0x08; /* CD-ROM profile */
+            buf[18] = buf[7] == 0x08; /* (in)active */
+            ide_atapi_cmd_reply(s, 32, 32);
+            break;
+        }
     default:
-        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST, 
+        ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
                             ASC_ILLEGAL_OPCODE);
         break;
     }
 }
 
+static void ide_cfata_metadata_inquiry(IDEState *s)
+{
+    uint16_t *p;
+    uint32_t spd;
+
+    p = (uint16_t *) s->io_buffer;
+    memset(p, 0, 0x200);
+    spd = ((s->mdata_size - 1) >> 9) + 1;
+
+    put_le16(p + 0, 0x0001);			/* Data format revision */
+    put_le16(p + 1, 0x0000);			/* Media property: silicon */
+    put_le16(p + 2, s->media_changed);		/* Media status */
+    put_le16(p + 3, s->mdata_size & 0xffff);	/* Capacity in bytes (low) */
+    put_le16(p + 4, s->mdata_size >> 16);	/* Capacity in bytes (high) */
+    put_le16(p + 5, spd & 0xffff);		/* Sectors per device (low) */
+    put_le16(p + 6, spd >> 16);			/* Sectors per device (high) */
+}
+
+static void ide_cfata_metadata_read(IDEState *s)
+{
+    uint16_t *p;
+
+    if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
+        s->status = ERR_STAT;
+        s->error = ABRT_ERR;
+        return;
+    }
+
+    p = (uint16_t *) s->io_buffer;
+    memset(p, 0, 0x200);
+
+    put_le16(p + 0, s->media_changed);		/* Media status */
+    memcpy(p + 1, s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
+                    MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
+                                    s->nsector << 9), 0x200 - 2));
+}
+
+static void ide_cfata_metadata_write(IDEState *s)
+{
+    if (((s->hcyl << 16) | s->lcyl) << 9 > s->mdata_size + 2) {
+        s->status = ERR_STAT;
+        s->error = ABRT_ERR;
+        return;
+    }
+
+    s->media_changed = 0;
+
+    memcpy(s->mdata_storage + (((s->hcyl << 16) | s->lcyl) << 9),
+                    s->io_buffer + 2,
+                    MIN(MIN(s->mdata_size - (((s->hcyl << 16) | s->lcyl) << 9),
+                                    s->nsector << 9), 0x200 - 2));
+}
+
 /* called when the inserted state of the media has changed */
 static void cdrom_change_cb(void *opaque)
 {
@@ -1608,13 +1838,16 @@
 #endif
         s = ide_if->cur_drive;
         /* ignore commands to non existant slave */
-        if (s != ide_if && !s->bs) 
+        if (s != ide_if && !s->bs)
             break;
 
         switch(val) {
         case WIN_IDENTIFY:
             if (s->bs && !s->is_cdrom) {
-                ide_identify(s);
+                if (!s->is_cf)
+                    ide_identify(s);
+                else
+                    ide_cfata_identify(s);
                 s->status = READY_STAT | SEEK_STAT;
                 ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
             } else {
@@ -1632,12 +1865,16 @@
             ide_set_irq(s);
             break;
         case WIN_SETMULT:
-            if (s->nsector > MAX_MULT_SECTORS || 
-                s->nsector == 0 ||
-                (s->nsector & (s->nsector - 1)) != 0) {
+            if (s->is_cf && s->nsector == 0) {
+                /* Disable Read and Write Multiple */
+                s->mult_sectors = 0;
+                s->status = READY_STAT;
+            } else if ((s->nsector & 0xff) != 0 &&
+                ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
+                 (s->nsector & (s->nsector - 1)) != 0)) {
                 ide_abort_command(s);
             } else {
-                s->mult_sectors = s->nsector;
+                s->mult_sectors = s->nsector & 0xff;
                 s->status = READY_STAT;
             }
             ide_set_irq(s);
@@ -1655,7 +1892,7 @@
 	    lba48 = 1;
         case WIN_READ:
         case WIN_READ_ONCE:
-            if (!s->bs) 
+            if (!s->bs)
                 goto abort_cmd;
 	    ide_cmd_lba48_transform(s, lba48);
             s->req_nb_sectors = 1;
@@ -1665,11 +1902,14 @@
 	    lba48 = 1;
         case WIN_WRITE:
         case WIN_WRITE_ONCE:
+        case CFA_WRITE_SECT_WO_ERASE:
+        case WIN_WRITE_VERIFY:
 	    ide_cmd_lba48_transform(s, lba48);
             s->error = 0;
             s->status = SEEK_STAT | READY_STAT;
             s->req_nb_sectors = 1;
             ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
+            s->media_changed = 1;
             break;
 	case WIN_MULTREAD_EXT:
 	    lba48 = 1;
@@ -1683,6 +1923,7 @@
         case WIN_MULTWRITE_EXT:
 	    lba48 = 1;
         case WIN_MULTWRITE:
+        case CFA_WRITE_MULTI_WO_ERASE:
             if (!s->mult_sectors)
                 goto abort_cmd;
 	    ide_cmd_lba48_transform(s, lba48);
@@ -1693,12 +1934,13 @@
             if (n > s->req_nb_sectors)
                 n = s->req_nb_sectors;
             ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
+            s->media_changed = 1;
             break;
 	case WIN_READDMA_EXT:
 	    lba48 = 1;
         case WIN_READDMA:
         case WIN_READDMA_ONCE:
-            if (!s->bs) 
+            if (!s->bs)
                 goto abort_cmd;
 	    ide_cmd_lba48_transform(s, lba48);
             ide_sector_read_dma(s);
@@ -1707,10 +1949,11 @@
 	    lba48 = 1;
         case WIN_WRITEDMA:
         case WIN_WRITEDMA_ONCE:
-            if (!s->bs) 
+            if (!s->bs)
                 goto abort_cmd;
 	    ide_cmd_lba48_transform(s, lba48);
             ide_sector_write_dma(s);
+            s->media_changed = 1;
             break;
         case WIN_READ_NATIVE_MAX_EXT:
 	    lba48 = 1;
@@ -1721,6 +1964,7 @@
             ide_set_irq(s);
             break;
         case WIN_CHECKPOWERMODE1:
+        case WIN_CHECKPOWERMODE2:
             s->nsector = 0xff; /* device active or idle */
             s->status = READY_STAT;
             ide_set_irq(s);
@@ -1730,10 +1974,20 @@
                 goto abort_cmd;
             /* XXX: valid for CDROM ? */
             switch(s->feature) {
+            case 0xcc: /* reverting to power-on defaults enable */
+            case 0x66: /* reverting to power-on defaults disable */
             case 0x02: /* write cache enable */
             case 0x82: /* write cache disable */
             case 0xaa: /* read look-ahead enable */
             case 0x55: /* read look-ahead disable */
+            case 0x05: /* set advanced power management mode */
+            case 0x85: /* disable advanced power management mode */
+            case 0x69: /* NOP */
+            case 0x67: /* NOP */
+            case 0x96: /* NOP */
+            case 0x9a: /* NOP */
+            case 0x42: /* enable Automatic Acoustic Mode */
+            case 0xc2: /* disable Automatic Acoustic Mode */
                 s->status = READY_STAT | SEEK_STAT;
                 ide_set_irq(s);
                 break;
@@ -1772,9 +2026,17 @@
 	    s->status = READY_STAT;
             ide_set_irq(s);
             break;
-	case WIN_STANDBYNOW1:
+        case WIN_STANDBY:
+        case WIN_STANDBY2:
+        case WIN_STANDBYNOW1:
+        case WIN_STANDBYNOW2:
         case WIN_IDLEIMMEDIATE:
-	    s->status = READY_STAT;
+        case CFA_IDLEIMMEDIATE:
+        case WIN_SETIDLE1:
+        case WIN_SETIDLE2:
+        case WIN_SLEEPNOW1:
+        case WIN_SLEEPNOW2:
+            s->status = READY_STAT;
             ide_set_irq(s);
             break;
             /* ATAPI commands */
@@ -1809,9 +2071,82 @@
             s->status = READY_STAT;
             s->atapi_dma = s->feature & 1;
             s->nsector = 1;
-            ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE, 
+            ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
                                ide_atapi_cmd);
             break;
+        /* CF-ATA commands */
+        case CFA_REQ_EXT_ERROR_CODE:
+            if (!s->is_cf)
+                goto abort_cmd;
+            s->error = 0x09;    /* miscellaneous error */
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+        case CFA_ERASE_SECTORS:
+        case CFA_WEAR_LEVEL:
+            if (!s->is_cf)
+                goto abort_cmd;
+            if (val == CFA_WEAR_LEVEL)
+                s->nsector = 0;
+            if (val == CFA_ERASE_SECTORS)
+                s->media_changed = 1;
+            s->error = 0x00;
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
+        case CFA_TRANSLATE_SECTOR:
+            if (!s->is_cf)
+                goto abort_cmd;
+            s->error = 0x00;
+            s->status = READY_STAT;
+            memset(s->io_buffer, 0, 0x200);
+            s->io_buffer[0x00] = s->hcyl;			/* Cyl MSB */
+            s->io_buffer[0x01] = s->lcyl;			/* Cyl LSB */
+            s->io_buffer[0x02] = s->select;			/* Head */
+            s->io_buffer[0x03] = s->sector;			/* Sector */
+            s->io_buffer[0x04] = ide_get_sector(s) >> 16;	/* LBA MSB */
+            s->io_buffer[0x05] = ide_get_sector(s) >> 8;	/* LBA */
+            s->io_buffer[0x06] = ide_get_sector(s) >> 0;	/* LBA LSB */
+            s->io_buffer[0x13] = 0x00;				/* Erase flag */
+            s->io_buffer[0x18] = 0x00;				/* Hot count */
+            s->io_buffer[0x19] = 0x00;				/* Hot count */
+            s->io_buffer[0x1a] = 0x01;				/* Hot count */
+            ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+            ide_set_irq(s);
+            break;
+        case CFA_ACCESS_METADATA_STORAGE:
+            if (!s->is_cf)
+                goto abort_cmd;
+            switch (s->feature) {
+            case 0x02:	/* Inquiry Metadata Storage */
+                ide_cfata_metadata_inquiry(s);
+                break;
+            case 0x03:	/* Read Metadata Storage */
+                ide_cfata_metadata_read(s);
+                break;
+            case 0x04:	/* Write Metadata Storage */
+                ide_cfata_metadata_write(s);
+                break;
+            default:
+                goto abort_cmd;
+            }
+            ide_transfer_start(s, s->io_buffer, 0x200, ide_transfer_stop);
+            s->status = 0x00; /* NOTE: READY is _not_ set */
+            ide_set_irq(s);
+            break;
+        case IBM_SENSE_CONDITION:
+            if (!s->is_cf)
+                goto abort_cmd;
+            switch (s->feature) {
+            case 0x01:  /* sense temperature in device */
+                s->nsector = 0x50;      /* +20 C */
+                break;
+            default:
+                goto abort_cmd;
+            }
+            s->status = READY_STAT;
+            ide_set_irq(s);
+            break;
         default:
         abort_cmd:
             ide_abort_command(s);
@@ -1889,7 +2224,7 @@
             ret = 0;
         else
             ret = s->status;
-        s->set_irq(s->irq_opaque, s->irq, 0);
+        qemu_irq_lower(s->irq);
         break;
     }
 #ifdef DEBUG_IDE
@@ -1995,7 +2330,7 @@
     IDEState *s = ((IDEState *)opaque)->cur_drive;
     uint8_t *p;
     int ret;
-    
+
     p = s->data_ptr;
     ret = cpu_to_le32(*(uint32_t *)p);
     p += 4;
@@ -2017,7 +2352,10 @@
 
 static void ide_reset(IDEState *s)
 {
-    s->mult_sectors = MAX_MULT_SECTORS;
+    if (s->is_cf)
+        s->mult_sectors = 0;
+    else
+        s->mult_sectors = MAX_MULT_SECTORS;
     s->cur_drive = s;
     s->select = 0xa0;
     s->status = READY_STAT;
@@ -2026,6 +2364,7 @@
        accesses */
     s->end_transfer_func = ide_dummy_transfer_stop;
     ide_dummy_transfer_stop(s);
+    s->media_changed = 0;
 }
 
 struct partition {
@@ -2042,7 +2381,7 @@
 } __attribute__((packed));
 
 /* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
-static int guess_disk_lchs(IDEState *s, 
+static int guess_disk_lchs(IDEState *s,
                            int *pcylinders, int *pheads, int *psectors)
 {
     uint8_t buf[512];
@@ -2073,7 +2412,7 @@
             *psectors = sectors;
             *pcylinders = cylinders;
 #if 0
-            printf("guessed geometry: LCHS=%d %d %d\n", 
+            printf("guessed geometry: LCHS=%d %d %d\n",
                    cylinders, heads, sectors);
 #endif
             return 0;
@@ -2084,7 +2423,7 @@
 
 static void ide_init2(IDEState *ide_state,
                       BlockDriverState *hd0, BlockDriverState *hd1,
-                      SetIRQFunc *set_irq, void *irq_opaque, int irq)
+                      qemu_irq irq)
 {
     IDEState *s;
     static int drive_serial = 1;
@@ -2155,10 +2494,8 @@
             }
         }
         s->drive_serial = drive_serial++;
-        s->set_irq = set_irq;
-        s->irq_opaque = irq_opaque;
         s->irq = irq;
-        s->sector_write_timer = qemu_new_timer(vm_clock, 
+        s->sector_write_timer = qemu_new_timer(vm_clock,
                                                ide_sector_write_timer_cb, s);
         ide_reset(s);
     }
@@ -2172,7 +2509,7 @@
         register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state);
         register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state);
     }
-    
+
     /* data ports */
     register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state);
     register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state);
@@ -2180,10 +2517,66 @@
     register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state);
 }
 
+/* save per IDE drive data */
+static void ide_save(QEMUFile* f, IDEState *s)
+{
+    qemu_put_be32s(f, &s->mult_sectors);
+    qemu_put_be32s(f, &s->identify_set);
+    if (s->identify_set) {
+        qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512);
+    }
+    qemu_put_8s(f, &s->feature);
+    qemu_put_8s(f, &s->error);
+    qemu_put_be32s(f, &s->nsector);
+    qemu_put_8s(f, &s->sector);
+    qemu_put_8s(f, &s->lcyl);
+    qemu_put_8s(f, &s->hcyl);
+    qemu_put_8s(f, &s->hob_feature);
+    qemu_put_8s(f, &s->hob_nsector);
+    qemu_put_8s(f, &s->hob_sector);
+    qemu_put_8s(f, &s->hob_lcyl);
+    qemu_put_8s(f, &s->hob_hcyl);
+    qemu_put_8s(f, &s->select);
+    qemu_put_8s(f, &s->status);
+    qemu_put_8s(f, &s->lba48);
+
+    qemu_put_8s(f, &s->sense_key);
+    qemu_put_8s(f, &s->asc);
+    /* XXX: if a transfer is pending, we do not save it yet */
+}
+
+/* load per IDE drive data */
+static void ide_load(QEMUFile* f, IDEState *s)
+{
+    qemu_get_be32s(f, &s->mult_sectors);
+    qemu_get_be32s(f, &s->identify_set);
+    if (s->identify_set) {
+        qemu_get_buffer(f, (uint8_t *)s->identify_data, 512);
+    }
+    qemu_get_8s(f, &s->feature);
+    qemu_get_8s(f, &s->error);
+    qemu_get_be32s(f, &s->nsector);
+    qemu_get_8s(f, &s->sector);
+    qemu_get_8s(f, &s->lcyl);
+    qemu_get_8s(f, &s->hcyl);
+    qemu_get_8s(f, &s->hob_feature);
+    qemu_get_8s(f, &s->hob_nsector);
+    qemu_get_8s(f, &s->hob_sector);
+    qemu_get_8s(f, &s->hob_lcyl);
+    qemu_get_8s(f, &s->hob_hcyl);
+    qemu_get_8s(f, &s->select);
+    qemu_get_8s(f, &s->status);
+    qemu_get_8s(f, &s->lba48);
+
+    qemu_get_8s(f, &s->sense_key);
+    qemu_get_8s(f, &s->asc);
+    /* XXX: if a transfer is pending, we do not save it yet */
+}
+
 /***********************************************************/
 /* ISA IDE definitions */
 
-void isa_ide_init(int iobase, int iobase2, int irq,
+void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
                   BlockDriverState *hd0, BlockDriverState *hd1)
 {
     IDEState *ide_state;
@@ -2191,8 +2584,8 @@
     ide_state = qemu_mallocz(sizeof(IDEState) * 2);
     if (!ide_state)
         return;
-    
-    ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq);
+
+    ide_init2(ide_state, hd0, hd1, irq);
     ide_init_ioport(ide_state, iobase, iobase2);
 }
 
@@ -2201,7 +2594,7 @@
 
 static void cmd646_update_irq(PCIIDEState *d);
 
-static void ide_map(PCIDevice *pci_dev, int region_num, 
+static void ide_map(PCIDevice *pci_dev, int region_num,
                     uint32_t addr, uint32_t size, int type)
 {
     PCIIDEState *d = (PCIIDEState *)pci_dev;
@@ -2278,9 +2671,9 @@
     BMDMAState *bm = opaque;
     PCIIDEState *pci_dev;
     uint32_t val;
-    
+
     switch(addr & 3) {
-    case 0: 
+    case 0:
         val = bm->cmd;
         break;
     case 1:
@@ -2326,7 +2719,7 @@
     case 1:
         pci_dev = bm->pci_dev;
         if (pci_dev->type == IDE_TYPE_CMD646) {
-            pci_dev->dev.config[MRDMODE] = 
+            pci_dev->dev.config[MRDMODE] =
                 (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
             cmd646_update_irq(pci_dev);
         }
@@ -2367,7 +2760,7 @@
     bm->cur_addr = bm->addr;
 }
 
-static void bmdma_map(PCIDevice *pci_dev, int region_num, 
+static void bmdma_map(PCIDevice *pci_dev, int region_num,
                     uint32_t addr, uint32_t size, int type)
 {
     PCIIDEState *d = (PCIIDEState *)pci_dev;
@@ -2399,7 +2792,7 @@
                  !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
         ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
          !(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
-    pci_set_irq((PCIDevice *)d, 0, pci_level);
+    qemu_set_irq(d->dev.irq[0], pci_level);
 }
 
 /* the PCI irq level is the logical OR of the two channels */
@@ -2423,10 +2816,11 @@
     PCIIDEState *d;
     uint8_t *pci_conf;
     int i;
+    qemu_irq *irq;
 
-    d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE", 
+    d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE",
                                            sizeof(PCIIDEState),
-                                           -1, 
+                                           -1,
                                            NULL, NULL);
     d->type = IDE_TYPE_CMD646;
     pci_conf = d->dev.config;
@@ -2436,36 +2830,36 @@
     pci_conf[0x03] = 0x06;
 
     pci_conf[0x08] = 0x07; // IDE controller revision
-    pci_conf[0x09] = 0x8f; 
+    pci_conf[0x09] = 0x8f;
 
     pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
     pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
     pci_conf[0x0e] = 0x00; // header_type
-    
+
     if (secondary_ide_enabled) {
         /* XXX: if not enabled, really disable the seconday IDE controller */
         pci_conf[0x51] = 0x80; /* enable IDE1 */
     }
 
-    pci_register_io_region((PCIDevice *)d, 0, 0x8, 
+    pci_register_io_region((PCIDevice *)d, 0, 0x8,
                            PCI_ADDRESS_SPACE_IO, ide_map);
-    pci_register_io_region((PCIDevice *)d, 1, 0x4, 
+    pci_register_io_region((PCIDevice *)d, 1, 0x4,
                            PCI_ADDRESS_SPACE_IO, ide_map);
-    pci_register_io_region((PCIDevice *)d, 2, 0x8, 
+    pci_register_io_region((PCIDevice *)d, 2, 0x8,
                            PCI_ADDRESS_SPACE_IO, ide_map);
-    pci_register_io_region((PCIDevice *)d, 3, 0x4, 
+    pci_register_io_region((PCIDevice *)d, 3, 0x4,
                            PCI_ADDRESS_SPACE_IO, ide_map);
-    pci_register_io_region((PCIDevice *)d, 4, 0x10, 
+    pci_register_io_region((PCIDevice *)d, 4, 0x10,
                            PCI_ADDRESS_SPACE_IO, bmdma_map);
 
     pci_conf[0x3d] = 0x01; // interrupt on pin 1
-    
+
     for(i = 0; i < 4; i++)
         d->ide_if[i].pci_dev = (PCIDevice *)d;
-    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
-              cmd646_set_irq, d, 0);
-    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
-              cmd646_set_irq, d, 1);
+
+    irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
+    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], irq[0]);
+    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], irq[1]);
 }
 
 static void pci_ide_save(QEMUFile* f, void *opaque)
@@ -2494,30 +2888,7 @@
 
     /* per IDE drive data */
     for(i = 0; i < 4; i++) {
-        IDEState *s = &d->ide_if[i];
-        qemu_put_be32s(f, &s->mult_sectors);
-        qemu_put_be32s(f, &s->identify_set);
-        if (s->identify_set) {
-            qemu_put_buffer(f, (const uint8_t *)s->identify_data, 512);
-        }
-        qemu_put_8s(f, &s->feature);
-        qemu_put_8s(f, &s->error);
-        qemu_put_be32s(f, &s->nsector);
-        qemu_put_8s(f, &s->sector);
-        qemu_put_8s(f, &s->lcyl);
-        qemu_put_8s(f, &s->hcyl);
-        qemu_put_8s(f, &s->hob_feature);
-        qemu_put_8s(f, &s->hob_nsector);
-        qemu_put_8s(f, &s->hob_sector);
-        qemu_put_8s(f, &s->hob_lcyl);
-        qemu_put_8s(f, &s->hob_hcyl);
-        qemu_put_8s(f, &s->select);
-        qemu_put_8s(f, &s->status);
-        qemu_put_8s(f, &s->lba48);
-
-        qemu_put_8s(f, &s->sense_key);
-        qemu_put_8s(f, &s->asc);
-        /* XXX: if a transfer is pending, we do not save it yet */
+        ide_save(f, &d->ide_if[i]);
     }
 }
 
@@ -2551,30 +2922,7 @@
 
     /* per IDE drive data */
     for(i = 0; i < 4; i++) {
-        IDEState *s = &d->ide_if[i];
-        qemu_get_be32s(f, &s->mult_sectors);
-        qemu_get_be32s(f, &s->identify_set);
-        if (s->identify_set) {
-            qemu_get_buffer(f, (uint8_t *)s->identify_data, 512);
-        }
-        qemu_get_8s(f, &s->feature);
-        qemu_get_8s(f, &s->error);
-        qemu_get_be32s(f, &s->nsector);
-        qemu_get_8s(f, &s->sector);
-        qemu_get_8s(f, &s->lcyl);
-        qemu_get_8s(f, &s->hcyl);
-        qemu_get_8s(f, &s->hob_feature);
-        qemu_get_8s(f, &s->hob_nsector);
-        qemu_get_8s(f, &s->hob_sector);
-        qemu_get_8s(f, &s->hob_lcyl);
-        qemu_get_8s(f, &s->hob_hcyl);
-        qemu_get_8s(f, &s->select);
-        qemu_get_8s(f, &s->status);
-        qemu_get_8s(f, &s->lba48);
-
-        qemu_get_8s(f, &s->sense_key);
-        qemu_get_8s(f, &s->asc);
-        /* XXX: if a transfer is pending, we do not save it yet */
+        ide_load(f, &d->ide_if[i]);
     }
     return 0;
 }
@@ -2590,53 +2938,16 @@
     pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */
 }
 
-void pci_piix_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
-{
-    PCIIDEState *d;
-    uint8_t *pci_conf;
-    
-    /* register a function 1 of PIIX */
-    d = (PCIIDEState *)pci_register_device(bus, "PIIX IDE", 
-                                           sizeof(PCIIDEState),
-                                           devfn,
-                                           NULL, NULL);
-    d->type = IDE_TYPE_PIIX3;
-
-    pci_conf = d->dev.config;
-    pci_conf[0x00] = 0x86; // Intel
-    pci_conf[0x01] = 0x80;
-    pci_conf[0x02] = 0x30;
-    pci_conf[0x03] = 0x12;
-    pci_conf[0x08] = 0x02; // Step A1
-    pci_conf[0x09] = 0x80; // legacy ATA mode
-    pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
-    pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
-    pci_conf[0x0e] = 0x00; // header_type
-
-    piix3_reset(d);
-
-    pci_register_io_region((PCIDevice *)d, 4, 0x10, 
-                           PCI_ADDRESS_SPACE_IO, bmdma_map);
-
-    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
-              pic_set_irq_new, isa_pic, 14);
-    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
-              pic_set_irq_new, isa_pic, 15);
-    ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
-    ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
-
-    register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d);
-}
-
 /* hd_table must contain 4 block drivers */
 /* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic)
 {
     PCIIDEState *d;
     uint8_t *pci_conf;
-    
+
     /* register a function 1 of PIIX3 */
-    d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE", 
+    d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE",
                                            sizeof(PCIIDEState),
                                            devfn,
                                            NULL, NULL);
@@ -2654,13 +2965,49 @@
 
     piix3_reset(d);
 
-    pci_register_io_region((PCIDevice *)d, 4, 0x10, 
+    pci_register_io_region((PCIDevice *)d, 4, 0x10,
                            PCI_ADDRESS_SPACE_IO, bmdma_map);
 
-    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
-              pic_set_irq_new, isa_pic, 14);
-    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
-              pic_set_irq_new, isa_pic, 15);
+    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
+    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
+    ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
+    ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
+
+    register_savevm("ide", 0, 1, pci_ide_save, pci_ide_load, d);
+}
+
+/* hd_table must contain 4 block drivers */
+/* NOTE: for the PIIX4, the IRQs and IOports are hardcoded */
+void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic)
+{
+    PCIIDEState *d;
+    uint8_t *pci_conf;
+
+    /* register a function 1 of PIIX4 */
+    d = (PCIIDEState *)pci_register_device(bus, "PIIX4 IDE",
+                                           sizeof(PCIIDEState),
+                                           devfn,
+                                           NULL, NULL);
+    d->type = IDE_TYPE_PIIX4;
+
+    pci_conf = d->dev.config;
+    pci_conf[0x00] = 0x86; // Intel
+    pci_conf[0x01] = 0x80;
+    pci_conf[0x02] = 0x11;
+    pci_conf[0x03] = 0x71;
+    pci_conf[0x09] = 0x80; // legacy ATA mode
+    pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
+    pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
+    pci_conf[0x0e] = 0x00; // header_type
+
+    piix3_reset(d);
+
+    pci_register_io_region((PCIDevice *)d, 4, 0x10,
+                           PCI_ADDRESS_SPACE_IO, bmdma_map);
+
+    ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
+    ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
     ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
     ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
 
@@ -2674,7 +3021,7 @@
 static void pmac_ide_writeb (void *opaque,
                              target_phys_addr_t addr, uint32_t val)
 {
-    addr = (addr & 0xFFF) >> 4; 
+    addr = (addr & 0xFFF) >> 4;
     switch (addr) {
     case 1 ... 7:
         ide_ioport_write(opaque, addr, val);
@@ -2711,7 +3058,7 @@
 static void pmac_ide_writew (void *opaque,
                              target_phys_addr_t addr, uint32_t val)
 {
-    addr = (addr & 0xFFF) >> 4; 
+    addr = (addr & 0xFFF) >> 4;
 #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap16(val);
 #endif
@@ -2724,7 +3071,7 @@
 {
     uint16_t retval;
 
-    addr = (addr & 0xFFF) >> 4; 
+    addr = (addr & 0xFFF) >> 4;
     if (addr == 0) {
         retval = ide_data_readw(opaque, 0);
     } else {
@@ -2739,7 +3086,7 @@
 static void pmac_ide_writel (void *opaque,
                              target_phys_addr_t addr, uint32_t val)
 {
-    addr = (addr & 0xFFF) >> 4; 
+    addr = (addr & 0xFFF) >> 4;
 #ifdef TARGET_WORDS_BIGENDIAN
     val = bswap32(val);
 #endif
@@ -2752,7 +3099,7 @@
 {
     uint32_t retval;
 
-    addr = (addr & 0xFFF) >> 4; 
+    addr = (addr & 0xFFF) >> 4;
     if (addr == 0) {
         retval = ide_data_readl(opaque, 0);
     } else {
@@ -2779,17 +3126,559 @@
 /* hd_table must contain 4 block drivers */
 /* PowerMac uses memory mapped registers, not I/O. Return the memory
    I/O index to access the ide. */
-int pmac_ide_init (BlockDriverState **hd_table,
-                   SetIRQFunc *set_irq, void *irq_opaque, int irq)
+int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq)
 {
     IDEState *ide_if;
     int pmac_ide_memory;
 
     ide_if = qemu_mallocz(sizeof(IDEState) * 2);
-    ide_init2(&ide_if[0], hd_table[0], hd_table[1],
-              set_irq, irq_opaque, irq);
-    
+    ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq);
+
     pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
                                              pmac_ide_write, &ide_if[0]);
     return pmac_ide_memory;
 }
+
+/***********************************************************/
+/* CF-ATA Microdrive */
+
+#define METADATA_SIZE	0x20
+
+/* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface.  */
+struct md_s {
+    IDEState ide[2];
+    struct pcmcia_card_s card;
+    uint32_t attr_base;
+    uint32_t io_base;
+
+    /* Card state */
+    uint8_t opt;
+    uint8_t stat;
+    uint8_t pins;
+
+    uint8_t ctrl;
+    uint16_t io;
+    int cycle;
+};
+
+/* Register bitfields */
+enum md_opt {
+    OPT_MODE_MMAP	= 0,
+    OPT_MODE_IOMAP16	= 1,
+    OPT_MODE_IOMAP1	= 2,
+    OPT_MODE_IOMAP2	= 3,
+    OPT_MODE		= 0x3f,
+    OPT_LEVIREQ		= 0x40,
+    OPT_SRESET		= 0x80,
+};
+enum md_cstat {
+    STAT_INT		= 0x02,
+    STAT_PWRDWN		= 0x04,
+    STAT_XE		= 0x10,
+    STAT_IOIS8		= 0x20,
+    STAT_SIGCHG		= 0x40,
+    STAT_CHANGED	= 0x80,
+};
+enum md_pins {
+    PINS_MRDY		= 0x02,
+    PINS_CRDY		= 0x20,
+};
+enum md_ctrl {
+    CTRL_IEN		= 0x02,
+    CTRL_SRST		= 0x04,
+};
+
+static inline void md_interrupt_update(struct md_s *s)
+{
+    if (!s->card.slot)
+        return;
+
+    qemu_set_irq(s->card.slot->irq,
+                    !(s->stat & STAT_INT) &&	/* Inverted */
+                    !(s->ctrl & (CTRL_IEN | CTRL_SRST)) &&
+                    !(s->opt & OPT_SRESET));
+}
+
+static void md_set_irq(void *opaque, int irq, int level)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    if (level)
+        s->stat |= STAT_INT;
+    else
+        s->stat &= ~STAT_INT;
+
+    md_interrupt_update(s);
+}
+
+static void md_reset(struct md_s *s)
+{
+    s->opt = OPT_MODE_MMAP;
+    s->stat = 0;
+    s->pins = 0;
+    s->cycle = 0;
+    s->ctrl = 0;
+    ide_reset(s->ide);
+}
+
+static uint8_t md_attr_read(void *opaque, uint32_t at)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    if (at < s->attr_base) {
+        if (at < s->card.cis_len)
+            return s->card.cis[at];
+        else
+            return 0x00;
+    }
+
+    at -= s->attr_base;
+
+    switch (at) {
+    case 0x00:	/* Configuration Option Register */
+        return s->opt;
+    case 0x02:	/* Card Configuration Status Register */
+        if (s->ctrl & CTRL_IEN)
+            return s->stat & ~STAT_INT;
+        else
+            return s->stat;
+    case 0x04:	/* Pin Replacement Register */
+        return (s->pins & PINS_CRDY) | 0x0c;
+    case 0x06:	/* Socket and Copy Register */
+        return 0x00;
+#ifdef VERBOSE
+    default:
+        printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
+#endif
+    }
+
+    return 0;
+}
+
+static void md_attr_write(void *opaque, uint32_t at, uint8_t value)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    at -= s->attr_base;
+
+    switch (at) {
+    case 0x00:	/* Configuration Option Register */
+        s->opt = value & 0xcf;
+        if (value & OPT_SRESET)
+            md_reset(s);
+        md_interrupt_update(s);
+        break;
+    case 0x02:	/* Card Configuration Status Register */
+        if ((s->stat ^ value) & STAT_PWRDWN)
+            s->pins |= PINS_CRDY;
+        s->stat &= 0x82;
+        s->stat |= value & 0x74;
+        md_interrupt_update(s);
+        /* Word 170 in Identify Device must be equal to STAT_XE */
+        break;
+    case 0x04:	/* Pin Replacement Register */
+        s->pins &= PINS_CRDY;
+        s->pins |= value & PINS_MRDY;
+        break;
+    case 0x06:	/* Socket and Copy Register */
+        break;
+    default:
+        printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
+    }
+}
+
+static uint16_t md_common_read(void *opaque, uint32_t at)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    uint16_t ret;
+    at -= s->io_base;
+
+    switch (s->opt & OPT_MODE) {
+    case OPT_MODE_MMAP:
+        if ((at & ~0x3ff) == 0x400)
+            at = 0;
+        break;
+    case OPT_MODE_IOMAP16:
+        at &= 0xf;
+        break;
+    case OPT_MODE_IOMAP1:
+        if ((at & ~0xf) == 0x3f0)
+            at -= 0x3e8;
+        else if ((at & ~0xf) == 0x1f0)
+            at -= 0x1f0;
+        break;
+    case OPT_MODE_IOMAP2:
+        if ((at & ~0xf) == 0x370)
+            at -= 0x368;
+        else if ((at & ~0xf) == 0x170)
+            at -= 0x170;
+    }
+
+    switch (at) {
+    case 0x0:	/* Even RD Data */
+    case 0x8:
+        return ide_data_readw(s->ide, 0);
+
+        /* TODO: 8-bit accesses */
+        if (s->cycle)
+            ret = s->io >> 8;
+        else {
+            s->io = ide_data_readw(s->ide, 0);
+            ret = s->io & 0xff;
+        }
+        s->cycle = !s->cycle;
+        return ret;
+    case 0x9:	/* Odd RD Data */
+        return s->io >> 8;
+    case 0xd:	/* Error */
+        return ide_ioport_read(s->ide, 0x1);
+    case 0xe:	/* Alternate Status */
+        if (s->ide->cur_drive->bs)
+            return s->ide->cur_drive->status;
+        else
+            return 0;
+    case 0xf:	/* Device Address */
+        return 0xc2 | ((~s->ide->select << 2) & 0x3c);
+    default:
+        return ide_ioport_read(s->ide, at);
+    }
+
+    return 0;
+}
+
+static void md_common_write(void *opaque, uint32_t at, uint16_t value)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    at -= s->io_base;
+
+    switch (s->opt & OPT_MODE) {
+    case OPT_MODE_MMAP:
+        if ((at & ~0x3ff) == 0x400)
+            at = 0;
+        break;
+    case OPT_MODE_IOMAP16:
+        at &= 0xf;
+        break;
+    case OPT_MODE_IOMAP1:
+        if ((at & ~0xf) == 0x3f0)
+            at -= 0x3e8;
+        else if ((at & ~0xf) == 0x1f0)
+            at -= 0x1f0;
+        break;
+    case OPT_MODE_IOMAP2:
+        if ((at & ~0xf) == 0x370)
+            at -= 0x368;
+        else if ((at & ~0xf) == 0x170)
+            at -= 0x170;
+    }
+
+    switch (at) {
+    case 0x0:	/* Even WR Data */
+    case 0x8:
+        ide_data_writew(s->ide, 0, value);
+        break;
+
+        /* TODO: 8-bit accesses */
+        if (s->cycle)
+            ide_data_writew(s->ide, 0, s->io | (value << 8));
+        else
+            s->io = value & 0xff;
+        s->cycle = !s->cycle;
+        break;
+    case 0x9:
+        s->io = value & 0xff;
+        s->cycle = !s->cycle;
+        break;
+    case 0xd:	/* Features */
+        ide_ioport_write(s->ide, 0x1, value);
+        break;
+    case 0xe:	/* Device Control */
+        s->ctrl = value;
+        if (value & CTRL_SRST)
+            md_reset(s);
+        md_interrupt_update(s);
+        break;
+    default:
+        if (s->stat & STAT_PWRDWN) {
+            s->pins |= PINS_CRDY;
+            s->stat &= ~STAT_PWRDWN;
+        }
+        ide_ioport_write(s->ide, at, value);
+    }
+}
+
+static void md_save(QEMUFile *f, void *opaque)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    int i;
+    uint8_t drive1_selected;
+
+    qemu_put_8s(f, &s->opt);
+    qemu_put_8s(f, &s->stat);
+    qemu_put_8s(f, &s->pins);
+
+    qemu_put_8s(f, &s->ctrl);
+    qemu_put_be16s(f, &s->io);
+    qemu_put_byte(f, s->cycle);
+
+    drive1_selected = (s->ide->cur_drive != s->ide);
+    qemu_put_8s(f, &s->ide->cmd);
+    qemu_put_8s(f, &drive1_selected);
+
+    for (i = 0; i < 2; i ++)
+        ide_save(f, &s->ide[i]);
+}
+
+static int md_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct md_s *s = (struct md_s *) opaque;
+    int i;
+    uint8_t drive1_selected;
+
+    qemu_get_8s(f, &s->opt);
+    qemu_get_8s(f, &s->stat);
+    qemu_get_8s(f, &s->pins);
+
+    qemu_get_8s(f, &s->ctrl);
+    qemu_get_be16s(f, &s->io);
+    s->cycle = qemu_get_byte(f);
+
+    qemu_get_8s(f, &s->ide->cmd);
+    qemu_get_8s(f, &drive1_selected);
+    s->ide->cur_drive = &s->ide[(drive1_selected != 0)];
+
+    for (i = 0; i < 2; i ++)
+        ide_load(f, &s->ide[i]);
+
+    return 0;
+}
+
+static int md_iid = 0;
+
+static const uint8_t dscm1xxxx_cis[0x14a] = {
+    [0x000] = CISTPL_DEVICE,	/* 5V Device Information */
+    [0x002] = 0x03,		/* Tuple length = 4 bytes */
+    [0x004] = 0xdb,		/* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
+    [0x006] = 0x01,		/* Size = 2K bytes */
+    [0x008] = CISTPL_ENDMARK,
+
+    [0x00a] = CISTPL_DEVICE_OC,	/* Additional Device Information */
+    [0x00c] = 0x04,		/* Tuple length = 4 byest */
+    [0x00e] = 0x03,		/* Conditions: Ext = 0, Vcc 3.3V, MWAIT = 1 */
+    [0x010] = 0xdb,		/* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
+    [0x012] = 0x01,		/* Size = 2K bytes */
+    [0x014] = CISTPL_ENDMARK,
+
+    [0x016] = CISTPL_JEDEC_C,	/* JEDEC ID */
+    [0x018] = 0x02,		/* Tuple length = 2 bytes */
+    [0x01a] = 0xdf,		/* PC Card ATA with no Vpp required */
+    [0x01c] = 0x01,
+
+    [0x01e] = CISTPL_MANFID,	/* Manufacture ID */
+    [0x020] = 0x04,		/* Tuple length = 4 bytes */
+    [0x022] = 0xa4,		/* TPLMID_MANF = 00a4 (IBM) */
+    [0x024] = 0x00,
+    [0x026] = 0x00,		/* PLMID_CARD = 0000 */
+    [0x028] = 0x00,
+
+    [0x02a] = CISTPL_VERS_1,	/* Level 1 Version */
+    [0x02c] = 0x12,		/* Tuple length = 23 bytes */
+    [0x02e] = 0x04,		/* Major Version = JEIDA 4.2 / PCMCIA 2.1 */
+    [0x030] = 0x01,		/* Minor Version = 1 */
+    [0x032] = 'I',
+    [0x034] = 'B',
+    [0x036] = 'M',
+    [0x038] = 0x00,
+    [0x03a] = 'm',
+    [0x03c] = 'i',
+    [0x03e] = 'c',
+    [0x040] = 'r',
+    [0x042] = 'o',
+    [0x044] = 'd',
+    [0x046] = 'r',
+    [0x048] = 'i',
+    [0x04a] = 'v',
+    [0x04c] = 'e',
+    [0x04e] = 0x00,
+    [0x050] = CISTPL_ENDMARK,
+
+    [0x052] = CISTPL_FUNCID,	/* Function ID */
+    [0x054] = 0x02,		/* Tuple length = 2 bytes */
+    [0x056] = 0x04,		/* TPLFID_FUNCTION = Fixed Disk */
+    [0x058] = 0x01,		/* TPLFID_SYSINIT: POST = 1, ROM = 0 */
+
+    [0x05a] = CISTPL_FUNCE,	/* Function Extension */
+    [0x05c] = 0x02,		/* Tuple length = 2 bytes */
+    [0x05e] = 0x01,		/* TPLFE_TYPE = Disk Device Interface */
+    [0x060] = 0x01,		/* TPLFE_DATA = PC Card ATA Interface */
+
+    [0x062] = CISTPL_FUNCE,	/* Function Extension */
+    [0x064] = 0x03,		/* Tuple length = 3 bytes */
+    [0x066] = 0x02,		/* TPLFE_TYPE = Basic PC Card ATA Interface */
+    [0x068] = 0x08,		/* TPLFE_DATA: Rotating, Unique, Single */
+    [0x06a] = 0x0f,		/* TPLFE_DATA: Sleep, Standby, Idle, Auto */
+
+    [0x06c] = CISTPL_CONFIG,	/* Configuration */
+    [0x06e] = 0x05,		/* Tuple length = 5 bytes */
+    [0x070] = 0x01,		/* TPCC_RASZ = 2 bytes, TPCC_RMSZ = 1 byte */
+    [0x072] = 0x07,		/* TPCC_LAST = 7 */
+    [0x074] = 0x00,		/* TPCC_RADR = 0200 */
+    [0x076] = 0x02,
+    [0x078] = 0x0f,		/* TPCC_RMSK = 200, 202, 204, 206 */
+
+    [0x07a] = CISTPL_CFTABLE_ENTRY,	/* 16-bit PC Card Configuration */
+    [0x07c] = 0x0b,		/* Tuple length = 11 bytes */
+    [0x07e] = 0xc0,		/* TPCE_INDX = Memory Mode, Default, Iface */
+    [0x080] = 0xc0,		/* TPCE_IF = Memory, no BVDs, no WP, READY */
+    [0x082] = 0xa1,		/* TPCE_FS = Vcc only, no I/O, Memory, Misc */
+    [0x084] = 0x27,		/* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+    [0x086] = 0x55,		/* NomV: 5.0 V */
+    [0x088] = 0x4d,		/* MinV: 4.5 V */
+    [0x08a] = 0x5d,		/* MaxV: 5.5 V */
+    [0x08c] = 0x4e,		/* Peakl: 450 mA */
+    [0x08e] = 0x08,		/* TPCE_MS = 1 window, 1 byte, Host address */
+    [0x090] = 0x00,		/* Window descriptor: Window length = 0 */
+    [0x092] = 0x20,		/* TPCE_MI: support power down mode, RW */
+
+    [0x094] = CISTPL_CFTABLE_ENTRY,	/* 16-bit PC Card Configuration */
+    [0x096] = 0x06,		/* Tuple length = 6 bytes */
+    [0x098] = 0x00,		/* TPCE_INDX = Memory Mode, no Default */
+    [0x09a] = 0x01,		/* TPCE_FS = Vcc only, no I/O, no Memory */
+    [0x09c] = 0x21,		/* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+    [0x09e] = 0xb5,		/* NomV: 3.3 V */
+    [0x0a0] = 0x1e,
+    [0x0a2] = 0x3e,		/* Peakl: 350 mA */
+
+    [0x0a4] = CISTPL_CFTABLE_ENTRY,	/* 16-bit PC Card Configuration */
+    [0x0a6] = 0x0d,		/* Tuple length = 13 bytes */
+    [0x0a8] = 0xc1,		/* TPCE_INDX = I/O and Memory Mode, Default */
+    [0x0aa] = 0x41,		/* TPCE_IF = I/O and Memory, no BVD, no WP */
+    [0x0ac] = 0x99,		/* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+    [0x0ae] = 0x27,		/* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+    [0x0b0] = 0x55,		/* NomV: 5.0 V */
+    [0x0b2] = 0x4d,		/* MinV: 4.5 V */
+    [0x0b4] = 0x5d,		/* MaxV: 5.5 V */
+    [0x0b6] = 0x4e,		/* Peakl: 450 mA */
+    [0x0b8] = 0x64,		/* TPCE_IO = 16-byte boundary, 16/8 accesses */
+    [0x0ba] = 0xf0,		/* TPCE_IR =  MASK, Level, Pulse, Share */
+    [0x0bc] = 0xff,		/* IRQ0..IRQ7 supported */
+    [0x0be] = 0xff,		/* IRQ8..IRQ15 supported */
+    [0x0c0] = 0x20,		/* TPCE_MI = support power down mode */
+
+    [0x0c2] = CISTPL_CFTABLE_ENTRY,	/* 16-bit PC Card Configuration */
+    [0x0c4] = 0x06,		/* Tuple length = 6 bytes */
+    [0x0c6] = 0x01,		/* TPCE_INDX = I/O and Memory Mode */
+    [0x0c8] = 0x01,		/* TPCE_FS = Vcc only, no I/O, no Memory */
+    [0x0ca] = 0x21,		/* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+    [0x0cc] = 0xb5,		/* NomV: 3.3 V */
+    [0x0ce] = 0x1e,
+    [0x0d0] = 0x3e,		/* Peakl: 350 mA */
+
+    [0x0d2] = CISTPL_CFTABLE_ENTRY,	/* 16-bit PC Card Configuration */
+    [0x0d4] = 0x12,		/* Tuple length = 18 bytes */
+    [0x0d6] = 0xc2,		/* TPCE_INDX = I/O Primary Mode */
+    [0x0d8] = 0x41,		/* TPCE_IF = I/O and Memory, no BVD, no WP */
+    [0x0da] = 0x99,		/* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+    [0x0dc] = 0x27,		/* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+    [0x0de] = 0x55,		/* NomV: 5.0 V */
+    [0x0e0] = 0x4d,		/* MinV: 4.5 V */
+    [0x0e2] = 0x5d,		/* MaxV: 5.5 V */
+    [0x0e4] = 0x4e,		/* Peakl: 450 mA */
+    [0x0e6] = 0xea,		/* TPCE_IO = 1K boundary, 16/8 access, Range */
+    [0x0e8] = 0x61,		/* Range: 2 fields, 2 bytes addr, 1 byte len */
+    [0x0ea] = 0xf0,		/* Field 1 address = 0x01f0 */
+    [0x0ec] = 0x01,
+    [0x0ee] = 0x07,		/* Address block length = 8 */
+    [0x0f0] = 0xf6,		/* Field 2 address = 0x03f6 */
+    [0x0f2] = 0x03,
+    [0x0f4] = 0x01,		/* Address block length = 2 */
+    [0x0f6] = 0xee,		/* TPCE_IR = IRQ E, Level, Pulse, Share */
+    [0x0f8] = 0x20,		/* TPCE_MI = support power down mode */
+
+    [0x0fa] = CISTPL_CFTABLE_ENTRY,	/* 16-bit PC Card Configuration */
+    [0x0fc] = 0x06,		/* Tuple length = 6 bytes */
+    [0x0fe] = 0x02,		/* TPCE_INDX = I/O Primary Mode, no Default */
+    [0x100] = 0x01,		/* TPCE_FS = Vcc only, no I/O, no Memory */
+    [0x102] = 0x21,		/* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+    [0x104] = 0xb5,		/* NomV: 3.3 V */
+    [0x106] = 0x1e,
+    [0x108] = 0x3e,		/* Peakl: 350 mA */
+
+    [0x10a] = CISTPL_CFTABLE_ENTRY,	/* 16-bit PC Card Configuration */
+    [0x10c] = 0x12,		/* Tuple length = 18 bytes */
+    [0x10e] = 0xc3,		/* TPCE_INDX = I/O Secondary Mode, Default */
+    [0x110] = 0x41,		/* TPCE_IF = I/O and Memory, no BVD, no WP */
+    [0x112] = 0x99,		/* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+    [0x114] = 0x27,		/* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+    [0x116] = 0x55,		/* NomV: 5.0 V */
+    [0x118] = 0x4d,		/* MinV: 4.5 V */
+    [0x11a] = 0x5d,		/* MaxV: 5.5 V */
+    [0x11c] = 0x4e,		/* Peakl: 450 mA */
+    [0x11e] = 0xea,		/* TPCE_IO = 1K boundary, 16/8 access, Range */
+    [0x120] = 0x61,		/* Range: 2 fields, 2 byte addr, 1 byte len */
+    [0x122] = 0x70,		/* Field 1 address = 0x0170 */
+    [0x124] = 0x01,
+    [0x126] = 0x07,		/* Address block length = 8 */
+    [0x128] = 0x76,		/* Field 2 address = 0x0376 */
+    [0x12a] = 0x03,
+    [0x12c] = 0x01,		/* Address block length = 2 */
+    [0x12e] = 0xee,		/* TPCE_IR = IRQ E, Level, Pulse, Share */
+    [0x130] = 0x20,		/* TPCE_MI = support power down mode */
+
+    [0x132] = CISTPL_CFTABLE_ENTRY,	/* 16-bit PC Card Configuration */
+    [0x134] = 0x06,		/* Tuple length = 6 bytes */
+    [0x136] = 0x03,		/* TPCE_INDX = I/O Secondary Mode */
+    [0x138] = 0x01,		/* TPCE_FS = Vcc only, no I/O, no Memory */
+    [0x13a] = 0x21,		/* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+    [0x13c] = 0xb5,		/* NomV: 3.3 V */
+    [0x13e] = 0x1e,
+    [0x140] = 0x3e,		/* Peakl: 350 mA */
+
+    [0x142] = CISTPL_NO_LINK,	/* No Link */
+    [0x144] = 0x00,		/* Tuple length = 0 bytes */
+
+    [0x146] = CISTPL_END,	/* Tuple End */
+};
+
+static int dscm1xxxx_attach(void *opaque)
+{
+    struct md_s *md = (struct md_s *) opaque;
+    md->card.attr_read = md_attr_read;
+    md->card.attr_write = md_attr_write;
+    md->card.common_read = md_common_read;
+    md->card.common_write = md_common_write;
+    md->card.io_read = md_common_read;
+    md->card.io_write = md_common_write;
+
+    md->attr_base = md->card.cis[0x74] | (md->card.cis[0x76] << 8);
+    md->io_base = 0x0;
+
+    md_reset(md);
+    md_interrupt_update(md);
+
+    md->card.slot->card_string = "DSCM-1xxxx Hitachi Microdrive";
+    return 0;
+}
+
+static int dscm1xxxx_detach(void *opaque)
+{
+    struct md_s *md = (struct md_s *) opaque;
+    md_reset(md);
+    return 0;
+}
+
+struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv)
+{
+    struct md_s *md = (struct md_s *) qemu_mallocz(sizeof(struct md_s));
+    md->card.state = md;
+    md->card.attach = dscm1xxxx_attach;
+    md->card.detach = dscm1xxxx_detach;
+    md->card.cis = dscm1xxxx_cis;
+    md->card.cis_len = sizeof(dscm1xxxx_cis);
+
+    ide_init2(md->ide, bdrv, 0, qemu_allocate_irqs(md_set_irq, md, 1)[0]);
+    md->ide->is_cf = 1;
+    md->ide->mdata_size = METADATA_SIZE;
+    md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
+
+    register_savevm("microdrive", md_iid ++, 0, md_save, md_load, md);
+
+    return &md->card;
+}
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
index 4e5f4ac..83c6208 100644
--- a/hw/integratorcp.c
+++ b/hw/integratorcp.c
@@ -1,7 +1,7 @@
-/* 
+/*
  * ARM Integrator CP System emulation.
  *
- * Copyright (c) 2005-2006 CodeSourcery.
+ * Copyright (c) 2005-2007 CodeSourcery.
  * Written by Paul Brook
  *
  * This code is licenced under the GPL
@@ -257,7 +257,7 @@
 
     iomemtype = cpu_register_io_memory(0, integratorcm_readfn,
                                        integratorcm_writefn, s);
-    cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype);
+    cpu_register_physical_memory(0x10000000, 0x00800000, iomemtype);
     integratorcm_do_remap(s, 1);
     /* ??? Save/restore.  */
 }
@@ -267,28 +267,22 @@
 
 typedef struct icp_pic_state
 {
-  arm_pic_handler handler;
   uint32_t base;
   uint32_t level;
   uint32_t irq_enabled;
   uint32_t fiq_enabled;
-  void *parent;
-  int parent_irq;
-  int parent_fiq;
+  qemu_irq parent_irq;
+  qemu_irq parent_fiq;
 } icp_pic_state;
 
 static void icp_pic_update(icp_pic_state *s)
 {
     uint32_t flags;
 
-    if (s->parent_irq != -1) {
-        flags = (s->level & s->irq_enabled);
-        pic_set_irq_new(s->parent, s->parent_irq, flags != 0);
-    }
-    if (s->parent_fiq != -1) {
-        flags = (s->level & s->fiq_enabled);
-        pic_set_irq_new(s->parent, s->parent_fiq, flags != 0);
-    }
+    flags = (s->level & s->irq_enabled);
+    qemu_set_irq(s->parent_irq, flags != 0);
+    flags = (s->level & s->fiq_enabled);
+    qemu_set_irq(s->parent_fiq, flags != 0);
 }
 
 static void icp_pic_set_irq(void *opaque, int irq, int level)
@@ -345,11 +339,11 @@
         break;
     case 4: /* INT_SOFTSET */
         if (value & 1)
-            pic_set_irq_new(s, 0, 1);
+            icp_pic_set_irq(s, 0, 1);
         break;
     case 5: /* INT_SOFTCLR */
         if (value & 1)
-            pic_set_irq_new(s, 0, 0);
+            icp_pic_set_irq(s, 0, 0);
         break;
     case 10: /* FRQ_ENABLESET */
         s->fiq_enabled |= value;
@@ -380,25 +374,25 @@
    icp_pic_write
 };
 
-static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
-                                   int parent_irq, int parent_fiq)
+static qemu_irq *icp_pic_init(uint32_t base,
+                              qemu_irq parent_irq, qemu_irq parent_fiq)
 {
     icp_pic_state *s;
     int iomemtype;
+    qemu_irq *qi;
 
     s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
     if (!s)
         return NULL;
-    s->handler = icp_pic_set_irq;
+    qi = qemu_allocate_irqs(icp_pic_set_irq, s, 32);
     s->base = base;
-    s->parent = parent;
     s->parent_irq = parent_irq;
     s->parent_fiq = parent_fiq;
     iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
                                        icp_pic_writefn, s);
-    cpu_register_physical_memory(base, 0x007fffff, iomemtype);
+    cpu_register_physical_memory(base, 0x00800000, iomemtype);
     /* ??? Save/restore.  */
-    return s;
+    return qi;
 }
 
 /* CP control registers.  */
@@ -460,7 +454,7 @@
     s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state));
     iomemtype = cpu_register_io_memory(0, icp_control_readfn,
                                        icp_control_writefn, s);
-    cpu_register_physical_memory(base, 0x007fffff, iomemtype);
+    cpu_register_physical_memory(base, 0x00800000, iomemtype);
     s->base = base;
     /* ??? Save/restore.  */
 }
@@ -471,15 +465,17 @@
 static void integratorcp_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, uint32_t cpuid)
+                     const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
     uint32_t bios_offset;
-    icp_pic_state *pic;
-    void *cpu_pic;
+    qemu_irq *pic;
+    qemu_irq *cpu_pic;
 
     env = cpu_init();
-    cpu_arm_set_model(env, cpuid);
+    if (!cpu_model)
+        cpu_model = "arm926";
+    cpu_arm_set_model(env, cpu_model);
     bios_offset = ram_size + vga_ram_size;
     /* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash.  */
     /* ??? RAM shoud repeat to fill physical memory space.  */
@@ -490,57 +486,37 @@
 
     integratorcm_init(ram_size >> 20, bios_offset);
     cpu_pic = arm_pic_init_cpu(env);
-    pic = icp_pic_init(0x14000000, cpu_pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
-    icp_pic_init(0xca000000, pic, 26, -1);
+    pic = icp_pic_init(0x14000000, cpu_pic[ARM_PIC_CPU_IRQ],
+                       cpu_pic[ARM_PIC_CPU_FIQ]);
+    icp_pic_init(0xca000000, pic[26], NULL);
     icp_pit_init(0x13000000, pic, 5);
-    pl011_init(0x16000000, pic, 1, serial_hds[0]);
-    pl011_init(0x17000000, pic, 2, serial_hds[1]);
+    pl031_init(0x15000000, pic[8]);
+    pl011_init(0x16000000, pic[1], serial_hds[0]);
+    pl011_init(0x17000000, pic[2], serial_hds[1]);
     icp_control_init(0xcb000000);
-    pl050_init(0x18000000, pic, 3, 0);
-    pl050_init(0x19000000, pic, 4, 1);
+    pl050_init(0x18000000, pic[3], 0);
+    pl050_init(0x19000000, pic[4], 1);
+    pl181_init(0x1c000000, sd_bdrv, pic[23], pic[24]);
     if (nd_table[0].vlan) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "smc91c111") == 0) {
-            smc91c111_init(&nd_table[0], 0xc8000000, pic, 27);
+            smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
+        } else if (strcmp(nd_table[0].model, "?") == 0) {
+            fprintf(stderr, "qemu: Supported NICs: smc91c111\n");
+            exit (1);
         } else {
             fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
             exit (1);
         }
     }
-    pl110_init(ds, 0xc0000000, pic, 22, 0);
+    pl110_init(ds, 0xc0000000, pic[22], 0);
 
     arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
-                    initrd_filename, 0x113);
+                    initrd_filename, 0x113, 0x0);
 }
 
-static void integratorcp926_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)
-{
-    integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
-                      snapshot, kernel_filename, kernel_cmdline,
-                      initrd_filename, ARM_CPUID_ARM926);
-}
-
-static void integratorcp1026_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)
-{
-    integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
-                      snapshot, kernel_filename, kernel_cmdline,
-                      initrd_filename, ARM_CPUID_ARM1026);
-}
-
-QEMUMachine integratorcp926_machine = {
-    "integratorcp926",
+QEMUMachine integratorcp_machine = {
+    "integratorcp",
     "ARM Integrator/CP (ARM926EJ-S)",
-    integratorcp926_init,
-};
-
-QEMUMachine integratorcp1026_machine = {
-    "integratorcp1026",
-    "ARM Integrator/CP (ARM1026EJ-S)",
-    integratorcp1026_init,
+    integratorcp_init,
 };
diff --git a/hw/iommu.c b/hw/iommu.c
index 5c2768c..0ee8c71 100644
--- a/hw/iommu.c
+++ b/hw/iommu.c
@@ -2,7 +2,7 @@
  * QEMU SPARC iommu emulation
  *
  * Copyright (c) 2003-2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -59,6 +59,20 @@
 #define IOMMU_PGFLUSH       (0x0018 >> 2)
 #define IOMMU_PGFLUSH_MASK  0xffffffff
 
+#define IOMMU_AFSR          (0x1000 >> 2)
+#define IOMMU_AFSR_ERR      0x80000000 /* LE, TO, or BE asserted */
+#define IOMMU_AFSR_LE       0x40000000 /* SBUS reports error after transaction */
+#define IOMMU_AFSR_TO       0x20000000 /* Write access took more than 12.8 us. */
+#define IOMMU_AFSR_BE       0x10000000 /* Write access received error acknowledge */
+#define IOMMU_AFSR_SIZE     0x0e000000 /* Size of transaction causing error */
+#define IOMMU_AFSR_S        0x01000000 /* Sparc was in supervisor mode */
+#define IOMMU_AFSR_RESV     0x00f00000 /* Reserved, forced to 0x8 by hardware */
+#define IOMMU_AFSR_ME       0x00080000 /* Multiple errors occurred */
+#define IOMMU_AFSR_RD       0x00040000 /* A read operation was in progress */
+#define IOMMU_AFSR_FAV      0x00020000 /* IOMMU afar has valid contents */
+
+#define IOMMU_AFAR          (0x1004 >> 2)
+
 #define IOMMU_SBCFG0        (0x1010 >> 2) /* SBUS configration per-slot */
 #define IOMMU_SBCFG1        (0x1014 >> 2) /* SBUS configration per-slot */
 #define IOMMU_SBCFG2        (0x1018 >> 2) /* SBUS configration per-slot */
@@ -87,20 +101,20 @@
 #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) {
     default:
-	DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]);
+	DPRINTF("read reg[%d] = %x\n", (int)saddr, s->regs[saddr]);
 	return s->regs[saddr];
 	break;
     }
@@ -110,40 +124,40 @@
 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);
+    DPRINTF("write reg[%d] = %x\n", (int)saddr, val);
     switch (saddr) {
     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 = " TARGET_FMT_plx "\n", s->iostart);
 	s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION);
 	break;
     case IOMMU_BASE:
@@ -186,31 +200,56 @@
     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;
+    uint32_t ret;
+    target_phys_addr_t iopte;
+#ifdef DEBUG_IOMMU
+    target_phys_addr_t pa = addr;
+#endif
 
-    iopte = s->regs[1] << 4;
+    iopte = s->regs[IOMMU_BASE] << 4;
     addr &= ~s->iostart;
     iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
-    return ldl_phys(iopte);
+    cpu_physical_memory_read(iopte, (uint8_t *)&ret, 4);
+    tswap32s(&ret);
+    DPRINTF("get flags addr " TARGET_FMT_plx " => pte " TARGET_FMT_plx
+            ", *pte = %x\n", pa, iopte, ret);
+
+    return ret;
 }
 
-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;
 }
 
+static void iommu_bad_addr(IOMMUState *s, target_phys_addr_t addr, int is_write)
+{
+    DPRINTF("bad addr " TARGET_FMT_plx "\n", addr);
+    s->regs[IOMMU_AFSR] = IOMMU_AFSR_ERR | IOMMU_AFSR_LE | (8 << 20) |
+        IOMMU_AFSR_FAV;
+    if (!is_write)
+        s->regs[IOMMU_AFSR] |= IOMMU_AFSR_RD;
+    s->regs[IOMMU_AFAR] = addr;
+}
+
 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;
@@ -218,12 +257,16 @@
         if (l > len)
             l = len;
         flags = iommu_page_get_flags(opaque, page);
-        if (!(flags & IOPTE_VALID))
+        if (!(flags & IOPTE_VALID)) {
+            iommu_bad_addr(opaque, page, is_write);
             return;
+        }
         phys_addr = iommu_translate_pa(opaque, addr, flags);
         if (is_write) {
-            if (!(flags & IOPTE_WRITE))
+            if (!(flags & IOPTE_WRITE)) {
+                iommu_bad_addr(opaque, page, is_write);
                 return;
+            }
             cpu_physical_memory_write(phys_addr, buf, len);
         } else {
             cpu_physical_memory_read(phys_addr, buf, len);
@@ -238,25 +281,23 @@
 {
     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)
 {
     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_be32s(f, &s->regs[i]);
+    qemu_get_be64s(f, &s->iostart);
 
     return 0;
 }
@@ -267,10 +308,10 @@
 
     memset(s->regs, 0, IOMMU_NREGS * 4);
     s->iostart = 0;
-    s->regs[0] = IOMMU_VERSION;
+    s->regs[IOMMU_CTRL] = IOMMU_VERSION;
 }
 
-void *iommu_init(uint32_t addr)
+void *iommu_init(target_phys_addr_t addr)
 {
     IOMMUState *s;
     int iommu_io_memory;
@@ -283,8 +324,8 @@
 
     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;
 }
diff --git a/hw/irq.c b/hw/irq.c
new file mode 100644
index 0000000..e46ee60
--- /dev/null
+++ b/hw/irq.c
@@ -0,0 +1,57 @@
+/*
+ * QEMU IRQ/GPIO common code.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+struct IRQState {
+    qemu_irq_handler handler;
+    void *opaque;
+    int n;
+};
+
+void qemu_set_irq(qemu_irq irq, int level)
+{
+    if (!irq)
+        return;
+
+    irq->handler(irq->opaque, irq->n, level);
+}
+
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
+{
+    qemu_irq *s;
+    struct IRQState *p;
+    int i;
+
+    s = (qemu_irq *)qemu_mallocz(sizeof(qemu_irq) * n);
+    p = (struct IRQState *)qemu_mallocz(sizeof(struct IRQState) * n);
+    for (i = 0; i < n; i++) {
+        p->handler = handler;
+        p->opaque = opaque;
+        p->n = i;
+        s[i] = p;
+        p++;
+    }
+    return s;
+}
+
diff --git a/hw/irq.h b/hw/irq.h
new file mode 100644
index 0000000..652fd6a
--- /dev/null
+++ b/hw/irq.h
@@ -0,0 +1,21 @@
+/* Generic IRQ/GPIO pin infrastructure.  */
+
+typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
+
+typedef struct IRQState *qemu_irq;
+
+void qemu_set_irq(qemu_irq irq, int level);
+
+static inline void qemu_irq_raise(qemu_irq irq)
+{
+    qemu_set_irq(irq, 1);
+}
+
+static inline void qemu_irq_lower(qemu_irq irq)
+{
+    qemu_set_irq(irq, 0);
+}
+
+/* Returns an array of N IRQs.  */
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+
diff --git a/hw/isa_mmio.c b/hw/isa_mmio.c
index 070f6f5..4e7914e 100644
--- a/hw/isa_mmio.c
+++ b/hw/isa_mmio.c
@@ -2,7 +2,7 @@
  * Memory mapped access to ISA IO space.
  *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
diff --git a/hw/jazz_led.c b/hw/jazz_led.c
new file mode 100644
index 0000000..1c7c176
--- /dev/null
+++ b/hw/jazz_led.c
@@ -0,0 +1,303 @@
+/*
+ * QEMU JAZZ LED emulator.
+ *
+ * Copyright (c) 2007 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+#include "pixel_ops.h"
+
+//#define DEBUG_LED
+
+typedef enum {
+    REDRAW_NONE = 0, REDRAW_SEGMENTS = 1, REDRAW_BACKGROUND = 2,
+} screen_state_t;
+
+typedef struct LedState {
+    target_phys_addr_t base;
+    uint8_t segments;
+    DisplayState *ds;
+    screen_state_t state;
+} LedState;
+
+static uint32_t led_readb(void *opaque, target_phys_addr_t addr)
+{
+    LedState *s = opaque;
+    int relative_addr = addr - s->base;
+    uint32_t val;
+
+    switch (relative_addr) {
+        case 0:
+            val = s->segments;
+            break;
+        default:
+#ifdef DEBUG_LED
+            printf("jazz led: invalid read [0x%x]\n", relative_addr);
+#endif
+            val = 0;
+    }
+
+    return val;
+}
+
+static uint32_t led_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+#ifdef TARGET_WORDS_BIGENDIAN
+    v = led_readb(opaque, addr) << 8;
+    v |= led_readb(opaque, addr + 1);
+#else
+    v = led_readb(opaque, addr);
+    v |= led_readb(opaque, addr + 1) << 8;
+#endif
+    return v;
+}
+
+static uint32_t led_readl(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t v;
+#ifdef TARGET_WORDS_BIGENDIAN
+    v = led_readb(opaque, addr) << 24;
+    v |= led_readb(opaque, addr + 1) << 16;
+    v |= led_readb(opaque, addr + 2) << 8;
+    v |= led_readb(opaque, addr + 3);
+#else
+    v = led_readb(opaque, addr);
+    v |= led_readb(opaque, addr + 1) << 8;
+    v |= led_readb(opaque, addr + 2) << 16;
+    v |= led_readb(opaque, addr + 3) << 24;
+#endif
+    return v;
+}
+
+static void led_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    LedState *s = opaque;
+    int relative_addr = addr - s->base;
+
+    switch (relative_addr) {
+        case 0:
+            s->segments = val;
+            s->state |= REDRAW_SEGMENTS;
+            break;
+        default:
+#ifdef DEBUG_LED
+            printf("jazz led: invalid write of 0x%02x at [0x%x]\n", val, relative_addr);
+#endif
+            break;
+    }
+}
+
+static void led_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    led_writeb(opaque, addr, (val >> 8) & 0xff);
+    led_writeb(opaque, addr + 1, val & 0xff);
+#else
+    led_writeb(opaque, addr, val & 0xff);
+    led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+#endif
+}
+
+static void led_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+    led_writeb(opaque, addr, (val >> 24) & 0xff);
+    led_writeb(opaque, addr + 1, (val >> 16) & 0xff);
+    led_writeb(opaque, addr + 2, (val >> 8) & 0xff);
+    led_writeb(opaque, addr + 3, val & 0xff);
+#else
+    led_writeb(opaque, addr, val & 0xff);
+    led_writeb(opaque, addr + 1, (val >> 8) & 0xff);
+    led_writeb(opaque, addr + 2, (val >> 16) & 0xff);
+    led_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+#endif
+}
+
+static CPUReadMemoryFunc *led_read[3] = {
+    led_readb,
+    led_readw,
+    led_readl,
+};
+
+static CPUWriteMemoryFunc *led_write[3] = {
+    led_writeb,
+    led_writew,
+    led_writel,
+};
+
+/***********************************************************/
+/* jazz_led display */
+
+static void draw_horizontal_line(DisplayState *ds, int posy, int posx1, int posx2, uint32_t color)
+{
+    uint8_t *d;
+    int x, bpp;
+
+    bpp = (ds->depth + 7) >> 3;
+    d = ds->data + ds->linesize * posy + bpp * posx1;
+    switch(bpp) {
+        case 1:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint8_t *)d) = color;
+                d++;
+            }
+            break;
+        case 2:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint16_t *)d) = color;
+                d += 2;
+            }
+            break;
+        case 4:
+            for (x = posx1; x <= posx2; x++) {
+                *((uint32_t *)d) = color;
+                d += 4;
+            }
+            break;
+    }
+}
+
+static void draw_vertical_line(DisplayState *ds, int posx, int posy1, int posy2, uint32_t color)
+{
+    uint8_t *d;
+    int y, bpp;
+
+    bpp = (ds->depth + 7) >> 3;
+    d = ds->data + ds->linesize * posy1 + bpp * posx;
+    switch(bpp) {
+        case 1:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint8_t *)d) = color;
+                d += ds->linesize;
+            }
+            break;
+        case 2:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint16_t *)d) = color;
+                d += ds->linesize;
+            }
+            break;
+        case 4:
+            for (y = posy1; y <= posy2; y++) {
+                *((uint32_t *)d) = color;
+                d += ds->linesize;
+            }
+            break;
+    }
+}
+
+static void jazz_led_update_display(void *opaque)
+{
+    LedState *s = opaque;
+    DisplayState *ds = s->ds;
+    uint8_t *d1;
+    uint32_t color_segment, color_led;
+    int y, bpp;
+
+    if (s->state & REDRAW_BACKGROUND) {
+        /* clear screen */
+        bpp = (ds->depth + 7) >> 3;
+        d1 = ds->data;
+        for (y = 0; y < ds->height; y++) {
+            memset(d1, 0x00, ds->width * bpp);
+            d1 += ds->linesize;
+        }
+    }
+
+    if (s->state & REDRAW_SEGMENTS) {
+        /* set colors according to bpp */
+        switch (ds->depth) {
+            case 8:
+                color_segment = rgb_to_pixel8(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel8(0x00, 0xff, 0x00);
+                break;
+            case 15:
+                color_segment = rgb_to_pixel15(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel15(0x00, 0xff, 0x00);
+                break;
+            case 16:
+                color_segment = rgb_to_pixel16(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel16(0x00, 0xff, 0x00);
+            case 24:
+                color_segment = rgb_to_pixel24(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel24(0x00, 0xff, 0x00);
+                break;
+            case 32:
+                color_segment = rgb_to_pixel32(0xaa, 0xaa, 0xaa);
+                color_led = rgb_to_pixel32(0x00, 0xff, 0x00);
+                break;
+            default:
+                return;
+        }
+
+        /* display segments */
+        draw_horizontal_line(ds, 40, 10, 40, (s->segments & 0x02) ? color_segment : 0);
+        draw_vertical_line(ds, 10, 10, 40, (s->segments & 0x04) ? color_segment : 0);
+        draw_vertical_line(ds, 10, 40, 70, (s->segments & 0x08) ? color_segment : 0);
+        draw_horizontal_line(ds, 70, 10, 40, (s->segments & 0x10) ? color_segment : 0);
+        draw_vertical_line(ds, 40, 40, 70, (s->segments & 0x20) ? color_segment : 0);
+        draw_vertical_line(ds, 40, 10, 40, (s->segments & 0x40) ? color_segment : 0);
+        draw_horizontal_line(ds, 10, 10, 40, (s->segments & 0x80) ? color_segment : 0);
+
+        /* display led */
+        if (!(s->segments & 0x01))
+            color_led = 0; /* black */
+        draw_horizontal_line(ds, 68, 50, 50, color_led);
+        draw_horizontal_line(ds, 69, 49, 51, color_led);
+        draw_horizontal_line(ds, 70, 48, 52, color_led);
+        draw_horizontal_line(ds, 71, 49, 51, color_led);
+        draw_horizontal_line(ds, 72, 50, 50, color_led);
+    }
+
+    s->state = REDRAW_NONE;
+    dpy_update(ds, 0, 0, ds->width, ds->height);
+}
+
+static void jazz_led_invalidate_display(void *opaque)
+{
+    LedState *s = opaque;
+    s->state |= REDRAW_SEGMENTS | REDRAW_BACKGROUND;
+}
+
+static void jazz_led_screen_dump(void *opaque, const char *filename)
+{
+    printf("jazz_led_screen_dump() not implemented\n");
+}
+
+void jazz_led_init(DisplayState *ds, target_phys_addr_t base)
+{
+    LedState *s;
+    int io;
+
+    s = qemu_mallocz(sizeof(LedState));
+    if (!s)
+        return;
+
+    s->base = base;
+    s->ds = ds;
+    s->state = REDRAW_SEGMENTS | REDRAW_BACKGROUND;
+
+    io = cpu_register_io_memory(0, led_read, led_write, s);
+    cpu_register_physical_memory(s->base, 1, io);
+
+    graphic_console_init(ds, jazz_led_update_display, jazz_led_invalidate_display, jazz_led_screen_dump, s);
+}
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index 41c1ff2..e9866ba 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * QEMU LSI53C895A SCSI Host Bus Adapter emulation
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -251,7 +251,7 @@
     uint32_t ia;
     uint32_t sbc;
     uint32_t csbc;
-    uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */
+    uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
 
     /* Script ram is stored as 32-bit words in host byteorder.  */
     uint32_t script_ram[2048];
@@ -374,7 +374,7 @@
                 level, s->dstat, s->sist1, s->sist0);
         last_level = level;
     }
-    pci_set_irq(&s->pci_dev, 0, level);
+    qemu_set_irq(s->pci_dev.irq[0], level);
 }
 
 /* Stop SCRIPTS execution and raise a SCSI interrupt.  */
@@ -855,6 +855,7 @@
             offset = sxt24(addr);
             cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
             s->dbc = cpu_to_le32(buf[0]);
+            s->rbc = s->dbc;
             addr = cpu_to_le32(buf[1]);
         }
         if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
@@ -864,6 +865,8 @@
             break;
         }
         s->dnad = addr;
+        /* ??? Set ESA.  */
+        s->ia = s->dsp - 8;
         switch (s->sstat1 & 0x7) {
         case PHASE_DO:
             s->waiting = 2;
@@ -898,8 +901,6 @@
         s->sbc = s->dbc;
         s->rbc -= s->dbc;
         s->ua = addr + s->dbc;
-        /* ??? Set ESA.  */
-        s->ia = s->dsp - 8;
         break;
 
     case 1: /* IO or Read/Write instruction.  */
@@ -1038,7 +1039,7 @@
                 op0 |= op1;
                 break;
             case 3: /* XOR */
-                op0 |= op1;
+                op0 ^= op1;
                 break;
             case 4: /* AND */
                 op0 &= op1;
@@ -1046,6 +1047,7 @@
             case 5: /* SHR */
                 op1 = op0 & 1;
                 op0 = (op0 >> 1) | (s->carry << 7);
+                s->carry = op1;
                 break;
             case 6: /* ADD */
                 op0 += op1;
@@ -1388,7 +1390,7 @@
         break;
     case 0x02: /* SCNTL2 */
         val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
-        s->scntl3 = val;
+        s->scntl2 = val;
         break;
     case 0x03: /* SCNTL3 */
         s->scntl3 = val;
@@ -1433,10 +1435,13 @@
         if (val & LSI_ISTAT0_SRST) {
             lsi_soft_reset(s);
         }
+        break;
     case 0x16: /* MBOX0 */
         s->mbox0 = val;
+        break;
     case 0x17: /* MBOX1 */
         s->mbox1 = val;
+        break;
     case 0x1b: /* CTEST3 */
         s->ctest3 = val & 0x0f;
         break;
@@ -1453,19 +1458,19 @@
         }
         s->ctest5 = val;
         break;
-    case 0x2c: /* DSPS[0:7] */
+    case 0x2c: /* DSP[0:7] */
         s->dsp &= 0xffffff00;
         s->dsp |= val;
         break;
-    case 0x2d: /* DSPS[8:15] */
+    case 0x2d: /* DSP[8:15] */
         s->dsp &= 0xffff00ff;
         s->dsp |= val << 8;
         break;
-    case 0x2e: /* DSPS[16:23] */
+    case 0x2e: /* DSP[16:23] */
         s->dsp &= 0xff00ffff;
         s->dsp |= val << 16;
         break;
-    case 0x2f: /* DSPS[14:31] */
+    case 0x2f: /* DSP[24:31] */
         s->dsp &= 0x00ffffff;
         s->dsp |= val << 24;
         if ((s->dmode & LSI_DMODE_MAN) == 0
@@ -1765,10 +1770,10 @@
     lsi_reg_writeb(s, addr, val & 0xff);
     lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
     lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
-    lsi_reg_writeb(s, addr + 2, (val >> 24) & 0xff);
+    lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
 }
 
-static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num, 
+static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
                            uint32_t addr, uint32_t size, int type)
 {
     LSIState *s = (LSIState *)pci_dev;
@@ -1783,7 +1788,7 @@
     register_ioport_read(addr, 256, 4, lsi_io_readl, s);
 }
 
-static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num, 
+static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
                             uint32_t addr, uint32_t size, int type)
 {
     LSIState *s = (LSIState *)pci_dev;
@@ -1793,7 +1798,7 @@
     cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
 }
 
-static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num, 
+static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
                              uint32_t addr, uint32_t size, int type)
 {
     LSIState *s = (LSIState *)pci_dev;
diff --git a/hw/m48t59.c b/hw/m48t59.c
index daa1c52..da61313 100644
--- a/hw/m48t59.c
+++ b/hw/m48t59.c
@@ -1,8 +1,8 @@
 /*
  * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
- * 
- * Copyright (c) 2003-2005 Jocelyn Mayer
- * 
+ *
+ * Copyright (c) 2003-2005, 2007 Jocelyn Mayer
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -41,9 +41,9 @@
     /* Model parameters */
     int type; // 8 = m48t08, 59 = m48t59
     /* Hardware parameters */
-    int      IRQ;
+    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 */
@@ -80,14 +80,17 @@
 #ifdef _WIN32
     memcpy(tm,localtime(&t),sizeof(*tm));
 #else
-    localtime_r (&t, tm) ;
+    if (rtc_utc)
+        gmtime_r (&t, tm);
+    else
+        localtime_r (&t, tm) ;
 #endif
 }
 
 static void set_time (m48t59_t *NVRAM, struct tm *tm)
 {
     time_t now, new_time;
-    
+
     new_time = mktime(tm);
     now = time(NULL);
     NVRAM->time_offset = new_time - now;
@@ -100,8 +103,8 @@
     uint64_t next_time;
     m48t59_t *NVRAM = opaque;
 
-    pic_set_irq(NVRAM->IRQ, 1);
-    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 && 
+    qemu_set_irq(NVRAM->IRQ, 1);
+    if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
 	(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
 	(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
 	(NVRAM->buffer[0x1FF2] & 0x80) == 0) {
@@ -137,7 +140,7 @@
 	next_time = 1 + mktime(&tm_now);
     }
     qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
-    pic_set_irq(NVRAM->IRQ, 0);
+    qemu_set_irq(NVRAM->IRQ, 0);
 }
 
 
@@ -146,7 +149,10 @@
 #ifdef _WIN32
     memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
 #else
-    localtime_r (&NVRAM->alarm, tm);
+    if (rtc_utc)
+        gmtime_r (&NVRAM->alarm, tm);
+    else
+        localtime_r (&NVRAM->alarm, tm);
 #endif
 }
 
@@ -155,10 +161,9 @@
     NVRAM->alarm = mktime(tm);
     if (NVRAM->alrm_timer != NULL) {
         qemu_del_timer(NVRAM->alrm_timer);
-	NVRAM->alrm_timer = NULL;
+        if (NVRAM->alarm - time(NULL) > 0)
+            qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
     }
-    if (NVRAM->alarm - time(NULL) > 0)
-	qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
 }
 
 /* Watchdog management */
@@ -173,8 +178,8 @@
         /* May it be a hw CPU Reset instead ? */
         qemu_system_reset_request();
     } else {
-	pic_set_irq(NVRAM->IRQ, 1);
-	pic_set_irq(NVRAM->IRQ, 0);
+	qemu_set_irq(NVRAM->IRQ, 1);
+	qemu_set_irq(NVRAM->IRQ, 0);
     }
 }
 
@@ -182,15 +187,14 @@
 {
     uint64_t interval; /* in 1/16 seconds */
 
+    NVRAM->buffer[0x1FF0] &= ~0x80;
     if (NVRAM->wd_timer != NULL) {
         qemu_del_timer(NVRAM->wd_timer);
-	NVRAM->wd_timer = NULL;
-    }
-    NVRAM->buffer[0x1FF0] &= ~0x80;
-    if (value != 0) {
-	interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
-	qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
-		       ((interval * 1000) >> 4));
+        if (value != 0) {
+            interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
+            qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
+                           ((interval * 1000) >> 4));
+        }
     }
 }
 
@@ -202,7 +206,7 @@
 
     if (addr > 0x1FF8 && addr < 0x2000)
 	NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
-    if (NVRAM->type == 8 && 
+    if (NVRAM->type == 8 &&
         (addr >= 0x1ff0 && addr <= 0x1ff7))
         goto do_write;
     switch (addr) {
@@ -358,7 +362,7 @@
     struct tm tm;
     uint32_t retval = 0xFF;
 
-    if (NVRAM->type == 8 && 
+    if (NVRAM->type == 8 &&
         (addr >= 0x1ff0 && addr <= 0x1ff7))
         goto do_read;
     switch (addr) {
@@ -424,7 +428,7 @@
     case 0x1FFF:
         /* year */
         get_time(NVRAM, &tm);
-        if (NVRAM->type == 8) 
+        if (NVRAM->type == 8)
             retval = toBCD(tm.tm_year - 68); // Base year is 1968
         else
             retval = toBCD(tm.tm_year);
@@ -504,7 +508,7 @@
 static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     m48t59_t *NVRAM = opaque;
-    
+
     addr -= NVRAM->mem_base;
     m48t59_write(NVRAM, addr, value & 0xff);
 }
@@ -512,7 +516,7 @@
 static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     m48t59_t *NVRAM = opaque;
-    
+
     addr -= NVRAM->mem_base;
     m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
     m48t59_write(NVRAM, addr + 1, value & 0xff);
@@ -521,7 +525,7 @@
 static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
 {
     m48t59_t *NVRAM = opaque;
-    
+
     addr -= NVRAM->mem_base;
     m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
     m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
@@ -533,7 +537,7 @@
 {
     m48t59_t *NVRAM = opaque;
     uint32_t retval;
-    
+
     addr -= NVRAM->mem_base;
     retval = m48t59_read(NVRAM, addr);
     return retval;
@@ -543,7 +547,7 @@
 {
     m48t59_t *NVRAM = opaque;
     uint32_t retval;
-    
+
     addr -= NVRAM->mem_base;
     retval = m48t59_read(NVRAM, addr) << 8;
     retval |= m48t59_read(NVRAM, addr + 1);
@@ -575,12 +579,47 @@
     &nvram_readl,
 };
 
+static void m48t59_save(QEMUFile *f, void *opaque)
+{
+    m48t59_t *s = opaque;
+
+    qemu_put_8s(f, &s->lock);
+    qemu_put_be16s(f, &s->addr);
+    qemu_put_buffer(f, s->buffer, s->size);
+}
+
+static int m48t59_load(QEMUFile *f, void *opaque, int version_id)
+{
+    m48t59_t *s = opaque;
+
+    if (version_id != 1)
+        return -EINVAL;
+
+    qemu_get_8s(f, &s->lock);
+    qemu_get_be16s(f, &s->addr);
+    qemu_get_buffer(f, s->buffer, s->size);
+
+    return 0;
+}
+
+static void m48t59_reset(void *opaque)
+{
+    m48t59_t *NVRAM = opaque;
+
+    if (NVRAM->alrm_timer != NULL)
+        qemu_del_timer(NVRAM->alrm_timer);
+
+    if (NVRAM->wd_timer != NULL)
+        qemu_del_timer(NVRAM->wd_timer);
+}
+
 /* Initialisation routine */
-m48t59_t *m48t59_init (int 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_phys_addr_t save_base;
 
     s = qemu_mallocz(sizeof(m48t59_t));
     if (!s)
@@ -610,5 +649,9 @@
     }
     s->lock = 0;
 
+    qemu_register_reset(m48t59_reset, s);
+    save_base = mem_base ? mem_base : io_base;
+    register_savevm("m48t59", save_base, 1, m48t59_save, m48t59_load, s);
+
     return s;
 }
diff --git a/hw/m48t59.h b/hw/m48t59.h
index af22dc1..cfe9b2a 100644
--- a/hw/m48t59.h
+++ b/hw/m48t59.h
@@ -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 (int 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);
 
diff --git a/hw/max111x.c b/hw/max111x.c
new file mode 100644
index 0000000..8425bee
--- /dev/null
+++ b/hw/max111x.c
@@ -0,0 +1,173 @@
+/*
+ * Maxim MAX1110/1111 ADC chip emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPLv2.
+ */
+
+#include <vl.h>
+
+struct max111x_s {
+    qemu_irq interrupt;
+    uint8_t tb1, rb2, rb3;
+    int cycle;
+
+    int input[8];
+    int inputs, com;
+};
+
+/* Control-byte bitfields */
+#define CB_PD0		(1 << 0)
+#define CB_PD1		(1 << 1)
+#define CB_SGL		(1 << 2)
+#define CB_UNI		(1 << 3)
+#define CB_SEL0		(1 << 4)
+#define CB_SEL1		(1 << 5)
+#define CB_SEL2		(1 << 6)
+#define CB_START	(1 << 7)
+
+#define CHANNEL_NUM(v, b0, b1, b2)	\
+			((((v) >> (2 + (b0))) & 4) |	\
+			 (((v) >> (3 + (b1))) & 2) |	\
+			 (((v) >> (4 + (b2))) & 1))
+
+uint32_t max111x_read(void *opaque)
+{
+    struct max111x_s *s = (struct max111x_s *) opaque;
+
+    if (!s->tb1)
+        return 0;
+
+    switch (s->cycle ++) {
+    case 1:
+        return s->rb2;
+    case 2:
+        return s->rb3;
+    }
+
+    return 0;
+}
+
+/* Interpret a control-byte */
+void max111x_write(void *opaque, uint32_t value)
+{
+    struct max111x_s *s = (struct max111x_s *) opaque;
+    int measure, chan;
+
+    /* Ignore the value if START bit is zero */
+    if (!(value & CB_START))
+        return;
+
+    s->cycle = 0;
+
+    if (!(value & CB_PD1)) {
+        s->tb1 = 0;
+        return;
+    }
+
+    s->tb1 = value;
+
+    if (s->inputs == 8)
+        chan = CHANNEL_NUM(value, 1, 0, 2);
+    else
+        chan = CHANNEL_NUM(value & ~CB_SEL0, 0, 1, 2);
+
+    if (value & CB_SGL)
+        measure = s->input[chan] - s->com;
+    else
+        measure = s->input[chan] - s->input[chan ^ 1];
+
+    if (!(value & CB_UNI))
+        measure ^= 0x80;
+
+    s->rb2 = (measure >> 2) & 0x3f;
+    s->rb3 = (measure << 6) & 0xc0;
+
+    if (s->interrupt)
+        qemu_irq_raise(s->interrupt);
+}
+
+static void max111x_save(QEMUFile *f, void *opaque)
+{
+    struct max111x_s *s = (struct max111x_s *) opaque;
+    int i;
+
+    qemu_put_8s(f, &s->tb1);
+    qemu_put_8s(f, &s->rb2);
+    qemu_put_8s(f, &s->rb3);
+    qemu_put_be32(f, s->inputs);
+    qemu_put_be32(f, s->com);
+    for (i = 0; i < s->inputs; i ++)
+        qemu_put_byte(f, s->input[i]);
+}
+
+static int max111x_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct max111x_s *s = (struct max111x_s *) opaque;
+    int i;
+
+    qemu_get_8s(f, &s->tb1);
+    qemu_get_8s(f, &s->rb2);
+    qemu_get_8s(f, &s->rb3);
+    if (s->inputs != qemu_get_be32(f))
+        return -EINVAL;
+    s->com = qemu_get_be32(f);
+    for (i = 0; i < s->inputs; i ++)
+        s->input[i] = qemu_get_byte(f);
+
+    return 0;
+}
+
+static int max111x_iid = 0;
+
+static struct max111x_s *max111x_init(qemu_irq cb)
+{
+    struct max111x_s *s;
+    s = (struct max111x_s *)
+            qemu_mallocz(sizeof(struct max111x_s));
+    memset(s, 0, sizeof(struct max111x_s));
+
+    s->interrupt = cb;
+
+    /* TODO: add a user interface for setting these */
+    s->input[0] = 0xf0;
+    s->input[1] = 0xe0;
+    s->input[2] = 0xd0;
+    s->input[3] = 0xc0;
+    s->input[4] = 0xb0;
+    s->input[5] = 0xa0;
+    s->input[6] = 0x90;
+    s->input[7] = 0x80;
+    s->com = 0;
+
+    register_savevm("max111x", max111x_iid ++, 0,
+                    max111x_save, max111x_load, s);
+
+    return s;
+}
+
+struct max111x_s *max1110_init(qemu_irq cb)
+{
+    struct max111x_s *s = max111x_init(cb);
+    s->inputs = 8;
+    return s;
+}
+
+struct max111x_s *max1111_init(qemu_irq cb)
+{
+    struct max111x_s *s = max111x_init(cb);
+    s->inputs = 4;
+    return s;
+}
+
+void max111x_set_input(struct max111x_s *s, int line, uint8_t value)
+{
+    if (line >= s->inputs) {
+        printf("%s: There's no input %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    s->input[line] = value;
+}
diff --git a/hw/max7310.c b/hw/max7310.c
new file mode 100644
index 0000000..6b180d9
--- /dev/null
+++ b/hw/max7310.c
@@ -0,0 +1,226 @@
+/*
+ * MAX7310 8-port GPIO expansion chip.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This file is licensed under GNU GPL.
+ */
+
+#include "vl.h"
+
+struct max7310_s {
+    i2c_slave i2c;
+    int i2c_command_byte;
+    int len;
+
+    uint8_t level;
+    uint8_t direction;
+    uint8_t polarity;
+    uint8_t status;
+    uint8_t command;
+    qemu_irq handler[8];
+    qemu_irq *gpio_in;
+};
+
+void max7310_reset(i2c_slave *i2c)
+{
+    struct max7310_s *s = (struct max7310_s *) i2c;
+    s->level &= s->direction;
+    s->direction = 0xff;
+    s->polarity = 0xf0;
+    s->status = 0x01;
+    s->command = 0x00;
+}
+
+static int max7310_rx(i2c_slave *i2c)
+{
+    struct max7310_s *s = (struct max7310_s *) i2c;
+
+    switch (s->command) {
+    case 0x00:	/* Input port */
+        return s->level ^ s->polarity;
+        break;
+
+    case 0x01:	/* Output port */
+        return s->level & ~s->direction;
+        break;
+
+    case 0x02:	/* Polarity inversion */
+        return s->polarity;
+
+    case 0x03:	/* Configuration */
+        return s->direction;
+
+    case 0x04:	/* Timeout */
+        return s->status;
+        break;
+
+    case 0xff:	/* Reserved */
+        return 0xff;
+
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
+#endif
+        break;
+    }
+    return 0xff;
+}
+
+static int max7310_tx(i2c_slave *i2c, uint8_t data)
+{
+    struct max7310_s *s = (struct max7310_s *) i2c;
+    uint8_t diff;
+    int line;
+
+    if (s->len ++ > 1) {
+#ifdef VERBOSE
+        printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+        return 1;
+    }
+
+    if (s->i2c_command_byte) {
+        s->command = data;
+        s->i2c_command_byte = 0;
+        return 0;
+    }
+
+    switch (s->command) {
+    case 0x01:	/* Output port */
+        for (diff = (data ^ s->level) & ~s->direction; diff;
+                        diff &= ~(1 << line)) {
+            line = ffs(diff) - 1;
+            if (s->handler[line])
+                qemu_set_irq(s->handler[line], (data >> line) & 1);
+        }
+        s->level = (s->level & s->direction) | (data & ~s->direction);
+        break;
+
+    case 0x02:	/* Polarity inversion */
+        s->polarity = data;
+        break;
+
+    case 0x03:	/* Configuration */
+        s->level &= ~(s->direction ^ data);
+        s->direction = data;
+        break;
+
+    case 0x04:	/* Timeout */
+        s->status = data;
+        break;
+
+    case 0x00:	/* Input port - ignore writes */
+	break;
+    default:
+#ifdef VERBOSE
+        printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
+#endif
+        return 1;
+    }
+
+    return 0;
+}
+
+static void max7310_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct max7310_s *s = (struct max7310_s *) i2c;
+    s->len = 0;
+
+    switch (event) {
+    case I2C_START_SEND:
+        s->i2c_command_byte = 1;
+        break;
+    case I2C_FINISH:
+        if (s->len == 1)
+#ifdef VERBOSE
+            printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+        break;
+    default:
+        break;
+    }
+}
+
+static void max7310_save(QEMUFile *f, void *opaque)
+{
+    struct max7310_s *s = (struct max7310_s *) opaque;
+
+    qemu_put_be32(f, s->i2c_command_byte);
+    qemu_put_be32(f, s->len);
+
+    qemu_put_8s(f, &s->level);
+    qemu_put_8s(f, &s->direction);
+    qemu_put_8s(f, &s->polarity);
+    qemu_put_8s(f, &s->status);
+    qemu_put_8s(f, &s->command);
+
+    i2c_slave_save(f, &s->i2c);
+}
+
+static int max7310_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct max7310_s *s = (struct max7310_s *) opaque;
+
+    s->i2c_command_byte = qemu_get_be32(f);
+    s->len = qemu_get_be32(f);
+
+    qemu_get_8s(f, &s->level);
+    qemu_get_8s(f, &s->direction);
+    qemu_get_8s(f, &s->polarity);
+    qemu_get_8s(f, &s->status);
+    qemu_get_8s(f, &s->command);
+
+    i2c_slave_load(f, &s->i2c);
+    return 0;
+}
+
+static int max7310_iid = 0;
+
+static void max7310_gpio_set(void *opaque, int line, int level)
+{
+    struct max7310_s *s = (struct max7310_s *) opaque;
+    if (line >= sizeof(s->handler) / sizeof(*s->handler) || line  < 0)
+        cpu_abort(cpu_single_env, "bad GPIO line");
+
+    if (level)
+        s->level |= s->direction & (1 << line);
+    else
+        s->level &= ~(s->direction & (1 << line));
+}
+
+/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
+ * but also accepts sequences that are not SMBus so return an I2C device.  */
+struct i2c_slave *max7310_init(i2c_bus *bus)
+{
+    struct max7310_s *s = (struct max7310_s *)
+            i2c_slave_init(bus, 0, sizeof(struct max7310_s));
+    s->i2c.event = max7310_event;
+    s->i2c.recv = max7310_rx;
+    s->i2c.send = max7310_tx;
+    s->gpio_in = qemu_allocate_irqs(max7310_gpio_set, s,
+                    sizeof(s->handler) / sizeof(*s->handler));
+
+    max7310_reset(&s->i2c);
+
+    register_savevm("max7310", max7310_iid ++, 0,
+                    max7310_save, max7310_load, s);
+
+    return &s->i2c;
+}
+
+qemu_irq *max7310_gpio_in_get(i2c_slave *i2c)
+{
+    struct max7310_s *s = (struct max7310_s *) i2c;
+    return s->gpio_in;
+}
+
+void max7310_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler)
+{
+    struct max7310_s *s = (struct max7310_s *) i2c;
+    if (line >= sizeof(s->handler) / sizeof(*s->handler) || line  < 0)
+        cpu_abort(cpu_single_env, "bad GPIO line");
+
+    s->handler[line] = handler;
+}
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index bad4cbd..789ebd3 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -1,8 +1,8 @@
 /*
  * QEMU MC146818 RTC emulation
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -54,7 +54,9 @@
     uint8_t cmos_data[128];
     uint8_t cmos_index;
     struct tm current_tm;
-    int irq;
+    qemu_irq irq;
+    target_phys_addr_t base;
+    int it_shift;
     /* periodic timer */
     QEMUTimer *periodic_timer;
     int64_t next_periodic_time;
@@ -73,7 +75,7 @@
     int64_t cur_clock, next_irq_clock;
 
     period_code = s->cmos_data[RTC_REG_A] & 0x0f;
-    if (period_code != 0 && 
+    if (period_code != 0 &&
         (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
         if (period_code <= 2)
             period_code += 7;
@@ -95,7 +97,7 @@
 
     rtc_timer_update(s, s->next_periodic_time);
     s->cmos_data[RTC_REG_C] |= 0xc0;
-    pic_set_irq(s->irq, 1);
+    qemu_irq_raise(s->irq);
 }
 
 static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
@@ -108,7 +110,7 @@
 #ifdef DEBUG_CMOS
         printf("cmos: write index=0x%02x val=0x%02x\n",
                s->cmos_index, data);
-#endif        
+#endif
         switch(s->cmos_index) {
         case RTC_SECONDS_ALARM:
         case RTC_MINUTES_ALARM:
@@ -219,8 +221,8 @@
 /* month is between 0 and 11. */
 static int get_days_in_month(int month, int year)
 {
-    static const int days_tab[12] = { 
-        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 
+    static const int days_tab[12] = {
+        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
     };
     int d;
     if ((unsigned )month >= 12)
@@ -251,7 +253,7 @@
                 tm->tm_wday++;
                 if ((unsigned)tm->tm_wday >= 7)
                     tm->tm_wday = 0;
-                days_in_month = get_days_in_month(tm->tm_mon, 
+                days_in_month = get_days_in_month(tm->tm_mon,
                                                   tm->tm_year + 1900);
                 tm->tm_mday++;
                 if (tm->tm_mday < 1) {
@@ -281,7 +283,7 @@
         qemu_mod_timer(s->second_timer, s->next_second_time);
     } else {
         rtc_next_second(&s->current_tm);
-        
+
         if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
             /* update in progress bit */
             s->cmos_data[RTC_REG_A] |= REG_A_UIP;
@@ -291,7 +293,7 @@
         delay = (ticks_per_sec * 1) / 100;
         if (delay < 1)
             delay = 1;
-        qemu_mod_timer(s->second_timer2, 
+        qemu_mod_timer(s->second_timer2,
                        s->next_second_time + delay);
     }
 }
@@ -313,15 +315,15 @@
             ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
              s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
 
-            s->cmos_data[RTC_REG_C] |= 0xa0; 
-            pic_set_irq(s->irq, 1);
+            s->cmos_data[RTC_REG_C] |= 0xa0;
+            qemu_irq_raise(s->irq);
         }
     }
 
     /* update ended interrupt */
     if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
-        s->cmos_data[RTC_REG_C] |= 0x90; 
-        pic_set_irq(s->irq, 1);
+        s->cmos_data[RTC_REG_C] |= 0x90;
+        qemu_irq_raise(s->irq);
     }
 
     /* clear update in progress bit */
@@ -353,8 +355,8 @@
             break;
         case RTC_REG_C:
             ret = s->cmos_data[s->cmos_index];
-            pic_set_irq(s->irq, 0);
-            s->cmos_data[RTC_REG_C] = 0x00; 
+            qemu_irq_lower(s->irq);
+            s->cmos_data[RTC_REG_C] = 0x00;
             break;
         default:
             ret = s->cmos_data[s->cmos_index];
@@ -409,7 +411,7 @@
 
     qemu_put_buffer(f, s->cmos_data, 128);
     qemu_put_8s(f, &s->cmos_index);
-    
+
     qemu_put_be32s(f, &s->current_tm.tm_sec);
     qemu_put_be32s(f, &s->current_tm.tm_min);
     qemu_put_be32s(f, &s->current_tm.tm_hour);
@@ -453,7 +455,7 @@
     return 0;
 }
 
-RTCState *rtc_init(int base, int irq)
+RTCState *rtc_init(int base, qemu_irq irq)
 {
     RTCState *s;
 
@@ -469,11 +471,11 @@
 
     rtc_set_date_from_host(s);
 
-    s->periodic_timer = qemu_new_timer(vm_clock, 
+    s->periodic_timer = qemu_new_timer(vm_clock,
                                        rtc_periodic_timer, s);
-    s->second_timer = qemu_new_timer(vm_clock, 
+    s->second_timer = qemu_new_timer(vm_clock,
                                      rtc_update_second, s);
-    s->second_timer2 = qemu_new_timer(vm_clock, 
+    s->second_timer2 = qemu_new_timer(vm_clock,
                                       rtc_update_second2, s);
 
     s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
@@ -486,3 +488,109 @@
     return s;
 }
 
+/* Memory mapped interface */
+uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    RTCState *s = opaque;
+
+    return cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
+}
+
+void cmos_mm_writeb (void *opaque,
+                     target_phys_addr_t addr, uint32_t value)
+{
+    RTCState *s = opaque;
+
+    cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
+}
+
+uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+    RTCState *s = opaque;
+    uint32_t val;
+
+    val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap16(val);
+#endif
+    return val;
+}
+
+void cmos_mm_writew (void *opaque,
+                     target_phys_addr_t addr, uint32_t value)
+{
+    RTCState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+    value = bswap16(value);
+#endif
+    cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
+}
+
+uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+    RTCState *s = opaque;
+    uint32_t val;
+
+    val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    return val;
+}
+
+void cmos_mm_writel (void *opaque,
+                     target_phys_addr_t addr, uint32_t value)
+{
+    RTCState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+    value = bswap32(value);
+#endif
+    cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc *rtc_mm_read[] = {
+    &cmos_mm_readb,
+    &cmos_mm_readw,
+    &cmos_mm_readl,
+};
+
+static CPUWriteMemoryFunc *rtc_mm_write[] = {
+    &cmos_mm_writeb,
+    &cmos_mm_writew,
+    &cmos_mm_writel,
+};
+
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)
+{
+    RTCState *s;
+    int io_memory;
+
+    s = qemu_mallocz(sizeof(RTCState));
+    if (!s)
+        return NULL;
+
+    s->irq = irq;
+    s->cmos_data[RTC_REG_A] = 0x26;
+    s->cmos_data[RTC_REG_B] = 0x02;
+    s->cmos_data[RTC_REG_C] = 0x00;
+    s->cmos_data[RTC_REG_D] = 0x80;
+    s->base = base;
+
+    rtc_set_date_from_host(s);
+
+    s->periodic_timer = qemu_new_timer(vm_clock,
+                                       rtc_periodic_timer, s);
+    s->second_timer = qemu_new_timer(vm_clock,
+                                     rtc_update_second, s);
+    s->second_timer2 = qemu_new_timer(vm_clock,
+                                      rtc_update_second2, s);
+
+    s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
+    qemu_mod_timer(s->second_timer2, s->next_second_time);
+
+    io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s);
+    cpu_register_physical_memory(base, 2 << it_shift, io_memory);
+
+    register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
+    return s;
+}
diff --git a/hw/mcf5206.c b/hw/mcf5206.c
new file mode 100644
index 0000000..32117ae
--- /dev/null
+++ b/hw/mcf5206.c
@@ -0,0 +1,540 @@
+/*
+ * 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;
+}
+
+/* System Integration Module.  */
+
+typedef struct {
+    CPUState *env;
+    m5206_timer_state *timer[2];
+    void *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 mcf_uart_read(s->uart[0], offset - 0x140);
+    } else if (offset >= 0x180 && offset < 0x1a0) {
+        return mcf_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) {
+        mcf_uart_write(s->uart[0], offset - 0x140, value);
+        return;
+    } else if (offset >= 0x180 && offset < 0x1a0) {
+        mcf_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, 0x00001000, 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] = mcf_uart_init(pic[12], serial_hds[0]);
+    s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]);
+    s->env = env;
+
+    m5206_mbar_reset(s);
+    return pic;
+}
+
diff --git a/hw/mcf5208.c b/hw/mcf5208.c
new file mode 100644
index 0000000..993a686
--- /dev/null
+++ b/hw/mcf5208.c
@@ -0,0 +1,305 @@
+/*
+ * Motorola ColdFire MCF5208 SoC emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licenced under the GPL
+ */
+#include "vl.h"
+
+#define SYS_FREQ 66000000
+
+#define PCSR_EN         0x0001
+#define PCSR_RLD        0x0002
+#define PCSR_PIF        0x0004
+#define PCSR_PIE        0x0008
+#define PCSR_OVW        0x0010
+#define PCSR_DBG        0x0020
+#define PCSR_DOZE       0x0040
+#define PCSR_PRE_SHIFT  8
+#define PCSR_PRE_MASK   0x0f00
+
+typedef struct {
+    qemu_irq irq;
+    ptimer_state *timer;
+    uint16_t pcsr;
+    uint16_t pmr;
+    uint16_t pcntr;
+} m5208_timer_state;
+
+static void m5208_timer_update(m5208_timer_state *s)
+{
+    if ((s->pcsr & (PCSR_PIE | PCSR_PIF)) == (PCSR_PIE | PCSR_PIF))
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static void m5208_timer_write(m5208_timer_state *s, int offset,
+                              uint32_t value)
+{
+    int prescale;
+    int limit;
+    switch (offset) {
+    case 0:
+        /* The PIF bit is set-to-clear.  */
+        if (value & PCSR_PIF) {
+            s->pcsr &= ~PCSR_PIF;
+            value &= ~PCSR_PIF;
+        }
+        /* Avoid frobbing the timer if we're just twiddling IRQ bits. */
+        if (((s->pcsr ^ value) & ~PCSR_PIE) == 0) {
+            s->pcsr = value;
+            m5208_timer_update(s);
+            return;
+        }
+
+        if (s->pcsr & PCSR_EN)
+            ptimer_stop(s->timer);
+
+        s->pcsr = value;
+
+        prescale = 1 << ((s->pcsr & PCSR_PRE_MASK) >> PCSR_PRE_SHIFT);
+        ptimer_set_freq(s->timer, (SYS_FREQ / 2) / prescale);
+        if (s->pcsr & PCSR_RLD)
+            limit = s->pmr;
+        else
+            limit = 0xffff;
+        ptimer_set_limit(s->timer, limit, 0);
+
+        if (s->pcsr & PCSR_EN)
+            ptimer_run(s->timer, 0);
+        break;
+    case 2:
+        s->pmr = value;
+        s->pcsr &= ~PCSR_PIF;
+        if ((s->pcsr & PCSR_RLD) == 0) {
+            if (s->pcsr & PCSR_OVW)
+                ptimer_set_count(s->timer, value);
+        } else {
+            ptimer_set_limit(s->timer, value, s->pcsr & PCSR_OVW);
+        }
+        break;
+    case 4:
+        break;
+    default:
+        /* Should never happen.  */
+        abort();
+    }
+    m5208_timer_update(s);
+}
+
+static void m5208_timer_trigger(void *opaque)
+{
+    m5208_timer_state *s = (m5208_timer_state *)opaque;
+    s->pcsr |= PCSR_PIF;
+    m5208_timer_update(s);
+}
+
+typedef struct {
+    m5208_timer_state timer[2];
+} m5208_sys_state;
+
+static uint32_t m5208_sys_read(void *opaque, target_phys_addr_t addr)
+{
+    m5208_sys_state *s = (m5208_sys_state *)opaque;
+    switch (addr) {
+    /* PIT0 */
+    case 0xfc080000:
+        return s->timer[0].pcsr;
+    case 0xfc080002:
+        return s->timer[0].pmr;
+    case 0xfc080004:
+        return ptimer_get_count(s->timer[0].timer);
+    /* PIT1 */
+    case 0xfc084000:
+        return s->timer[1].pcsr;
+    case 0xfc084002:
+        return s->timer[1].pmr;
+    case 0xfc084004:
+        return ptimer_get_count(s->timer[1].timer);
+
+    /* SDRAM Controller.  */
+    case 0xfc0a8110: /* SDCS0 */
+        {
+            int n;
+            for (n = 0; n < 32; n++) {
+                if (ram_size < (2u << n))
+                    break;
+            }
+            return (n - 1)  | 0x40000000;
+        }
+    case 0xfc0a8114: /* SDCS1 */
+        return 0;
+
+    default:
+        cpu_abort(cpu_single_env, "m5208_sys_read: Bad offset 0x%x\n",
+                  (int)addr);
+        return 0;
+    }
+}
+
+static void m5208_sys_write(void *opaque, target_phys_addr_t addr,
+                            uint32_t value)
+{
+    m5208_sys_state *s = (m5208_sys_state *)opaque;
+    switch (addr) {
+    /* PIT0 */
+    case 0xfc080000:
+    case 0xfc080002:
+    case 0xfc080004:
+        m5208_timer_write(&s->timer[0], addr & 0xf, value);
+        return;
+    /* PIT1 */
+    case 0xfc084000:
+    case 0xfc084002:
+    case 0xfc084004:
+        m5208_timer_write(&s->timer[1], addr & 0xf, value);
+        return;
+    default:
+        cpu_abort(cpu_single_env, "m5208_sys_write: Bad offset 0x%x\n",
+                  (int)addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *m5208_sys_readfn[] = {
+   m5208_sys_read,
+   m5208_sys_read,
+   m5208_sys_read
+};
+
+static CPUWriteMemoryFunc *m5208_sys_writefn[] = {
+   m5208_sys_write,
+   m5208_sys_write,
+   m5208_sys_write
+};
+
+static void mcf5208_sys_init(qemu_irq *pic)
+{
+    int iomemtype;
+    m5208_sys_state *s;
+    QEMUBH *bh;
+    int i;
+
+    s = (m5208_sys_state *)qemu_mallocz(sizeof(m5208_sys_state));
+    iomemtype = cpu_register_io_memory(0, m5208_sys_readfn,
+                                       m5208_sys_writefn, s);
+    /* SDRAMC.  */
+    cpu_register_physical_memory(0xfc0a8000, 0x00004000, iomemtype);
+    /* Timers.  */
+    for (i = 0; i < 2; i++) {
+        bh = qemu_bh_new(m5208_timer_trigger, &s->timer[i]);
+        s->timer[i].timer = ptimer_init(bh);
+        cpu_register_physical_memory(0xfc080000 + 0x4000 * i, 0x00004000,
+                                     iomemtype);
+        s->timer[i].irq = pic[4 + i];
+    }
+}
+
+static void mcf5208evb_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;
+    qemu_irq *pic;
+
+    env = cpu_init();
+    if (!cpu_model)
+        cpu_model = "m5208";
+    if (cpu_m68k_set_model(env, cpu_model)) {
+        cpu_abort(env, "Unable to find m68k CPU definition\n");
+    }
+
+    /* Initialize CPU registers.  */
+    env->vbr = 0;
+    /* TODO: Configure BARs.  */
+
+    /* DRAM at 0x20000000 */
+    cpu_register_physical_memory(0x40000000, ram_size,
+        qemu_ram_alloc(ram_size) | IO_MEM_RAM);
+
+    /* Internal SRAM.  */
+    cpu_register_physical_memory(0x80000000, 16384,
+        qemu_ram_alloc(16384) | IO_MEM_RAM);
+
+    /* Internal peripherals.  */
+    pic = mcf_intc_init(0xfc048000, env);
+
+    mcf_uart_mm_init(0xfc060000, pic[26], serial_hds[0]);
+    mcf_uart_mm_init(0xfc064000, pic[27], serial_hds[1]);
+    mcf_uart_mm_init(0xfc068000, pic[28], serial_hds[2]);
+
+    mcf5208_sys_init(pic);
+
+    if (nb_nics > 1) {
+        fprintf(stderr, "Too many NICs\n");
+        exit(1);
+    }
+    if (nd_table[0].vlan) {
+        if (nd_table[0].model == NULL
+            || strcmp(nd_table[0].model, "mcf_fec") == 0) {
+            mcf_fec_init(&nd_table[0], 0xfc030000, pic + 36);
+        } else if (strcmp(nd_table[0].model, "?") == 0) {
+            fprintf(stderr, "qemu: Supported NICs: mcf_fec\n");
+            exit (1);
+        } else {
+            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
+            exit (1);
+        }
+    }
+
+    /*  0xfc000000 SCM.  */
+    /*  0xfc004000 XBS.  */
+    /*  0xfc008000 FlexBus CS.  */
+    /* 0xfc030000 FEC.  */
+    /*  0xfc040000 SCM + Power management.  */
+    /*  0xfc044000 eDMA.  */
+    /* 0xfc048000 INTC.  */
+    /*  0xfc058000 I2C.  */
+    /*  0xfc05c000 QSPI.  */
+    /* 0xfc060000 UART0.  */
+    /* 0xfc064000 UART0.  */
+    /* 0xfc068000 UART0.  */
+    /*  0xfc070000 DMA timers.  */
+    /* 0xfc080000 PIT0.  */
+    /* 0xfc084000 PIT1.  */
+    /*  0xfc088000 EPORT.  */
+    /*  0xfc08c000 Watchdog.  */
+    /*  0xfc090000 clock module.  */
+    /*  0xfc0a0000 CCM + reset.  */
+    /*  0xfc0a4000 GPIO.  */
+    /* 0xfc0a8000 SDRAM controller.  */
+
+    /* 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);
+        entry = 0x20000000;
+    }
+    if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+        exit(1);
+    }
+
+    env->pc = entry;
+}
+
+QEMUMachine mcf5208evb_machine = {
+    "mcf5208evb",
+    "MCF5206EVB",
+    mcf5208evb_init,
+};
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
new file mode 100644
index 0000000..a218108
--- /dev/null
+++ b/hw/mcf_fec.c
@@ -0,0 +1,456 @@
+/*
+ * ColdFire Fast Ethernet Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licenced under the GPL
+ */
+#include "vl.h"
+/* For crc32 */
+#include <zlib.h>
+
+//#define DEBUG_FEC 1
+
+#ifdef DEBUG_FEC
+#define DPRINTF(fmt, args...) \
+do { printf("mcf_fec: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+#define FEC_MAX_FRAME_SIZE 2032
+
+typedef struct {
+    qemu_irq *irq;
+    VLANClientState *vc;
+    uint32_t irq_state;
+    uint32_t eir;
+    uint32_t eimr;
+    int rx_enabled;
+    uint32_t rx_descriptor;
+    uint32_t tx_descriptor;
+    uint32_t ecr;
+    uint32_t mmfr;
+    uint32_t mscr;
+    uint32_t rcr;
+    uint32_t tcr;
+    uint32_t tfwr;
+    uint32_t rfsr;
+    uint32_t erdsr;
+    uint32_t etdsr;
+    uint32_t emrbr;
+    uint8_t macaddr[6];
+} mcf_fec_state;
+
+#define FEC_INT_HB   0x80000000
+#define FEC_INT_BABR 0x40000000
+#define FEC_INT_BABT 0x20000000
+#define FEC_INT_GRA  0x10000000
+#define FEC_INT_TXF  0x08000000
+#define FEC_INT_TXB  0x04000000
+#define FEC_INT_RXF  0x02000000
+#define FEC_INT_RXB  0x01000000
+#define FEC_INT_MII  0x00800000
+#define FEC_INT_EB   0x00400000
+#define FEC_INT_LC   0x00200000
+#define FEC_INT_RL   0x00100000
+#define FEC_INT_UN   0x00080000
+
+#define FEC_EN      2
+#define FEC_RESET   1
+
+/* Map interrupt flags onto IRQ lines.  */
+#define FEC_NUM_IRQ 13
+static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
+    FEC_INT_TXF,
+    FEC_INT_TXB,
+    FEC_INT_UN,
+    FEC_INT_RL,
+    FEC_INT_RXF,
+    FEC_INT_RXB,
+    FEC_INT_MII,
+    FEC_INT_LC,
+    FEC_INT_HB,
+    FEC_INT_GRA,
+    FEC_INT_EB,
+    FEC_INT_BABT,
+    FEC_INT_BABR
+};
+
+/* Buffer Descriptor.  */
+typedef struct {
+    uint16_t flags;
+    uint16_t length;
+    uint32_t data;
+} mcf_fec_bd;
+
+#define FEC_BD_R    0x8000
+#define FEC_BD_E    0x8000
+#define FEC_BD_O1   0x4000
+#define FEC_BD_W    0x2000
+#define FEC_BD_O2   0x1000
+#define FEC_BD_L    0x0800
+#define FEC_BD_TC   0x0400
+#define FEC_BD_ABC  0x0200
+#define FEC_BD_M    0x0100
+#define FEC_BD_BC   0x0080
+#define FEC_BD_MC   0x0040
+#define FEC_BD_LG   0x0020
+#define FEC_BD_NO   0x0010
+#define FEC_BD_CR   0x0004
+#define FEC_BD_OV   0x0002
+#define FEC_BD_TR   0x0001
+
+static void mcf_fec_read_bd(mcf_fec_bd *bd, uint32_t addr)
+{
+    cpu_physical_memory_read(addr, (uint8_t *)bd, sizeof(*bd));
+    be16_to_cpus(&bd->flags);
+    be16_to_cpus(&bd->length);
+    be32_to_cpus(&bd->data);
+}
+
+static void mcf_fec_write_bd(mcf_fec_bd *bd, uint32_t addr)
+{
+    mcf_fec_bd tmp;
+    tmp.flags = cpu_to_be16(bd->flags);
+    tmp.length = cpu_to_be16(bd->length);
+    tmp.data = cpu_to_be32(bd->data);
+    cpu_physical_memory_write(addr, (uint8_t *)&tmp, sizeof(tmp));
+}
+
+static void mcf_fec_update(mcf_fec_state *s)
+{
+    uint32_t active;
+    uint32_t changed;
+    uint32_t mask;
+    int i;
+
+    active = s->eir & s->eimr;
+    changed = active ^s->irq_state;
+    for (i = 0; i < FEC_NUM_IRQ; i++) {
+        mask = mcf_fec_irq_map[i];
+        if (changed & mask) {
+            DPRINTF("IRQ %d = %d\n", i, (active & mask) != 0);
+            qemu_set_irq(s->irq[i], (active & mask) != 0);
+        }
+    }
+    s->irq_state = active;
+}
+
+static void mcf_fec_do_tx(mcf_fec_state *s)
+{
+    uint32_t addr;
+    mcf_fec_bd bd;
+    int frame_size;
+    int len;
+    uint8_t frame[FEC_MAX_FRAME_SIZE];
+    uint8_t *ptr;
+
+    DPRINTF("do_tx\n");
+    ptr = frame;
+    frame_size = 0;
+    addr = s->tx_descriptor;
+    while (1) {
+        mcf_fec_read_bd(&bd, addr);
+        DPRINTF("tx_bd %x flags %04x len %d data %08x\n",
+                addr, bd.flags, bd.length, bd.data);
+        if ((bd.flags & FEC_BD_R) == 0) {
+            /* Run out of descriptors to transmit.  */
+            break;
+        }
+        len = bd.length;
+        if (frame_size + len > FEC_MAX_FRAME_SIZE) {
+            len = FEC_MAX_FRAME_SIZE - frame_size;
+            s->eir |= FEC_INT_BABT;
+        }
+        cpu_physical_memory_read(bd.data, ptr, len);
+        ptr += len;
+        frame_size += len;
+        if (bd.flags & FEC_BD_L) {
+            /* Last buffer in frame.  */
+            DPRINTF("Sending packet\n");
+            qemu_send_packet(s->vc, frame, len);
+            ptr = frame;
+            frame_size = 0;
+            s->eir |= FEC_INT_TXF;
+        }
+        s->eir |= FEC_INT_TXB;
+        bd.flags &= ~FEC_BD_R;
+        /* Write back the modified descriptor.  */
+        mcf_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->etdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->tx_descriptor = addr;
+}
+
+static void mcf_fec_enable_rx(mcf_fec_state *s)
+{
+    mcf_fec_bd bd;
+
+    mcf_fec_read_bd(&bd, s->rx_descriptor);
+    s->rx_enabled = ((bd.flags & FEC_BD_E) != 0);
+    if (!s->rx_enabled)
+        DPRINTF("RX buffer full\n");
+}
+
+static void mcf_fec_reset(mcf_fec_state *s)
+{
+    s->eir = 0;
+    s->eimr = 0;
+    s->rx_enabled = 0;
+    s->ecr = 0;
+    s->mscr = 0;
+    s->rcr = 0x05ee0001;
+    s->tcr = 0;
+    s->tfwr = 0;
+    s->rfsr = 0x500;
+}
+
+static uint32_t mcf_fec_read(void *opaque, target_phys_addr_t addr)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    switch (addr & 0x3ff) {
+    case 0x004: return s->eir;
+    case 0x008: return s->eimr;
+    case 0x010: return s->rx_enabled ? (1 << 24) : 0; /* RDAR */
+    case 0x014: return 0; /* TDAR */
+    case 0x024: return s->ecr;
+    case 0x040: return s->mmfr;
+    case 0x044: return s->mscr;
+    case 0x064: return 0; /* MIBC */
+    case 0x084: return s->rcr;
+    case 0x0c4: return s->tcr;
+    case 0x0e4: /* PALR */
+        return (s->macaddr[0] << 24) | (s->macaddr[1] << 16)
+              | (s->macaddr[2] << 8) | s->macaddr[3];
+        break;
+    case 0x0e8: /* PAUR */
+        return (s->macaddr[4] << 24) | (s->macaddr[5] << 16) | 0x8808;
+    case 0x0ec: return 0x10000; /* OPD */
+    case 0x118: return 0;
+    case 0x11c: return 0;
+    case 0x120: return 0;
+    case 0x124: return 0;
+    case 0x144: return s->tfwr;
+    case 0x14c: return 0x600;
+    case 0x150: return s->rfsr;
+    case 0x180: return s->erdsr;
+    case 0x184: return s->etdsr;
+    case 0x188: return s->emrbr;
+    default:
+        cpu_abort(cpu_single_env, "mcf_fec_read: Bad address 0x%x\n",
+                  (int)addr);
+        return 0;
+    }
+}
+
+void mcf_fec_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    switch (addr & 0x3ff) {
+    case 0x004:
+        s->eir &= ~value;
+        break;
+    case 0x008:
+        s->eimr = value;
+        break;
+    case 0x010: /* RDAR */
+        if ((s->ecr & FEC_EN) && !s->rx_enabled) {
+            DPRINTF("RX enable\n");
+            mcf_fec_enable_rx(s);
+        }
+        break;
+    case 0x014: /* TDAR */
+        if (s->ecr & FEC_EN) {
+            mcf_fec_do_tx(s);
+        }
+        break;
+    case 0x024:
+        s->ecr = value;
+        if (value & FEC_RESET) {
+            DPRINTF("Reset\n");
+            mcf_fec_reset(s);
+        }
+        if ((s->ecr & FEC_EN) == 0) {
+            s->rx_enabled = 0;
+        }
+        break;
+    case 0x040:
+        /* TODO: Implement MII.  */
+        s->mmfr = value;
+        break;
+    case 0x044:
+        s->mscr = value & 0xfe;
+        break;
+    case 0x064:
+        /* TODO: Implement MIB.  */
+        break;
+    case 0x084:
+        s->rcr = value & 0x07ff003f;
+        /* TODO: Implement LOOP mode.  */
+        break;
+    case 0x0c4: /* TCR */
+        /* We transmit immediately, so raise GRA immediately.  */
+        s->tcr = value;
+        if (value & 1)
+            s->eir |= FEC_INT_GRA;
+        break;
+    case 0x0e4: /* PALR */
+        s->macaddr[0] = value >> 24;
+        s->macaddr[1] = value >> 16;
+        s->macaddr[2] = value >> 8;
+        s->macaddr[3] = value;
+        break;
+    case 0x0e8: /* PAUR */
+        s->macaddr[4] = value >> 24;
+        s->macaddr[5] = value >> 16;
+        break;
+    case 0x0ec:
+        /* OPD */
+        break;
+    case 0x118:
+    case 0x11c:
+    case 0x120:
+    case 0x124:
+        /* TODO: implement MAC hash filtering.  */
+        break;
+    case 0x144:
+        s->tfwr = value & 3;
+        break;
+    case 0x14c:
+        /* FRBR writes ignored.  */
+        break;
+    case 0x150:
+        s->rfsr = (value & 0x3fc) | 0x400;
+        break;
+    case 0x180:
+        s->erdsr = value & ~3;
+        s->rx_descriptor = s->erdsr;
+        break;
+    case 0x184:
+        s->etdsr = value & ~3;
+        s->tx_descriptor = s->etdsr;
+        break;
+    case 0x188:
+        s->emrbr = value & 0x7f0;
+        break;
+    default:
+        cpu_abort(cpu_single_env, "mcf_fec_write Bad address 0x%x\n",
+                  (int)addr);
+    }
+    mcf_fec_update(s);
+}
+
+static int mcf_fec_can_receive(void *opaque)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    return s->rx_enabled;
+}
+
+static void mcf_fec_receive(void *opaque, const uint8_t *buf, int size)
+{
+    mcf_fec_state *s = (mcf_fec_state *)opaque;
+    mcf_fec_bd bd;
+    uint32_t flags = 0;
+    uint32_t addr;
+    uint32_t crc;
+    uint32_t buf_addr;
+    uint8_t *crc_ptr;
+    unsigned int buf_len;
+
+    DPRINTF("do_rx len %d\n", size);
+    if (!s->rx_enabled) {
+        fprintf(stderr, "mcf_fec_receive: Unexpected packet\n");
+    }
+    /* 4 bytes for the CRC.  */
+    size += 4;
+    crc = cpu_to_be32(crc32(~0, buf, size));
+    crc_ptr = (uint8_t *)&crc;
+    /* Huge frames are truncted.  */
+    if (size > FEC_MAX_FRAME_SIZE) {
+        size = FEC_MAX_FRAME_SIZE;
+        flags |= FEC_BD_TR | FEC_BD_LG;
+    }
+    /* Frames larger than the user limit just set error flags.  */
+    if (size > (s->rcr >> 16)) {
+        flags |= FEC_BD_LG;
+    }
+    addr = s->rx_descriptor;
+    while (size > 0) {
+        mcf_fec_read_bd(&bd, addr);
+        if ((bd.flags & FEC_BD_E) == 0) {
+            /* No descriptors available.  Bail out.  */
+            /* FIXME: This is wrong.  We should probably either save the
+               remainder for when more RX buffers are available, or
+               flag an error.  */
+            fprintf(stderr, "mcf_fec: Lost end of frame\n");
+            break;
+        }
+        buf_len = (size <= s->emrbr) ? size: s->emrbr;
+        bd.length = buf_len;
+        size -= buf_len;
+        DPRINTF("rx_bd %x length %d\n", addr, bd.length);
+        /* The last 4 bytes are the CRC.  */
+        if (size < 4)
+            buf_len += size - 4;
+        buf_addr = bd.data;
+        cpu_physical_memory_write(buf_addr, buf, buf_len);
+        buf += buf_len;
+        if (size < 4) {
+            cpu_physical_memory_write(buf_addr + buf_len, crc_ptr, 4 - size);
+            crc_ptr += 4 - size;
+        }
+        bd.flags &= ~FEC_BD_E;
+        if (size == 0) {
+            /* Last buffer in frame.  */
+            bd.flags |= flags | FEC_BD_L;
+            DPRINTF("rx frame flags %04x\n", bd.flags);
+            s->eir |= FEC_INT_RXF;
+        } else {
+            s->eir |= FEC_INT_RXB;
+        }
+        mcf_fec_write_bd(&bd, addr);
+        /* Advance to the next descriptor.  */
+        if ((bd.flags & FEC_BD_W) != 0) {
+            addr = s->erdsr;
+        } else {
+            addr += 8;
+        }
+    }
+    s->rx_descriptor = addr;
+    mcf_fec_enable_rx(s);
+    mcf_fec_update(s);
+}
+
+static CPUReadMemoryFunc *mcf_fec_readfn[] = {
+   mcf_fec_read,
+   mcf_fec_read,
+   mcf_fec_read
+};
+
+static CPUWriteMemoryFunc *mcf_fec_writefn[] = {
+   mcf_fec_write,
+   mcf_fec_write,
+   mcf_fec_write
+};
+
+void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq)
+{
+    mcf_fec_state *s;
+    int iomemtype;
+
+    s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state));
+    s->irq = irq;
+    iomemtype = cpu_register_io_memory(0, mcf_fec_readfn,
+                                       mcf_fec_writefn, s);
+    cpu_register_physical_memory(base, 0x400, iomemtype);
+
+    s->vc = qemu_new_vlan_client(nd->vlan, mcf_fec_receive,
+                                 mcf_fec_can_receive, s);
+    memcpy(s->macaddr, nd->macaddr, 6);
+}
diff --git a/hw/mcf_intc.c b/hw/mcf_intc.c
new file mode 100644
index 0000000..e469c31
--- /dev/null
+++ b/hw/mcf_intc.c
@@ -0,0 +1,156 @@
+/*
+ * ColdFire Interrupt Controller emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licenced under the GPL
+ */
+#include "vl.h"
+
+typedef struct {
+    uint64_t ipr;
+    uint64_t imr;
+    uint64_t ifr;
+    uint64_t enabled;
+    uint8_t icr[64];
+    CPUState *env;
+    int active_vector;
+} mcf_intc_state;
+
+static void mcf_intc_update(mcf_intc_state *s)
+{
+    uint64_t active;
+    int i;
+    int best;
+    int best_level;
+
+    active = (s->ipr | s->ifr) & s->enabled & ~s->imr;
+    best_level = 0;
+    best = 64;
+    if (active) {
+        for (i = 0; i < 64; i++) {
+            if ((active & 1) != 0 && s->icr[i] >= best_level) {
+                best_level = s->icr[i];
+                best = i;
+            }
+            active >>= 1;
+        }
+    }
+    s->active_vector = ((best == 64) ? 24 : (best + 64));
+    m68k_set_irq_level(s->env, best_level, s->active_vector);
+}
+
+static uint32_t mcf_intc_read(void *opaque, target_phys_addr_t addr)
+{
+    int offset;
+    mcf_intc_state *s = (mcf_intc_state *)opaque;
+    offset = addr & 0xff;
+    if (offset >= 0x40 && offset < 0x80) {
+        return s->icr[offset - 0x40];
+    }
+    switch (offset) {
+    case 0x00:
+        return (uint32_t)(s->ipr >> 32);
+    case 0x04:
+        return (uint32_t)s->ipr;
+    case 0x08:
+        return (uint32_t)(s->imr >> 32);
+    case 0x0c:
+        return (uint32_t)s->imr;
+    case 0x10:
+        return (uint32_t)(s->ifr >> 32);
+    case 0x14:
+        return (uint32_t)s->ifr;
+    case 0xe0: /* SWIACK.  */
+        return s->active_vector;
+    case 0xe1: case 0xe2: case 0xe3: case 0xe4:
+    case 0xe5: case 0xe6: case 0xe7:
+        /* LnIACK */
+        cpu_abort(cpu_single_env, "mcf_intc_read: LnIACK not implemented\n");
+    default:
+        return 0;
+    }
+}
+
+static void mcf_intc_write(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    int offset;
+    mcf_intc_state *s = (mcf_intc_state *)opaque;
+    offset = addr & 0xff;
+    if (offset >= 0x40 && offset < 0x80) {
+        int n = offset - 0x40;
+        s->icr[n] = val;
+        if (val == 0)
+            s->enabled &= ~(1ull << n);
+        else
+            s->enabled |= (1ull << n);
+        mcf_intc_update(s);
+        return;
+    }
+    switch (offset) {
+    case 0x00: case 0x04:
+        /* Ignore IPR writes.  */
+        return;
+    case 0x08:
+        s->imr = (s->imr & 0xffffffff) | ((uint64_t)val << 32);
+        break;
+    case 0x0c:
+        s->imr = (s->imr & 0xffffffff00000000ull) | (uint32_t)val;
+        break;
+    default:
+        cpu_abort(cpu_single_env, "mcf_intc_write: Bad write offset %d\n",
+                  offset);
+        break;
+    }
+    mcf_intc_update(s);
+}
+
+static void mcf_intc_set_irq(void *opaque, int irq, int level)
+{
+    mcf_intc_state *s = (mcf_intc_state *)opaque;
+    if (irq >= 64)
+        return;
+    if (level)
+        s->ipr |= 1ull << irq;
+    else
+        s->ipr &= ~(1ull << irq);
+    mcf_intc_update(s);
+}
+
+static void mcf_intc_reset(mcf_intc_state *s)
+{
+    s->imr = ~0ull;
+    s->ipr = 0;
+    s->ifr = 0;
+    s->enabled = 0;
+    memset(s->icr, 0, 64);
+    s->active_vector = 24;
+}
+
+static CPUReadMemoryFunc *mcf_intc_readfn[] = {
+   mcf_intc_read,
+   mcf_intc_read,
+   mcf_intc_read
+};
+
+static CPUWriteMemoryFunc *mcf_intc_writefn[] = {
+   mcf_intc_write,
+   mcf_intc_write,
+   mcf_intc_write
+};
+
+qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env)
+{
+    mcf_intc_state *s;
+    int iomemtype;
+
+    s = qemu_mallocz(sizeof(mcf_intc_state));
+    s->env = env;
+    mcf_intc_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, mcf_intc_readfn,
+                                       mcf_intc_writefn, s);
+    cpu_register_physical_memory(base, 0x100, iomemtype);
+
+    return qemu_allocate_irqs(mcf_intc_set_irq, s, 64);
+}
diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c
new file mode 100644
index 0000000..ab0f54f
--- /dev/null
+++ b/hw/mcf_uart.c
@@ -0,0 +1,306 @@
+/*
+ * ColdFire UART emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licenced under the GPL
+ */
+#include "vl.h"
+
+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;
+} mcf_uart_state;
+
+/* UART Status Register bits.  */
+#define MCF_UART_RxRDY  0x01
+#define MCF_UART_FFULL  0x02
+#define MCF_UART_TxRDY  0x04
+#define MCF_UART_TxEMP  0x08
+#define MCF_UART_OE     0x10
+#define MCF_UART_PE     0x20
+#define MCF_UART_FE     0x40
+#define MCF_UART_RB     0x80
+
+/* Interrupt flags.  */
+#define MCF_UART_TxINT  0x01
+#define MCF_UART_RxINT  0x02
+#define MCF_UART_DBINT  0x04
+#define MCF_UART_COSINT 0x80
+
+/* UMR1 flags.  */
+#define MCF_UART_BC0    0x01
+#define MCF_UART_BC1    0x02
+#define MCF_UART_PT     0x04
+#define MCF_UART_PM0    0x08
+#define MCF_UART_PM1    0x10
+#define MCF_UART_ERR    0x20
+#define MCF_UART_RxIRQ  0x40
+#define MCF_UART_RxRTS  0x80
+
+static void mcf_uart_update(mcf_uart_state *s)
+{
+    s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT);
+    if (s->sr & MCF_UART_TxRDY)
+        s->isr |= MCF_UART_TxINT;
+    if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ)
+                  ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0)
+        s->isr |= MCF_UART_RxINT;
+
+    qemu_set_irq(s->irq, (s->isr & s->imr) != 0);
+}
+
+uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+    switch (addr & 0x3f) {
+    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 &= ~MCF_UART_FFULL;
+            if (s->fifo_len == 0)
+                s->sr &= ~MCF_UART_RxRDY;
+            mcf_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 mcf_uart_do_tx(mcf_uart_state *s)
+{
+    if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) {
+        if (s->chr)
+            qemu_chr_write(s->chr, (unsigned char *)&s->tb, 1);
+        s->sr |= MCF_UART_TxEMP;
+    }
+    if (s->tx_enabled) {
+        s->sr |= MCF_UART_TxRDY;
+    } else {
+        s->sr &= ~MCF_UART_TxRDY;
+    }
+}
+
+static void mcf_do_command(mcf_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 &= ~(MCF_UART_RxRDY | MCF_UART_FFULL);
+        break;
+    case 3: /* Reset transmitter.  */
+        s->tx_enabled = 0;
+        s->sr |= MCF_UART_TxEMP;
+        s->sr &= ~MCF_UART_TxRDY;
+        break;
+    case 4: /* Reset error status.  */
+        break;
+    case 5: /* Reset break-change interrupt.  */
+        s->isr &= ~MCF_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;
+        mcf_uart_do_tx(s);
+        break;
+    case 2: /* Disable.  */
+        s->tx_enabled = 0;
+        mcf_uart_do_tx(s);
+        break;
+    case 3: /* Reserved.  */
+        fprintf(stderr, "mcf_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, "mcf_uart: Bad RX command\n");
+        break;
+    }
+}
+
+void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+    switch (addr & 0x3f) {
+    case 0x00:
+        s->mr[s->current_mr] = val;
+        s->current_mr = 1;
+        break;
+    case 0x04:
+        /* CSR is ignored.  */
+        break;
+    case 0x08: /* Command Register.  */
+        mcf_do_command(s, val);
+        break;
+    case 0x0c: /* Transmit Buffer.  */
+        s->sr &= ~MCF_UART_TxEMP;
+        s->tb = val;
+        mcf_uart_do_tx(s);
+        break;
+    case 0x10:
+        /* ACR is ignored.  */
+        break;
+    case 0x14:
+        s->imr = val;
+        break;
+    default:
+        break;
+    }
+    mcf_uart_update(s);
+}
+
+static void mcf_uart_reset(mcf_uart_state *s)
+{
+    s->fifo_len = 0;
+    s->mr[0] = 0;
+    s->mr[1] = 0;
+    s->sr = MCF_UART_TxEMP;
+    s->tx_enabled = 0;
+    s->rx_enabled = 0;
+    s->isr = 0;
+    s->imr = 0;
+}
+
+static void mcf_uart_push_byte(mcf_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 |= MCF_UART_RxRDY;
+    if (s->fifo_len == 4)
+        s->sr |= MCF_UART_FFULL;
+
+    mcf_uart_update(s);
+}
+
+static void mcf_uart_event(void *opaque, int event)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    switch (event) {
+    case CHR_EVENT_BREAK:
+        s->isr |= MCF_UART_DBINT;
+        mcf_uart_push_byte(s, 0);
+        break;
+    default:
+        break;
+    }
+}
+
+static int mcf_uart_can_receive(void *opaque)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0;
+}
+
+static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size)
+{
+    mcf_uart_state *s = (mcf_uart_state *)opaque;
+
+    mcf_uart_push_byte(s, buf[0]);
+}
+
+void *mcf_uart_init(qemu_irq irq, CharDriverState *chr)
+{
+    mcf_uart_state *s;
+
+    s = qemu_mallocz(sizeof(mcf_uart_state));
+    s->chr = chr;
+    s->irq = irq;
+    if (chr) {
+        qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive,
+                              mcf_uart_event, s);
+    }
+    mcf_uart_reset(s);
+    return s;
+}
+
+
+static CPUReadMemoryFunc *mcf_uart_readfn[] = {
+   mcf_uart_read,
+   mcf_uart_read,
+   mcf_uart_read
+};
+
+static CPUWriteMemoryFunc *mcf_uart_writefn[] = {
+   mcf_uart_write,
+   mcf_uart_write,
+   mcf_uart_write
+};
+
+void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
+                      CharDriverState *chr)
+{
+    mcf_uart_state *s;
+    int iomemtype;
+
+    s = mcf_uart_init(irq, chr);
+    iomemtype = cpu_register_io_memory(0, mcf_uart_readfn,
+                                       mcf_uart_writefn, s);
+    cpu_register_physical_memory(base, 0x40, iomemtype);
+}
diff --git a/hw/mips_int.c b/hw/mips_int.c
index 93d599f..f4e22dc 100644
--- a/hw/mips_int.c
+++ b/hw/mips_int.c
@@ -5,35 +5,40 @@
    IRQ may change */
 void cpu_mips_update_irq(CPUState *env)
 {
-    if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
-        (env->CP0_Status & (1 << CP0St_IE)) &&
-        !(env->hflags & MIPS_HFLAG_EXL) &&
-	!(env->hflags & MIPS_HFLAG_ERL) &&
-	!(env->hflags & MIPS_HFLAG_DM)) {
-        if (! (env->interrupt_request & CPU_INTERRUPT_HARD)) {
+    if ((env->CP0_Status & (1 << CP0St_IE)) &&
+        !(env->CP0_Status & (1 << CP0St_EXL)) &&
+        !(env->CP0_Status & (1 << CP0St_ERL)) &&
+        !(env->hflags & MIPS_HFLAG_DM)) {
+        if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
+            !(env->interrupt_request & CPU_INTERRUPT_HARD)) {
             cpu_interrupt(env, CPU_INTERRUPT_HARD);
 	}
-    } else {
+    } else
         cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-    }
 }
 
-void cpu_mips_irq_request(void *opaque, int irq, int level)
+static void cpu_mips_irq_request(void *opaque, int irq, int level)
 {
-    CPUState *env = first_cpu;
-   
-    uint32_t mask;
+    CPUState *env = (CPUState *)opaque;
 
-    if (irq >= 16)
+    if (irq < 0 || irq > 7)
         return;
 
-    mask = 1 << (irq + CP0Ca_IP);
-
     if (level) {
-        env->CP0_Cause |= mask;
+        env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
     } else {
-        env->CP0_Cause &= ~mask;
+        env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
     }
     cpu_mips_update_irq(env);
 }
 
+void cpu_mips_irq_init_cpu(CPUState *env)
+{
+    qemu_irq *qi;
+    int i;
+
+    qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8);
+    for (i = 0; i < 8; i++) {
+        env->irq[i] = qi[i];
+    }
+}
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index 029e18e..3b37596 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -30,40 +30,35 @@
 #define BIOS_FILENAME "mipsel_bios.bin"
 #endif
 
-#ifdef MIPS_HAS_MIPS64
-#define INITRD_LOAD_ADDR 	(int64_t)0x80800000
+#ifdef TARGET_MIPS64
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
 #else
-#define INITRD_LOAD_ADDR 	(int32_t)0x80800000
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
 #endif
 
-#define ENVP_ADDR        	(int32_t)0x80002000
-#define VIRT_TO_PHYS_ADDEND 	(-((int64_t)(int32_t)0x80000000))
+#define ENVP_ADDR (int32_t)0x80002000
+#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
 
 #define ENVP_NB_ENTRIES	 	16
 #define ENVP_ENTRY_SIZE	 	256
 
-
 extern FILE *logfile;
 
 typedef struct {
     uint32_t leds;
     uint32_t brk;
     uint32_t gpout;
+    uint32_t i2cin;
     uint32_t i2coe;
     uint32_t i2cout;
     uint32_t i2csel;
     CharDriverState *display;
     char display_text[9];
+    SerialState *uart;
 } MaltaFPGAState;
 
 static PITState *pit;
 
-/* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
-static void pic_irq_request(void *opaque, int level)
-{
-    cpu_mips_irq_request(opaque, 2, level);
-}
-
 /* Malta FPGA */
 static void malta_fpga_update_display(void *opaque)
 {
@@ -74,7 +69,7 @@
     for (i = 7 ; i >= 0 ; i--) {
         if (s->leds & (1 << i))
             leds_text[i] = '#';
-	else
+        else
             leds_text[i] = ' ';
     }
     leds_text[8] = '\0';
@@ -83,6 +78,124 @@
     qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
 }
 
+/*
+ * EEPROM 24C01 / 24C02 emulation.
+ *
+ * Emulation for serial EEPROMs:
+ * 24C01 - 1024 bit (128 x 8)
+ * 24C02 - 2048 bit (256 x 8)
+ *
+ * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
+ */
+
+//~ #define DEBUG
+
+#if defined(DEBUG)
+#  define logout(fmt, args...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ##args)
+#else
+#  define logout(fmt, args...) ((void)0)
+#endif
+
+struct _eeprom24c0x_t {
+  uint8_t tick;
+  uint8_t address;
+  uint8_t command;
+  uint8_t ack;
+  uint8_t scl;
+  uint8_t sda;
+  uint8_t data;
+  //~ uint16_t size;
+  uint8_t contents[256];
+};
+
+typedef struct _eeprom24c0x_t eeprom24c0x_t;
+
+static eeprom24c0x_t eeprom = {
+    contents: {
+        /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
+        /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
+        /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
+        /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
+        /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
+        /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
+        /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+        /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
+    },
+};
+
+static uint8_t eeprom24c0x_read()
+{
+    logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
+        eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
+    return eeprom.sda;
+}
+
+static void eeprom24c0x_write(int scl, int sda)
+{
+    if (eeprom.scl && scl && (eeprom.sda != sda)) {
+        logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
+        if (!sda) {
+            eeprom.tick = 1;
+            eeprom.command = 0;
+        }
+    } else if (eeprom.tick == 0 && !eeprom.ack) {
+        /* Waiting for start. */
+        logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+    } else if (!eeprom.scl && scl) {
+        logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
+                eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+        if (eeprom.ack) {
+            logout("\ti2c ack bit = 0\n");
+            sda = 0;
+            eeprom.ack = 0;
+        } else if (eeprom.sda == sda) {
+            uint8_t bit = (sda != 0);
+            logout("\ti2c bit = %d\n", bit);
+            if (eeprom.tick < 9) {
+                eeprom.command <<= 1;
+                eeprom.command += bit;
+                eeprom.tick++;
+                if (eeprom.tick == 9) {
+                    logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
+                    eeprom.ack = 1;
+                }
+            } else if (eeprom.tick < 17) {
+                if (eeprom.command & 1) {
+                    sda = ((eeprom.data & 0x80) != 0);
+                }
+                eeprom.address <<= 1;
+                eeprom.address += bit;
+                eeprom.tick++;
+                eeprom.data <<= 1;
+                if (eeprom.tick == 17) {
+                    eeprom.data = eeprom.contents[eeprom.address];
+                    logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
+                    eeprom.ack = 1;
+                    eeprom.tick = 0;
+                }
+            } else if (eeprom.tick >= 17) {
+                sda = 0;
+            }
+        } else {
+            logout("\tsda changed with raising scl\n");
+        }
+    } else {
+        logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+    }
+    eeprom.scl = scl;
+    eeprom.sda = sda;
+}
+
 static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
 {
     MaltaFPGAState *s = opaque;
@@ -122,6 +235,8 @@
         val = s->brk;
         break;
 
+    /* UART Registers are handled directly by the serial device */
+
     /* GPOUT Register */
     case 0x00a00:
         val = s->gpout;
@@ -140,7 +255,7 @@
 
     /* I2CINP Register */
     case 0x00b00:
-        val = 0x00000003;
+        val = ((s->i2cin & ~1) | eeprom24c0x_read());
         break;
 
     /* I2COE Register */
@@ -155,12 +270,12 @@
 
     /* I2CSEL Register */
     case 0x00b18:
-        val = s->i2cout;
+        val = s->i2csel;
         break;
 
     default:
 #if 0
-        printf ("malta_fpga_read: Bad register offset 0x" TLSZ "\n",
+        printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
 		addr);
 #endif
         break;
@@ -222,6 +337,8 @@
         s->brk = val & 0xff;
         break;
 
+    /* UART Registers are handled directly by the serial device */
+
     /* GPOUT Register */
     case 0x00a00:
         s->gpout = val & 0xff;
@@ -234,17 +351,18 @@
 
     /* I2COUT Register */
     case 0x00b10:
-        s->i2cout = val & 0x03;
+        eeprom24c0x_write(val & 0x02, val & 0x01);
+        s->i2cout = val;
         break;
 
     /* I2CSEL Register */
     case 0x00b18:
-        s->i2cout = val & 0x01;
+        s->i2csel = val & 0x01;
         break;
 
     default:
 #if 0
-        printf ("malta_fpga_write: Bad register offset 0x" TLSZ "\n",
+        printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
 		addr);
 #endif
         break;
@@ -270,6 +388,7 @@
     s->leds   = 0x00;
     s->brk    = 0x0a;
     s->gpout  = 0x00;
+    s->i2cin  = 0x3;
     s->i2coe  = 0x0;
     s->i2cout = 0x3;
     s->i2csel = 0x1;
@@ -279,16 +398,19 @@
     malta_fpga_update_display(s);
 }
 
-MaltaFPGAState *malta_fpga_init(target_phys_addr_t base)
+MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env)
 {
     MaltaFPGAState *s;
+    CharDriverState *uart_chr;
     int malta;
 
     s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
 
     malta = cpu_register_io_memory(0, malta_fpga_read,
                                    malta_fpga_write, s);
-    cpu_register_physical_memory(base, 0x100000, malta);
+
+    cpu_register_physical_memory(base, 0x900, malta);
+    cpu_register_physical_memory(base + 0xa00, 0x100000 - 0xa00, malta);
 
     s->display = qemu_chr_open("vc");
     qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
@@ -301,6 +423,10 @@
     qemu_chr_printf(s->display, "+        +\r\n");
     qemu_chr_printf(s->display, "+--------+\r\n");
 
+    uart_chr = qemu_chr_open("vc");
+    qemu_chr_printf(uart_chr, "CBUS UART\r\n");
+    s->uart = serial_mm_init(base + 0x900, 3, env->irq[2], uart_chr, 1);
+
     malta_fpga_reset(s);
     qemu_register_reset(malta_fpga_reset, s);
 
@@ -324,17 +450,8 @@
         s = AUD_init ();
         if (s) {
             for (c = soundhw; c->name; ++c) {
-                if (c->enabled) {
-                    if (c->isa) {
-                        fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name);
-                        exit(1);
-                    }
-                    else {
-                        if (pci_bus) {
-                            c->init.init_pci (pci_bus, s);
-                        }
-                    }
-                }
+                if (c->enabled)
+                    c->init.init_pci (pci_bus, s);
             }
         }
     }
@@ -383,29 +500,143 @@
      a3 - RAM size in bytes
 */
 
-static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_addr)
+static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry)
 {
     uint32_t *p;
 
     /* Small bootloader */
     p = (uint32_t *) (phys_ram_base + bios_offset);
-    stl_raw(p++, 0x0bf00010);                                      /* j 0x1fc00040 */
+    stl_raw(p++, 0x0bf00160);                                      /* j 0x1fc00580 */
     stl_raw(p++, 0x00000000);                                      /* nop */
 
+    /* YAMON service vector */
+    stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580);      /* start: */
+    stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c);      /* print_count: */
+    stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580);      /* start: */
+    stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800);      /* flush_cache: */
+    stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808);      /* print: */
+    stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800);      /* reg_cpu_isr: */
+    stl_raw(phys_ram_base + bios_offset + 0x53c, 0xbfc00800);      /* unred_cpu_isr: */
+    stl_raw(phys_ram_base + bios_offset + 0x540, 0xbfc00800);      /* reg_ic_isr: */
+    stl_raw(phys_ram_base + bios_offset + 0x544, 0xbfc00800);      /* unred_ic_isr: */
+    stl_raw(phys_ram_base + bios_offset + 0x548, 0xbfc00800);      /* reg_esr: */
+    stl_raw(phys_ram_base + bios_offset + 0x54c, 0xbfc00800);      /* unreg_esr: */
+    stl_raw(phys_ram_base + bios_offset + 0x550, 0xbfc00800);      /* getchar: */
+    stl_raw(phys_ram_base + bios_offset + 0x554, 0xbfc00800);      /* syscon_read: */
+
+
     /* Second part of the bootloader */
-    p = (uint32_t *) (phys_ram_base + bios_offset + 0x040);
-    stl_raw(p++, 0x3c040000);                                      /* lui a0, 0 */
-    stl_raw(p++, 0x34840002);                                      /* ori a0, a0, 2 */
+    p = (uint32_t *) (phys_ram_base + bios_offset + 0x580);
+    stl_raw(p++, 0x24040002);                                      /* addiu a0, zero, 2 */
+    stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
+    stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff));        /* ori sp, sp, low(ENVP_ADDR) */
     stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff));       /* lui a1, high(ENVP_ADDR) */
-    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a0, low(ENVP_ADDR) */
+    stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff));               /* ori a1, a1, low(ENVP_ADDR) */
     stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
     stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff));         /* ori a2, a2, low(ENVP_ADDR + 8) */
     stl_raw(p++, 0x3c070000 | (env->ram_size >> 16));              /* lui a3, high(env->ram_size) */
     stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff));           /* ori a3, a3, low(env->ram_size) */
-    stl_raw(p++, 0x3c1f0000 | ((kernel_addr >> 16) & 0xffff));     /* lui ra, high(kernel_addr) */;
-    stl_raw(p++, 0x37ff0000 | (kernel_addr & 0xffff));             /* ori ra, ra, low(kernel_addr) */
+
+    /* Load BAR registers as done by YAMON */
+    stl_raw(p++, 0x3c09b400);                                      /* lui t1, 0xb400 */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08df00);                                      /* lui t0, 0xdf00 */
+#else
+    stl_raw(p++, 0x340800df);                                      /* ori t0, r0, 0x00df */
+#endif
+    stl_raw(p++, 0xad280068);                                      /* sw t0, 0x0068(t1) */
+
+    stl_raw(p++, 0x3c09bbe0);                                      /* lui t1, 0xbbe0 */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08c000);                                      /* lui t0, 0xc000 */
+#else
+    stl_raw(p++, 0x340800c0);                                      /* ori t0, r0, 0x00c0 */
+#endif
+    stl_raw(p++, 0xad280048);                                      /* sw t0, 0x0048(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c084000);                                      /* lui t0, 0x4000 */
+#else
+    stl_raw(p++, 0x34080040);                                      /* ori t0, r0, 0x0040 */
+#endif
+    stl_raw(p++, 0xad280050);                                      /* sw t0, 0x0050(t1) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c088000);                                      /* lui t0, 0x8000 */
+#else
+    stl_raw(p++, 0x34080080);                                      /* ori t0, r0, 0x0080 */
+#endif
+    stl_raw(p++, 0xad280058);                                      /* sw t0, 0x0058(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c083f00);                                      /* lui t0, 0x3f00 */
+#else
+    stl_raw(p++, 0x3408003f);                                      /* ori t0, r0, 0x003f */
+#endif
+    stl_raw(p++, 0xad280060);                                      /* sw t0, 0x0060(t1) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c08c100);                                      /* lui t0, 0xc100 */
+#else
+    stl_raw(p++, 0x340800c1);                                      /* ori t0, r0, 0x00c1 */
+#endif
+    stl_raw(p++, 0xad280080);                                      /* sw t0, 0x0080(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+    stl_raw(p++, 0x3c085e00);                                      /* lui t0, 0x5e00 */
+#else
+    stl_raw(p++, 0x3408005e);                                      /* ori t0, r0, 0x005e */
+#endif
+    stl_raw(p++, 0xad280088);                                      /* sw t0, 0x0088(t1) */
+
+    /* Jump to kernel code */
+    stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff));    /* lui ra, high(kernel_entry) */
+    stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff));            /* ori ra, ra, low(kernel_entry) */
     stl_raw(p++, 0x03e00008);                                      /* jr ra */
     stl_raw(p++, 0x00000000);                                      /* nop */
+
+    /* YAMON subroutines */
+    p = (uint32_t *) (phys_ram_base + bios_offset + 0x800);
+    stl_raw(p++, 0x03e00008);                                     /* jr ra */
+    stl_raw(p++, 0x24020000);                                     /* li v0,0 */
+   /* 808 YAMON print */
+    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
+    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
+    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
+    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
+    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
+    stl_raw(p++, 0x10800005);                                     /* beqz a0,834 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x08000205);                                     /* j 814 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
+    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
+    /* 0x83c YAMON print_count */
+    stl_raw(p++, 0x03e06821);                                     /* move t5,ra */
+    stl_raw(p++, 0x00805821);                                     /* move t3,a0 */
+    stl_raw(p++, 0x00a05021);                                     /* move t2,a1 */
+    stl_raw(p++, 0x00c06021);                                     /* move t4,a2 */
+    stl_raw(p++, 0x91440000);                                     /* lbu a0,0(t2) */
+    stl_raw(p++, 0x0ff0021c);                                     /* jal 870 */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x254a0001);                                     /* addiu t2,t2,1 */
+    stl_raw(p++, 0x258cffff);                                     /* addiu t4,t4,-1 */
+    stl_raw(p++, 0x1580fffa);                                     /* bnez t4,84c */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x01a00008);                                     /* jr t5 */
+    stl_raw(p++, 0x01602021);                                     /* move a0,t3 */
+    /* 0x870 */
+    stl_raw(p++, 0x3c08b800);                                     /* lui t0,0xb400 */
+    stl_raw(p++, 0x350803f8);                                     /* ori t0,t0,0x3f8 */
+    stl_raw(p++, 0x91090005);                                     /* lbu t1,5(t0) */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x31290040);                                     /* andi t1,t1,0x40 */
+    stl_raw(p++, 0x1120fffc);                                     /* beqz t1,878 <outch+0x8> */
+    stl_raw(p++, 0x00000000);                                     /* nop */
+    stl_raw(p++, 0x03e00008);                                     /* jr ra */
+    stl_raw(p++, 0xa1040000);                                     /* sb a0,0(t0) */
+
 }
 
 static void prom_set(int index, const char *string, ...)
@@ -439,21 +670,34 @@
 /* Kernel */
 static int64_t load_kernel (CPUState *env)
 {
-    int64_t kernel_addr = 0;
+    int64_t kernel_entry, kernel_low, kernel_high;
     int index = 0;
     long initrd_size;
+    ram_addr_t initrd_offset;
 
-    if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND, &kernel_addr) < 0) {
+    if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND,
+                 &kernel_entry, &kernel_low, &kernel_high) < 0) {
         fprintf(stderr, "qemu: could not load kernel '%s'\n",
                 env->kernel_filename);
-      exit(1);
+        exit(1);
     }
 
     /* load initrd */
     initrd_size = 0;
+    initrd_offset = 0;
     if (env->initrd_filename) {
-        initrd_size = load_image(env->initrd_filename,
-                                 phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
+        initrd_size = get_image_size (env->initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > env->ram_size) {
+                fprintf(stderr,
+                        "qemu: memory too small for initial ram disk '%s'\n",
+                        env->initrd_filename);
+                exit(1);
+            }
+            initrd_size = load_image(env->initrd_filename,
+                                     phys_ram_base + initrd_offset);
+        }
         if (initrd_size == (target_ulong) -1) {
             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                     env->initrd_filename);
@@ -464,7 +708,9 @@
     /* Store command line.  */
     prom_set(index++, env->kernel_filename);
     if (initrd_size > 0)
-        prom_set(index++, "rd_start=0x" TLSZ " rd_size=%li %s", INITRD_LOAD_ADDR, initrd_size, env->kernel_cmdline);
+        prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
+                 PHYS_TO_VIRT(initrd_offset), initrd_size,
+                 env->kernel_cmdline);
     else
         prom_set(index++, env->kernel_cmdline);
 
@@ -475,37 +721,58 @@
     prom_set(index++, "38400n8r");
     prom_set(index++, NULL);
 
-    return kernel_addr;
+    return kernel_entry;
 }
 
 static void main_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
     cpu_reset(env);
+    cpu_mips_register(env, NULL);
 
     /* The bootload does not need to be rewritten as it is located in a
        read only location. The kernel location and the arguments table
        location does not change. */
-    if (env->kernel_filename)
+    if (env->kernel_filename) {
+        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
         load_kernel (env);
+    }
 }
 
+static
 void mips_malta_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 *initrd_filename, const char *cpu_model)
 {
     char buf[1024];
     unsigned long bios_offset;
-    int64_t kernel_addr;
+    int64_t kernel_entry;
     PCIBus *pci_bus;
     CPUState *env;
     RTCState *rtc_state;
     /* fdctrl_t *floppy_controller; */
     MaltaFPGAState *malta_fpga;
     int ret;
+    mips_def_t *def;
+    qemu_irq *i8259;
+    int piix4_devfn;
+    uint8_t *eeprom_buf;
+    i2c_bus *smbus;
+    int i;
 
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "20Kc";
+#else
+        cpu_model = "24Kf";
+#endif
+    }
+    if (mips_find_by_name(cpu_model, &def) != 0)
+        def = NULL;
     env = cpu_init();
+    cpu_mips_register(env, def);
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
     qemu_register_reset(main_cpu_reset, env);
 
@@ -519,24 +786,43 @@
     cpu_register_physical_memory(0x1fc00000LL,
                                  BIOS_SIZE, bios_offset | IO_MEM_ROM);
 
-    /* Load a BIOS image except if a kernel image has been specified. In
-       the later case, just write a small bootloader to the flash
-       location. */
+    /* FPGA */
+    malta_fpga = malta_fpga_init(0x1f000000LL, env);
+
+    /* Load a BIOS image unless a kernel image has been specified. */
+    if (!kernel_filename) {
+        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+        ret = load_image(buf, phys_ram_base + bios_offset);
+        if (ret < 0 || ret > BIOS_SIZE) {
+            fprintf(stderr,
+                    "qemu: Could not load MIPS bios '%s', and no -kernel argument was specified\n",
+                    buf);
+            exit(1);
+        }
+        /* In little endian mode the 32bit words in the bios are swapped,
+           a neat trick which allows bi-endian firmware. */
+#ifndef TARGET_WORDS_BIGENDIAN
+        {
+            uint32_t *addr;
+            for (addr = (uint32_t *)(phys_ram_base + bios_offset);
+                 addr < (uint32_t *)(phys_ram_base + bios_offset + ret);
+		 addr++) {
+                *addr = bswap32(*addr);
+            }
+        }
+#endif
+    }
+
+    /* If a kernel image has been specified, write a small bootloader
+       to the flash location. */
     if (kernel_filename) {
         env->ram_size = ram_size;
         env->kernel_filename = kernel_filename;
         env->kernel_cmdline = kernel_cmdline;
         env->initrd_filename = initrd_filename;
-        kernel_addr = load_kernel(env);
-        write_bootloader(env, bios_offset, kernel_addr);
-    } else {
-        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
-        ret = load_image(buf, phys_ram_base + bios_offset);
-        if (ret != BIOS_SIZE) {
-            fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
-                    buf);
-            exit(1);
-        }
+        kernel_entry = load_kernel(env);
+        env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+        write_bootloader(env, bios_offset, kernel_entry);
     }
 
     /* Board ID = 0x420 (Malta Board with CoreLV)
@@ -545,34 +831,42 @@
     stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
 
     /* Init internal devices */
+    cpu_mips_irq_init_cpu(env);
     cpu_mips_clock_init(env);
     cpu_mips_irqctrl_init();
 
-    /* FPGA */
-    malta_fpga = malta_fpga_init(0x1f000000LL);
-
     /* Interrupt controller */
-    isa_pic = pic_init(pic_irq_request, env);
+    /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
+    i8259 = i8259_init(env->irq[2]);
 
     /* Northbridge */
-    pci_bus = pci_gt64120_init(isa_pic);
+    pci_bus = pci_gt64120_init(i8259);
 
     /* Southbridge */
-    piix4_init(pci_bus, 80);
-    pci_piix3_ide_init(pci_bus, bs_table, 81);
-    usb_uhci_init(pci_bus, 82);
-    piix4_pm_init(pci_bus, 83);
-    pit = pit_init(0x40, 0);
+    piix4_devfn = piix4_init(pci_bus, 80);
+    pci_piix4_ide_init(pci_bus, bs_table, piix4_devfn + 1, i8259);
+    usb_uhci_piix4_init(pci_bus, piix4_devfn + 2);
+    smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100);
+    eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+    for (i = 0; i < 8; i++) {
+        /* TODO: Populate SPD eeprom data.  */
+        smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));
+    }
+    pit = pit_init(0x40, i8259[0]);
     DMA_init(0);
 
     /* Super I/O */
-    kbd_init();
-    rtc_state = rtc_init(0x70, 8);
-    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
-    parallel_init(0x378, 7, parallel_hds[0]);
+    i8042_init(i8259[1], i8259[12], 0x60);
+    rtc_state = rtc_init(0x70, i8259[8]);
+    if (serial_hds[0])
+        serial_init(0x3f8, i8259[4], serial_hds[0]);
+    if (serial_hds[1])
+        serial_init(0x2f8, i8259[3], serial_hds[1]);
+    if (parallel_hds[0])
+        parallel_init(0x378, i8259[7], parallel_hds[0]);
     /* XXX: The floppy controller does not work correctly, something is
        probably wrong.
-    floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table); */
+    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); */
 
     /* Sound card */
 #ifdef HAS_AUDIO
@@ -581,6 +875,10 @@
 
     /* Network card */
     network_init(pci_bus);
+
+    /* Optional PCI video card */
+    pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size,
+                        ram_size, vga_ram_size);
 }
 
 QEMUMachine mips_malta_machine = {
diff --git a/hw/mips_pica61.c b/hw/mips_pica61.c
new file mode 100644
index 0000000..2c44150
--- /dev/null
+++ b/hw/mips_pica61.c
@@ -0,0 +1,180 @@
+/*
+ * QEMU Acer Pica Machine support
+ *
+ * Copyright (c) 2007 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define BIOS_FILENAME "mips_bios.bin"
+#else
+#define BIOS_FILENAME "mipsel_bios.bin"
+#endif
+
+#ifdef TARGET_MIPS64
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
+#else
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
+#endif
+
+#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
+
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
+static const int ide_irq[2] = { 14, 15 };
+
+static uint32_t serial_base[MAX_SERIAL_PORTS] = { 0x80006000, 0x80007000 };
+static int serial_irq[MAX_SERIAL_PORTS] = { 8, 9 };
+
+extern FILE *logfile;
+
+static void main_cpu_reset(void *opaque)
+{
+    CPUState *env = opaque;
+    cpu_reset(env);
+    cpu_mips_register(env, NULL);
+}
+
+static
+void mips_pica61_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)
+{
+    char buf[1024];
+    unsigned long bios_offset;
+    int bios_size;
+    CPUState *env;
+    int i;
+    mips_def_t *def;
+    int available_ram;
+    qemu_irq *i8259;
+
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "R4000";
+#else
+        /* FIXME: All wrong, this maybe should be R3000 for the older PICAs. */
+        cpu_model = "24Kf";
+#endif
+    }
+    if (mips_find_by_name(cpu_model, &def) != 0)
+        def = NULL;
+    env = cpu_init();
+    cpu_mips_register(env, def);
+    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+    qemu_register_reset(main_cpu_reset, env);
+
+    /* allocate RAM (limited to 256 MB) */
+    if (ram_size < 256 * 1024 * 1024)
+        available_ram = ram_size;
+    else
+        available_ram = 256 * 1024 * 1024;
+    cpu_register_physical_memory(0, available_ram, IO_MEM_RAM);
+
+    /* load a BIOS image */
+    bios_offset = ram_size + vga_ram_size;
+    snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+    bios_size = load_image(buf, phys_ram_base + bios_offset);
+    if ((bios_size <= 0) || (bios_size > BIOS_SIZE)) {
+        /* fatal */
+        fprintf(stderr, "qemu: Error, could not load MIPS bios '%s'\n",
+                buf);
+        exit(1);
+    }
+    cpu_register_physical_memory(0x1fc00000,
+                                     BIOS_SIZE, bios_offset | IO_MEM_ROM);
+
+    /* Device map
+     *
+     * addr 0xe0004000: mc146818
+     * addr 0xe0005000 intr 6: ps2 keyboard
+     * addr 0xe0005000 intr 7: ps2 mouse
+     * addr 0xe0006000 intr 8: ns16550a,
+     * addr 0xe0007000 intr 9: ns16550a
+     * isa_io_base 0xe2000000 isa_mem_base 0xe3000000
+     */
+
+    /* Init CPU internal devices */
+    cpu_mips_irq_init_cpu(env);
+    cpu_mips_clock_init(env);
+    cpu_mips_irqctrl_init();
+
+    /* Register 64 KB of ISA IO space at 0x10000000 */
+    isa_mmio_init(0x10000000, 0x00010000);
+    isa_mem_base = 0x11000000;
+
+    /* PC style IRQ (i8259/i8254) and DMA (i8257) */
+    /* The PIC is attached to the MIPS CPU INT0 pin */
+    i8259 = i8259_init(env->irq[2]);
+    rtc_mm_init(0x80004070, 1, i8259[14]);
+    pit_init(0x40, 0);
+
+    /* Keyboard (i8042) */
+    i8042_mm_init(i8259[6], i8259[7], 0x80005060, 0);
+
+    /* IDE controller */
+    for(i = 0; i < 2; i++)
+        isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
+                     bs_table[2 * i], bs_table[2 * i + 1]);
+
+    /* Network controller */
+    /* FIXME: missing NS SONIC DP83932 */
+
+    /* SCSI adapter */
+    /* FIXME: missing NCR 53C94 */
+
+    /* ISA devices (floppy, serial, parallel) */
+    fdctrl_init(i8259[1], 1, 1, 0x80003000, fd_table);
+    for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+        if (serial_hds[i]) {
+            serial_mm_init(serial_base[i], 0, i8259[serial_irq[i]], serial_hds[i], 1);
+        }
+    }
+    /* Parallel port */
+    if (parallel_hds[0]) parallel_mm_init(0x80008000, 0, i8259[1], parallel_hds[0]);
+
+    /* Sound card */
+    /* FIXME: missing Jazz sound, IRQ 18 */
+
+    /* LED indicator */
+    /* FIXME: missing LED indicator */
+
+    /* NVRAM */
+    ds1225y_init(0x80009000, "nvram");
+
+    /* Video card */
+    /* FIXME: This card is not the real one which was in the original PICA,
+     * but let's do with what Qemu currenly emulates... */
+    isa_vga_mm_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size,
+                    0x40000000, 0x60000000, 0);
+
+    /* LED indicator */
+    jazz_led_init(ds, 0x8000f000);
+}
+
+QEMUMachine mips_pica61_machine = {
+    "pica61",
+    "Acer Pica 61",
+    mips_pica61_init,
+};
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 8d1cac9..5769ade 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -15,10 +15,10 @@
 #define BIOS_FILENAME "mipsel_bios.bin"
 #endif
 
-#ifdef MIPS_HAS_MIPS64
-#define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000
+#ifdef TARGET_MIPS64
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
 #else
-#define INITRD_LOAD_ADDR (int32_t)0x80800000
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
 #endif
 
 #define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
@@ -35,11 +35,6 @@
 static PITState *pit; /* PIT i8254 */
 
 /*i8254 PIT is attached to the IRQ0 at PIC i8259 */
-/*The PIC is attached to the MIPS CPU INT0 pin */
-static void pic_irq_request(void *opaque, int level)
-{
-    cpu_mips_irq_request(opaque, 2, level);
-}
 
 static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
 			      uint32_t val)
@@ -73,14 +68,16 @@
 		  const char *kernel_cmdline,
 		  const char *initrd_filename)
 {
-    int64_t entry = 0;
+    int64_t entry, kernel_low, kernel_high;
     long kernel_size, initrd_size;
+    ram_addr_t initrd_offset;
 
-    kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
+    kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND,
+                           &entry, &kernel_low, &kernel_high);
     if (kernel_size >= 0) {
         if ((entry & ~0x7fffffffULL) == 0x80000000)
             entry = (int32_t)entry;
-        env->PC = entry;
+        env->PC[env->current_tc] = entry;
     } else {
         fprintf(stderr, "qemu: could not load kernel '%s'\n",
                 kernel_filename);
@@ -89,9 +86,20 @@
 
     /* load initrd */
     initrd_size = 0;
+    initrd_offset = 0;
     if (initrd_filename) {
-        initrd_size = load_image(initrd_filename,
-                                 phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
+        initrd_size = get_image_size (initrd_filename);
+        if (initrd_size > 0) {
+            initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+            if (initrd_offset + initrd_size > ram_size) {
+                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 == (target_ulong) -1) {
             fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                     initrd_filename);
@@ -103,8 +111,8 @@
     if (initrd_size > 0) {
         int ret;
         ret = sprintf(phys_ram_base + (16 << 20) - 256,
-                      "rd_start=0x" TLSZ " rd_size=%li ",
-                      INITRD_LOAD_ADDR,
+                      "rd_start=0x" TARGET_FMT_lx " rd_size=%li ",
+                      PHYS_TO_VIRT((uint32_t)initrd_offset),
                       initrd_size);
         strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
     }
@@ -120,25 +128,40 @@
 {
     CPUState *env = opaque;
     cpu_reset(env);
+    cpu_mips_register(env, NULL);
 
     if (env->kernel_filename)
         load_kernel (env, env->ram_size, env->kernel_filename,
                      env->kernel_cmdline, env->initrd_filename);
 }
 
+static
 void mips_r4k_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 *initrd_filename, const char *cpu_model)
 {
     char buf[1024];
     unsigned long bios_offset;
     int bios_size;
     CPUState *env;
-    static RTCState *rtc_state;
+    RTCState *rtc_state;
     int i;
+    mips_def_t *def;
+    qemu_irq *i8259;
 
+    /* init CPUs */
+    if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+        cpu_model = "R4000";
+#else
+        cpu_model = "24Kf";
+#endif
+    }
+    if (mips_find_by_name(cpu_model, &def) != 0)
+        def = NULL;
     env = cpu_init();
+    cpu_mips_register(env, def);
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
     qemu_register_reset(main_cpu_reset, env);
 
@@ -147,7 +170,7 @@
 
     if (!mips_qemu_iomemtype) {
         mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read,
-						     mips_qemu_write, NULL);
+                                                     mips_qemu_write, NULL);
     }
     cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
 
@@ -177,32 +200,37 @@
     }
 
     /* Init CPU internal devices */
+    cpu_mips_irq_init_cpu(env);
     cpu_mips_clock_init(env);
     cpu_mips_irqctrl_init();
 
-    rtc_state = rtc_init(0x70, 8);
+    /* The PIC is attached to the MIPS CPU INT0 pin */
+    i8259 = i8259_init(env->irq[2]);
+
+    rtc_state = rtc_init(0x70, i8259[8]);
 
     /* Register 64 KB of ISA IO space at 0x14000000 */
     isa_mmio_init(0x14000000, 0x00010000);
     isa_mem_base = 0x10000000;
 
-    isa_pic = pic_init(pic_irq_request, env);
-    pit = pit_init(0x40, 0);
+    pit = pit_init(0x40, i8259[0]);
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(&pic_set_irq_new, isa_pic,
-                        serial_io[i], serial_irq[i], serial_hds[i]);
+            serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]);
         }
     }
 
-    isa_vga_init(ds, phys_ram_base + ram_size, ram_size, 
+    isa_vga_init(ds, phys_ram_base + ram_size, ram_size,
                  vga_ram_size);
 
     if (nd_table[0].vlan) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
-            isa_ne2000_init(0x300, 9, &nd_table[0]);
+            isa_ne2000_init(0x300, i8259[9], &nd_table[0]);
+        } else if (strcmp(nd_table[0].model, "?") == 0) {
+            fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n");
+            exit (1);
         } else {
             fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
             exit (1);
@@ -210,8 +238,11 @@
     }
 
     for(i = 0; i < 2; i++)
-        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+        isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
                      bs_table[2 * i], bs_table[2 * i + 1]);
+
+    i8042_init(i8259[1], i8259[12], 0x60);
+    ds1225y_init(0x9000, "nvram");
 }
 
 QEMUMachine mips_machine = {
diff --git a/hw/mips_timer.c b/hw/mips_timer.c
index bc83036..b295bdb 100644
--- a/hw/mips_timer.c
+++ b/hw/mips_timer.c
@@ -10,23 +10,26 @@
     static uint32_t seed = 0;
     uint32_t idx;
     seed = seed * 314159 + 1;
-    idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
+    idx = (seed >> 16) % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
     return idx;
 }
 
 /* MIPS R4K timer */
 uint32_t cpu_mips_get_count (CPUState *env)
 {
-    return env->CP0_Count +
-        (uint32_t)muldiv64(qemu_get_clock(vm_clock),
-                           100 * 1000 * 1000, ticks_per_sec);
+    if (env->CP0_Cause & (1 << CP0Ca_DC))
+        return env->CP0_Count;
+    else
+        return env->CP0_Count +
+            (uint32_t)muldiv64(qemu_get_clock(vm_clock),
+                               100 * 1000 * 1000, ticks_per_sec);
 }
 
-static void cpu_mips_update_count (CPUState *env, uint32_t count,
-                                   uint32_t compare)
+void cpu_mips_store_count (CPUState *env, uint32_t count)
 {
     uint64_t now, next;
     uint32_t tmp;
+    uint32_t compare = env->CP0_Compare;
 
     tmp = count;
     if (count == compare)
@@ -49,15 +52,33 @@
     qemu_mod_timer(env->timer, next);
 }
 
-void cpu_mips_store_count (CPUState *env, uint32_t value)
+static void cpu_mips_update_count (CPUState *env, uint32_t count)
 {
-    cpu_mips_update_count(env, value, env->CP0_Compare);
+    if (env->CP0_Cause & (1 << CP0Ca_DC))
+        return;
+
+    cpu_mips_store_count(env, count);
 }
 
 void cpu_mips_store_compare (CPUState *env, uint32_t value)
 {
-    cpu_mips_update_count(env, cpu_mips_get_count(env), value);
-    cpu_mips_irq_request(env, 7, 0);
+    env->CP0_Compare = value;
+    cpu_mips_update_count(env, cpu_mips_get_count(env));
+    if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+        env->CP0_Cause &= ~(1 << CP0Ca_TI);
+    qemu_irq_lower(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
+}
+
+void cpu_mips_start_count(CPUState *env)
+{
+    cpu_mips_store_count(env, env->CP0_Count);
+}
+
+void cpu_mips_stop_count(CPUState *env)
+{
+    /* Store the current value */
+    env->CP0_Count += (uint32_t)muldiv64(qemu_get_clock(vm_clock),
+                                         100 * 1000 * 1000, ticks_per_sec);
 }
 
 static void mips_timer_cb (void *opaque)
@@ -70,14 +91,19 @@
         fprintf(logfile, "%s\n", __func__);
     }
 #endif
-    cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
-    cpu_mips_irq_request(env, 7, 1);
+
+    if (env->CP0_Cause & (1 << CP0Ca_DC))
+        return;
+
+    cpu_mips_update_count(env, cpu_mips_get_count(env));
+    if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+        env->CP0_Cause |= 1 << CP0Ca_TI;
+    qemu_irq_raise(env->irq[(env->CP0_IntCtl >> CP0IntCtl_IPTI) & 0x7]);
 }
 
 void cpu_mips_clock_init (CPUState *env)
 {
     env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
     env->CP0_Compare = 0;
-    cpu_mips_update_count(env, 1, 0);
+    cpu_mips_update_count(env, 1);
 }
-
diff --git a/hw/nand.c b/hw/nand.c
new file mode 100644
index 0000000..118d04e
--- /dev/null
+++ b/hw/nand.c
@@ -0,0 +1,650 @@
+/*
+ * Flash NAND memory emulation.  Based on "16M x 8 Bit NAND Flash
+ * Memory" datasheet for the KM29U128AT / K9F2808U0A chips from
+ * Samsung Electronic.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#ifndef NAND_IO
+
+# include "vl.h"
+
+# define NAND_CMD_READ0		0x00
+# define NAND_CMD_READ1		0x01
+# define NAND_CMD_READ2		0x50
+# define NAND_CMD_LPREAD2	0x30
+# define NAND_CMD_NOSERIALREAD2	0x35
+# define NAND_CMD_RANDOMREAD1	0x05
+# define NAND_CMD_RANDOMREAD2	0xe0
+# define NAND_CMD_READID	0x90
+# define NAND_CMD_RESET		0xff
+# define NAND_CMD_PAGEPROGRAM1	0x80
+# define NAND_CMD_PAGEPROGRAM2	0x10
+# define NAND_CMD_CACHEPROGRAM2	0x15
+# define NAND_CMD_BLOCKERASE1	0x60
+# define NAND_CMD_BLOCKERASE2	0xd0
+# define NAND_CMD_READSTATUS	0x70
+# define NAND_CMD_COPYBACKPRG1	0x85
+
+# define NAND_IOSTATUS_ERROR	(1 << 0)
+# define NAND_IOSTATUS_PLANE0	(1 << 1)
+# define NAND_IOSTATUS_PLANE1	(1 << 2)
+# define NAND_IOSTATUS_PLANE2	(1 << 3)
+# define NAND_IOSTATUS_PLANE3	(1 << 4)
+# define NAND_IOSTATUS_BUSY	(1 << 6)
+# define NAND_IOSTATUS_UNPROTCT	(1 << 7)
+
+# define MAX_PAGE		0x800
+# define MAX_OOB		0x40
+
+struct nand_flash_s {
+    uint8_t manf_id, chip_id;
+    int size, pages;
+    int page_shift, oob_shift, erase_shift, addr_shift;
+    uint8_t *storage;
+    BlockDriverState *bdrv;
+    int mem_oob;
+
+    int cle, ale, ce, wp, gnd;
+
+    uint8_t io[MAX_PAGE + MAX_OOB + 0x400];
+    uint8_t *ioaddr;
+    int iolen;
+
+    uint32_t cmd, addr;
+    int addrlen;
+    int status;
+    int offset;
+
+    void (*blk_write)(struct nand_flash_s *s);
+    void (*blk_erase)(struct nand_flash_s *s);
+    void (*blk_load)(struct nand_flash_s *s, uint32_t addr, int offset);
+};
+
+# define NAND_NO_AUTOINCR	0x00000001
+# define NAND_BUSWIDTH_16	0x00000002
+# define NAND_NO_PADDING	0x00000004
+# define NAND_CACHEPRG		0x00000008
+# define NAND_COPYBACK		0x00000010
+# define NAND_IS_AND		0x00000020
+# define NAND_4PAGE_ARRAY	0x00000040
+# define NAND_NO_READRDY	0x00000100
+# define NAND_SAMSUNG_LP	(NAND_NO_PADDING | NAND_COPYBACK)
+
+# define NAND_IO
+
+# define PAGE(addr)		((addr) >> ADDR_SHIFT)
+# define PAGE_START(page)	(PAGE(page) * (PAGE_SIZE + OOB_SIZE))
+# define PAGE_MASK		((1 << ADDR_SHIFT) - 1)
+# define OOB_SHIFT		(PAGE_SHIFT - 5)
+# define OOB_SIZE		(1 << OOB_SHIFT)
+# define SECTOR(addr)		((addr) >> (9 + ADDR_SHIFT - PAGE_SHIFT))
+# define SECTOR_OFFSET(addr)	((addr) & ((511 >> PAGE_SHIFT) << 8))
+
+# define PAGE_SIZE		256
+# define PAGE_SHIFT		8
+# define PAGE_SECTORS		1
+# define ADDR_SHIFT		8
+# include "nand.c"
+# define PAGE_SIZE		512
+# define PAGE_SHIFT		9
+# define PAGE_SECTORS		1
+# define ADDR_SHIFT		8
+# include "nand.c"
+# define PAGE_SIZE		2048
+# define PAGE_SHIFT		11
+# define PAGE_SECTORS		4
+# define ADDR_SHIFT		16
+# include "nand.c"
+
+/* Information based on Linux drivers/mtd/nand/nand_ids.c */
+struct nand_info_s {
+    int size;
+    int width;
+    int page_shift;
+    int erase_shift;
+    uint32_t options;
+} nand_flash_ids[0x100] = {
+    [0 ... 0xff] = { 0 },
+
+    [0x6e] = { 1,	8,	8, 4, 0 },
+    [0x64] = { 2,	8,	8, 4, 0 },
+    [0x6b] = { 4,	8,	9, 4, 0 },
+    [0xe8] = { 1,	8,	8, 4, 0 },
+    [0xec] = { 1,	8,	8, 4, 0 },
+    [0xea] = { 2,	8,	8, 4, 0 },
+    [0xd5] = { 4,	8,	9, 4, 0 },
+    [0xe3] = { 4,	8,	9, 4, 0 },
+    [0xe5] = { 4,	8,	9, 4, 0 },
+    [0xd6] = { 8,	8,	9, 4, 0 },
+
+    [0x39] = { 8,	8,	9, 4, 0 },
+    [0xe6] = { 8,	8,	9, 4, 0 },
+    [0x49] = { 8,	16,	9, 4, NAND_BUSWIDTH_16 },
+    [0x59] = { 8,	16,	9, 4, NAND_BUSWIDTH_16 },
+
+    [0x33] = { 16,	8,	9, 5, 0 },
+    [0x73] = { 16,	8,	9, 5, 0 },
+    [0x43] = { 16,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x53] = { 16,	16,	9, 5, NAND_BUSWIDTH_16 },
+
+    [0x35] = { 32,	8,	9, 5, 0 },
+    [0x75] = { 32,	8,	9, 5, 0 },
+    [0x45] = { 32,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x55] = { 32,	16,	9, 5, NAND_BUSWIDTH_16 },
+
+    [0x36] = { 64,	8,	9, 5, 0 },
+    [0x76] = { 64,	8,	9, 5, 0 },
+    [0x46] = { 64,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x56] = { 64,	16,	9, 5, NAND_BUSWIDTH_16 },
+
+    [0x78] = { 128,	8,	9, 5, 0 },
+    [0x39] = { 128,	8,	9, 5, 0 },
+    [0x79] = { 128,	8,	9, 5, 0 },
+    [0x72] = { 128,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x49] = { 128,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x74] = { 128,	16,	9, 5, NAND_BUSWIDTH_16 },
+    [0x59] = { 128,	16,	9, 5, NAND_BUSWIDTH_16 },
+
+    [0x71] = { 256,	8,	9, 5, 0 },
+
+    /*
+     * These are the new chips with large page size. The pagesize and the
+     * erasesize is determined from the extended id bytes
+     */
+# define LP_OPTIONS	(NAND_SAMSUNG_LP | NAND_NO_READRDY | NAND_NO_AUTOINCR)
+# define LP_OPTIONS16	(LP_OPTIONS | NAND_BUSWIDTH_16)
+
+    /* 512 Megabit */
+    [0xa2] = { 64,	8,	0, 0, LP_OPTIONS },
+    [0xf2] = { 64,	8,	0, 0, LP_OPTIONS },
+    [0xb2] = { 64,	16,	0, 0, LP_OPTIONS16 },
+    [0xc2] = { 64,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 1 Gigabit */
+    [0xa1] = { 128,	8,	0, 0, LP_OPTIONS },
+    [0xf1] = { 128,	8,	0, 0, LP_OPTIONS },
+    [0xb1] = { 128,	16,	0, 0, LP_OPTIONS16 },
+    [0xc1] = { 128,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 2 Gigabit */
+    [0xaa] = { 256,	8,	0, 0, LP_OPTIONS },
+    [0xda] = { 256,	8,	0, 0, LP_OPTIONS },
+    [0xba] = { 256,	16,	0, 0, LP_OPTIONS16 },
+    [0xca] = { 256,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 4 Gigabit */
+    [0xac] = { 512,	8,	0, 0, LP_OPTIONS },
+    [0xdc] = { 512,	8,	0, 0, LP_OPTIONS },
+    [0xbc] = { 512,	16,	0, 0, LP_OPTIONS16 },
+    [0xcc] = { 512,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 8 Gigabit */
+    [0xa3] = { 1024,	8,	0, 0, LP_OPTIONS },
+    [0xd3] = { 1024,	8,	0, 0, LP_OPTIONS },
+    [0xb3] = { 1024,	16,	0, 0, LP_OPTIONS16 },
+    [0xc3] = { 1024,	16,	0, 0, LP_OPTIONS16 },
+
+    /* 16 Gigabit */
+    [0xa5] = { 2048,	8,	0, 0, LP_OPTIONS },
+    [0xd5] = { 2048,	8,	0, 0, LP_OPTIONS },
+    [0xb5] = { 2048,	16,	0, 0, LP_OPTIONS16 },
+    [0xc5] = { 2048,	16,	0, 0, LP_OPTIONS16 },
+};
+
+static void nand_reset(struct nand_flash_s *s)
+{
+    s->cmd = NAND_CMD_READ0;
+    s->addr = 0;
+    s->addrlen = 0;
+    s->iolen = 0;
+    s->offset = 0;
+    s->status &= NAND_IOSTATUS_UNPROTCT;
+}
+
+static void nand_command(struct nand_flash_s *s)
+{
+    switch (s->cmd) {
+    case NAND_CMD_READ0:
+        s->iolen = 0;
+        break;
+
+    case NAND_CMD_READID:
+        s->io[0] = s->manf_id;
+        s->io[1] = s->chip_id;
+        s->io[2] = 'Q';		/* Don't-care byte (often 0xa5) */
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+            s->io[3] = 0x15;	/* Page Size, Block Size, Spare Size.. */
+        else
+            s->io[3] = 0xc0;	/* Multi-plane */
+        s->ioaddr = s->io;
+        s->iolen = 4;
+        break;
+
+    case NAND_CMD_RANDOMREAD2:
+    case NAND_CMD_NOSERIALREAD2:
+        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP))
+            break;
+
+        s->blk_load(s, s->addr, s->addr & ((1 << s->addr_shift) - 1));
+        break;
+
+    case NAND_CMD_RESET:
+        nand_reset(s);
+        break;
+
+    case NAND_CMD_PAGEPROGRAM1:
+        s->ioaddr = s->io;
+        s->iolen = 0;
+        break;
+
+    case NAND_CMD_PAGEPROGRAM2:
+        if (s->wp) {
+            s->blk_write(s);
+        }
+        break;
+
+    case NAND_CMD_BLOCKERASE1:
+        break;
+
+    case NAND_CMD_BLOCKERASE2:
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP)
+            s->addr <<= 16;
+        else
+            s->addr <<= 8;
+
+        if (s->wp) {
+            s->blk_erase(s);
+        }
+        break;
+
+    case NAND_CMD_READSTATUS:
+        s->io[0] = s->status;
+        s->ioaddr = s->io;
+        s->iolen = 1;
+        break;
+
+    default:
+        printf("%s: Unknown NAND command 0x%02x\n", __FUNCTION__, s->cmd);
+    }
+}
+
+static void nand_save(QEMUFile *f, void *opaque)
+{
+    struct nand_flash_s *s = (struct nand_flash_s *) opaque;
+    qemu_put_byte(f, s->cle);
+    qemu_put_byte(f, s->ale);
+    qemu_put_byte(f, s->ce);
+    qemu_put_byte(f, s->wp);
+    qemu_put_byte(f, s->gnd);
+    qemu_put_buffer(f, s->io, sizeof(s->io));
+    qemu_put_be32(f, s->ioaddr - s->io);
+    qemu_put_be32(f, s->iolen);
+
+    qemu_put_be32s(f, &s->cmd);
+    qemu_put_be32s(f, &s->addr);
+    qemu_put_be32(f, s->addrlen);
+    qemu_put_be32(f, s->status);
+    qemu_put_be32(f, s->offset);
+    /* XXX: do we want to save s->storage too? */
+}
+
+static int nand_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct nand_flash_s *s = (struct nand_flash_s *) opaque;
+    s->cle = qemu_get_byte(f);
+    s->ale = qemu_get_byte(f);
+    s->ce = qemu_get_byte(f);
+    s->wp = qemu_get_byte(f);
+    s->gnd = qemu_get_byte(f);
+    qemu_get_buffer(f, s->io, sizeof(s->io));
+    s->ioaddr = s->io + qemu_get_be32(f);
+    s->iolen = qemu_get_be32(f);
+    if (s->ioaddr >= s->io + sizeof(s->io) || s->ioaddr < s->io)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->cmd);
+    qemu_get_be32s(f, &s->addr);
+    s->addrlen = qemu_get_be32(f);
+    s->status = qemu_get_be32(f);
+    s->offset = qemu_get_be32(f);
+    return 0;
+}
+
+static int nand_iid = 0;
+
+/*
+ * Chip inputs are CLE, ALE, CE, WP, GND and eight I/O pins.  Chip
+ * outputs are R/B and eight I/O pins.
+ *
+ * CE, WP and R/B are active low.
+ */
+void nand_setpins(struct nand_flash_s *s,
+                int cle, int ale, int ce, int wp, int gnd)
+{
+    s->cle = cle;
+    s->ale = ale;
+    s->ce = ce;
+    s->wp = wp;
+    s->gnd = gnd;
+    if (wp)
+        s->status |= NAND_IOSTATUS_UNPROTCT;
+    else
+        s->status &= ~NAND_IOSTATUS_UNPROTCT;
+}
+
+void nand_getpins(struct nand_flash_s *s, int *rb)
+{
+    *rb = 1;
+}
+
+void nand_setio(struct nand_flash_s *s, uint8_t value)
+{
+    if (!s->ce && s->cle) {
+        if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+            if (s->cmd == NAND_CMD_READ0 && value == NAND_CMD_LPREAD2)
+                return;
+            if (value == NAND_CMD_RANDOMREAD1) {
+                s->addr &= ~((1 << s->addr_shift) - 1);
+                s->addrlen = 0;
+                return;
+            }
+        }
+        if (value == NAND_CMD_READ0)
+            s->offset = 0;
+	else if (value == NAND_CMD_READ1) {
+            s->offset = 0x100;
+            value = NAND_CMD_READ0;
+        }
+	else if (value == NAND_CMD_READ2) {
+            s->offset = 1 << s->page_shift;
+            value = NAND_CMD_READ0;
+        }
+
+        s->cmd = value;
+
+        if (s->cmd == NAND_CMD_READSTATUS ||
+                s->cmd == NAND_CMD_PAGEPROGRAM2 ||
+                s->cmd == NAND_CMD_BLOCKERASE1 ||
+                s->cmd == NAND_CMD_BLOCKERASE2 ||
+                s->cmd == NAND_CMD_NOSERIALREAD2 ||
+                s->cmd == NAND_CMD_RANDOMREAD2 ||
+                s->cmd == NAND_CMD_RESET)
+            nand_command(s);
+
+        if (s->cmd != NAND_CMD_RANDOMREAD2) {
+            s->addrlen = 0;
+            s->addr = 0;
+        }
+    }
+
+    if (s->ale) {
+        s->addr |= value << (s->addrlen * 8);
+        s->addrlen ++;
+
+        if (s->addrlen == 1 && s->cmd == NAND_CMD_READID)
+            nand_command(s);
+
+        if (!(nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+                s->addrlen == 3 && (
+                    s->cmd == NAND_CMD_READ0 ||
+                    s->cmd == NAND_CMD_PAGEPROGRAM1))
+            nand_command(s);
+        if ((nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) &&
+               s->addrlen == 4 && (
+                    s->cmd == NAND_CMD_READ0 ||
+                    s->cmd == NAND_CMD_PAGEPROGRAM1))
+            nand_command(s);
+    }
+
+    if (!s->cle && !s->ale && s->cmd == NAND_CMD_PAGEPROGRAM1) {
+        if (s->iolen < (1 << s->page_shift) + (1 << s->oob_shift))
+            s->io[s->iolen ++] = value;
+    } else if (!s->cle && !s->ale && s->cmd == NAND_CMD_COPYBACKPRG1) {
+        if ((s->addr & ((1 << s->addr_shift) - 1)) <
+                (1 << s->page_shift) + (1 << s->oob_shift)) {
+            s->io[s->iolen + (s->addr & ((1 << s->addr_shift) - 1))] = value;
+            s->addr ++;
+        }
+    }
+}
+
+uint8_t nand_getio(struct nand_flash_s *s)
+{
+    int offset;
+
+    /* Allow sequential reading */
+    if (!s->iolen && s->cmd == NAND_CMD_READ0) {
+        offset = (s->addr & ((1 << s->addr_shift) - 1)) + s->offset;
+        s->offset = 0;
+
+        s->blk_load(s, s->addr, offset);
+        if (s->gnd)
+            s->iolen = (1 << s->page_shift) - offset;
+        else
+            s->iolen = (1 << s->page_shift) + (1 << s->oob_shift) - offset;
+    }
+
+    if (s->ce || s->iolen <= 0)
+        return 0;
+
+    s->iolen --;
+    return *(s->ioaddr ++);
+}
+
+struct nand_flash_s *nand_init(int manf_id, int chip_id)
+{
+    int pagesize;
+    struct nand_flash_s *s;
+
+    if (nand_flash_ids[chip_id].size == 0) {
+        cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n",
+                        __FUNCTION__);
+    }
+
+    s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s));
+    s->bdrv = mtd_bdrv;
+    s->manf_id = manf_id;
+    s->chip_id = chip_id;
+    s->size = nand_flash_ids[s->chip_id].size << 20;
+    if (nand_flash_ids[s->chip_id].options & NAND_SAMSUNG_LP) {
+        s->page_shift = 11;
+        s->erase_shift = 6;
+    } else {
+        s->page_shift = nand_flash_ids[s->chip_id].page_shift;
+        s->erase_shift = nand_flash_ids[s->chip_id].erase_shift;
+    }
+
+    switch (1 << s->page_shift) {
+    case 256:
+        nand_init_256(s);
+        break;
+    case 512:
+        nand_init_512(s);
+        break;
+    case 2048:
+        nand_init_2048(s);
+        break;
+    default:
+        cpu_abort(cpu_single_env, "%s: Unsupported NAND block size.\n",
+                        __FUNCTION__);
+    }
+
+    pagesize = 1 << s->oob_shift;
+    s->mem_oob = 1;
+    if (s->bdrv && bdrv_getlength(s->bdrv) >=
+                    (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
+        pagesize = 0;
+        s->mem_oob = 0;
+    }
+
+    if (!s->bdrv)
+        pagesize += 1 << s->page_shift;
+    if (pagesize)
+        s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
+                        0xff, s->pages * pagesize);
+
+    register_savevm("nand", nand_iid ++, 0, nand_save, nand_load, s);
+
+    return s;
+}
+
+void nand_done(struct nand_flash_s *s)
+{
+    if (s->bdrv) {
+        bdrv_close(s->bdrv);
+        bdrv_delete(s->bdrv);
+    }
+
+    if (!s->bdrv || s->mem_oob)
+        free(s->storage);
+
+    free(s);
+}
+
+#else
+
+/* Program a single page */
+static void glue(nand_blk_write_, PAGE_SIZE)(struct nand_flash_s *s)
+{
+    uint32_t off, page, sector, soff;
+    uint8_t iobuf[(PAGE_SECTORS + 2) * 0x200];
+    if (PAGE(s->addr) >= s->pages)
+        return;
+
+    if (!s->bdrv) {
+        memcpy(s->storage + PAGE_START(s->addr) + (s->addr & PAGE_MASK) +
+                        s->offset, s->io, s->iolen);
+    } else if (s->mem_oob) {
+        sector = SECTOR(s->addr);
+        off = (s->addr & PAGE_MASK) + s->offset;
+        soff = SECTOR_OFFSET(s->addr);
+        if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1) {
+            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            return;
+        }
+
+        memcpy(iobuf + (soff | off), s->io, MIN(s->iolen, PAGE_SIZE - off));
+        if (off + s->iolen > PAGE_SIZE) {
+            page = PAGE(s->addr);
+            memcpy(s->storage + (page << OOB_SHIFT), s->io + PAGE_SIZE - off,
+                            MIN(OOB_SIZE, off + s->iolen - PAGE_SIZE));
+        }
+
+        if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+    } else {
+        off = PAGE_START(s->addr) + (s->addr & PAGE_MASK) + s->offset;
+        sector = off >> 9;
+        soff = off & 0x1ff;
+        if (bdrv_read(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1) {
+            printf("%s: read error in sector %i\n", __FUNCTION__, sector);
+            return;
+        }
+
+        memcpy(iobuf + soff, s->io, s->iolen);
+
+        if (bdrv_write(s->bdrv, sector, iobuf, PAGE_SECTORS + 2) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, sector);
+    }
+    s->offset = 0;
+}
+
+/* Erase a single block */
+static void glue(nand_blk_erase_, PAGE_SIZE)(struct nand_flash_s *s)
+{
+    uint32_t i, page, addr;
+    uint8_t iobuf[0x200] = { [0 ... 0x1ff] = 0xff, };
+    addr = s->addr & ~((1 << (ADDR_SHIFT + s->erase_shift)) - 1);
+
+    if (PAGE(addr) >= s->pages)
+        return;
+
+    if (!s->bdrv) {
+        memset(s->storage + PAGE_START(addr),
+                        0xff, (PAGE_SIZE + OOB_SIZE) << s->erase_shift);
+    } else if (s->mem_oob) {
+        memset(s->storage + (PAGE(addr) << OOB_SHIFT),
+                        0xff, OOB_SIZE << s->erase_shift);
+        i = SECTOR(addr);
+        page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
+        for (; i < page; i ++)
+            if (bdrv_write(s->bdrv, i, iobuf, 1) == -1)
+                printf("%s: write error in sector %i\n", __FUNCTION__, i);
+    } else {
+        addr = PAGE_START(addr);
+        page = addr >> 9;
+        if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
+            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+        memset(iobuf + (addr & 0x1ff), 0xff, (~addr & 0x1ff) + 1);
+        if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+
+        memset(iobuf, 0xff, 0x200);
+        i = (addr & ~0x1ff) + 0x200;
+        for (addr += ((PAGE_SIZE + OOB_SIZE) << s->erase_shift) - 0x200;
+                        i < addr; i += 0x200)
+            if (bdrv_write(s->bdrv, i >> 9, iobuf, 1) == -1)
+                printf("%s: write error in sector %i\n", __FUNCTION__, i >> 9);
+
+        page = i >> 9;
+        if (bdrv_read(s->bdrv, page, iobuf, 1) == -1)
+            printf("%s: read error in sector %i\n", __FUNCTION__, page);
+        memset(iobuf, 0xff, ((addr - 1) & 0x1ff) + 1);
+        if (bdrv_write(s->bdrv, page, iobuf, 1) == -1)
+            printf("%s: write error in sector %i\n", __FUNCTION__, page);
+    }
+}
+
+static void glue(nand_blk_load_, PAGE_SIZE)(struct nand_flash_s *s,
+                uint32_t addr, int offset)
+{
+    if (PAGE(addr) >= s->pages)
+        return;
+
+    if (s->bdrv) {
+        if (s->mem_oob) {
+            if (bdrv_read(s->bdrv, SECTOR(addr), s->io, PAGE_SECTORS) == -1)
+                printf("%s: read error in sector %i\n",
+                                __FUNCTION__, SECTOR(addr));
+            memcpy(s->io + SECTOR_OFFSET(s->addr) + PAGE_SIZE,
+                            s->storage + (PAGE(s->addr) << OOB_SHIFT),
+                            OOB_SIZE);
+            s->ioaddr = s->io + SECTOR_OFFSET(s->addr) + offset;
+        } else {
+            if (bdrv_read(s->bdrv, PAGE_START(addr) >> 9,
+                                    s->io, (PAGE_SECTORS + 2)) == -1)
+                printf("%s: read error in sector %i\n",
+                                __FUNCTION__, PAGE_START(addr) >> 9);
+            s->ioaddr = s->io + (PAGE_START(addr) & 0x1ff) + offset;
+        }
+    } else {
+        memcpy(s->io, s->storage + PAGE_START(s->addr) +
+                        offset, PAGE_SIZE + OOB_SIZE - offset);
+        s->ioaddr = s->io;
+    }
+
+    s->addr &= PAGE_SIZE - 1;
+    s->addr += PAGE_SIZE;
+}
+
+static void glue(nand_init_, PAGE_SIZE)(struct nand_flash_s *s)
+{
+    s->oob_shift = PAGE_SHIFT - 5;
+    s->pages = s->size >> PAGE_SHIFT;
+    s->addr_shift = ADDR_SHIFT;
+
+    s->blk_erase = glue(nand_blk_erase_, PAGE_SIZE);
+    s->blk_write = glue(nand_blk_write_, PAGE_SIZE);
+    s->blk_load = glue(nand_blk_load_, PAGE_SIZE);
+}
+
+# undef PAGE_SIZE
+# undef PAGE_SHIFT
+# undef PAGE_SECTORS
+# undef ADDR_SHIFT
+#endif	/* NAND_IO */
diff --git a/hw/ne2000.c b/hw/ne2000.c
index a045a20..689216c 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -1,8 +1,8 @@
 /*
  * QEMU NE2000 emulation
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -136,7 +136,7 @@
     uint8_t phys[6]; /* mac address */
     uint8_t curpag;
     uint8_t mult[8]; /* multicast mask array */
-    int irq;
+    qemu_irq irq;
     PCIDevice *pci_dev;
     VLANClientState *vc;
     uint8_t macaddr[6];
@@ -164,16 +164,10 @@
     int isr;
     isr = (s->isr & s->imr) & 0x7f;
 #if defined(DEBUG_NE2000)
-    printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
-	   s->irq, isr ? 1 : 0, s->isr, s->imr);
+    printf("NE2000: Set IRQ to %d (%02x %02x)\n",
+	   isr ? 1 : 0, s->isr, s->imr);
 #endif
-    if (s->irq == 16) {
-        /* PCI irq */
-        pci_set_irq(s->pci_dev, 0, (isr != 0));
-    } else {
-        /* ISA irq */
-        pic_set_irq(s->irq, (isr != 0));
-    }
+    qemu_set_irq(s->irq, (isr != 0));
 }
 
 #define POLYNOMIAL 0x04c11db6
@@ -206,7 +200,7 @@
 
     index = s->curpag << 8;
     boundary = s->boundary << 8;
-    if (index <= boundary)
+    if (index < boundary)
         avail = boundary - index;
     else
         avail = (s->stop - s->start) - (index - boundary);
@@ -218,7 +212,7 @@
 static int ne2000_can_receive(void *opaque)
 {
     NE2000State *s = opaque;
-    
+
     if (s->cmd & E8390_STOP)
         return 1;
     return !ne2000_buffer_full(s);
@@ -230,18 +224,18 @@
 {
     NE2000State *s = opaque;
     uint8_t *p;
-    int total_len, next, avail, len, index, mcast_idx;
+    unsigned int total_len, next, avail, len, index, mcast_idx;
     uint8_t buf1[60];
-    static const uint8_t broadcast_macaddr[6] = 
+    static const uint8_t broadcast_macaddr[6] =
         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-    
+
 #if defined(DEBUG_NE2000)
     printf("NE2000: received len=%d\n", size);
 #endif
 
     if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
         return;
-    
+
     /* XXX: check this */
     if (s->rxcr & 0x10) {
         /* promiscuous: receive all */
@@ -258,10 +252,10 @@
             if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
                 return;
         } else if (s->mem[0] == buf[0] &&
-                   s->mem[2] == buf[1] &&                   
-                   s->mem[4] == buf[2] &&            
-                   s->mem[6] == buf[3] &&            
-                   s->mem[8] == buf[4] &&            
+                   s->mem[2] == buf[1] &&
+                   s->mem[4] == buf[2] &&
+                   s->mem[6] == buf[3] &&
+                   s->mem[8] == buf[4] &&
                    s->mem[10] == buf[5]) {
             /* match */
         } else {
@@ -299,7 +293,10 @@
 
     /* write packet data */
     while (size > 0) {
-        avail = s->stop - index;
+        if (index <= s->stop)
+            avail = s->stop - index;
+        else
+            avail = 0;
         len = size;
         if (len > avail)
             len = avail;
@@ -331,7 +328,7 @@
         s->cmd = val;
         if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
             s->isr &= ~ENISR_RESET;
-            /* test specific case: zero length transfert */
+            /* test specific case: zero length transfer */
             if ((val & (E8390_RREAD | E8390_RWRITE)) &&
                 s->rcnt == 0) {
                 s->isr |= ENISR_RDC;
@@ -339,17 +336,17 @@
             }
             if (val & E8390_TRANS) {
                 index = (s->tpsr << 8);
-                /* XXX: next 2 lines are a hack to make netware 3.11 work */ 
+                /* XXX: next 2 lines are a hack to make netware 3.11 work */
                 if (index >= NE2000_PMEM_END)
                     index -= NE2000_PMEM_SIZE;
                 /* fail safe: check range on the transmitted length  */
                 if (index + s->tcnt <= NE2000_PMEM_END) {
                     qemu_send_packet(s->vc, s->mem + index, s->tcnt);
                 }
-                /* signal end of transfert */
+                /* signal end of transfer */
                 s->tsr = ENTSR_PTX;
                 s->isr |= ENISR_TX;
-                s->cmd &= ~E8390_TRANS; 
+                s->cmd &= ~E8390_TRANS;
                 ne2000_update_irq(s);
             }
         }
@@ -485,30 +482,30 @@
     return ret;
 }
 
-static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr, 
+static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
                                      uint32_t val)
 {
-    if (addr < 32 || 
+    if (addr < 32 ||
         (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
         s->mem[addr] = val;
     }
 }
 
-static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr, 
+static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
                                      uint32_t val)
 {
     addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 || 
+    if (addr < 32 ||
         (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
         *(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
     }
 }
 
-static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr, 
+static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
                                      uint32_t val)
 {
     addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 || 
+    if (addr < 32 ||
         (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
         cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
     }
@@ -516,7 +513,7 @@
 
 static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
 {
-    if (addr < 32 || 
+    if (addr < 32 ||
         (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
         return s->mem[addr];
     } else {
@@ -527,7 +524,7 @@
 static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
 {
     addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 || 
+    if (addr < 32 ||
         (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
         return le16_to_cpu(*(uint16_t *)(s->mem + addr));
     } else {
@@ -538,7 +535,7 @@
 static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
 {
     addr &= ~1; /* XXX: check exact behaviour if not even */
-    if (addr < 32 || 
+    if (addr < 32 ||
         (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
         return le32_to_cpupu((uint32_t *)(s->mem + addr));
     } else {
@@ -556,7 +553,7 @@
 
     if (s->rcnt <= len) {
         s->rcnt = 0;
-        /* signal end of transfert */
+        /* signal end of transfer */
         s->isr |= ENISR_RDC;
         ne2000_update_irq(s);
     } else {
@@ -647,6 +644,7 @@
 static void ne2000_save(QEMUFile* f,void* opaque)
 {
 	NE2000State* s=(NE2000State*)opaque;
+        int tmp;
 
         if (s->pci_dev)
             pci_device_save(s->pci_dev, f);
@@ -669,7 +667,8 @@
 	qemu_put_buffer(f, s->phys, 6);
 	qemu_put_8s(f, &s->curpag);
 	qemu_put_buffer(f, s->mult, 8);
-	qemu_put_be32s(f, &s->irq);
+        tmp = 0;
+	qemu_put_be32s(f, &tmp); /* ignored, was irq */
 	qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);
 }
 
@@ -677,6 +676,7 @@
 {
 	NE2000State* s=(NE2000State*)opaque;
         int ret;
+        int tmp;
 
         if (version_id > 3)
             return -EINVAL;
@@ -709,20 +709,20 @@
 	qemu_get_buffer(f, s->phys, 6);
 	qemu_get_8s(f, &s->curpag);
 	qemu_get_buffer(f, s->mult, 8);
-	qemu_get_be32s(f, &s->irq);
+	qemu_get_be32s(f, &tmp); /* ignored */
 	qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE);
 
 	return 0;
 }
 
-void isa_ne2000_init(int base, int irq, NICInfo *nd)
+void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd)
 {
     NE2000State *s;
-    
+
     s = qemu_mallocz(sizeof(NE2000State));
     if (!s)
         return;
-    
+
     register_ioport_write(base, 16, 1, ne2000_ioport_write, s);
     register_ioport_read(base, 16, 1, ne2000_ioport_read, s);
 
@@ -749,7 +749,7 @@
              s->macaddr[3],
              s->macaddr[4],
              s->macaddr[5]);
-             
+
     register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
 }
 
@@ -761,7 +761,7 @@
     NE2000State ne2000;
 } PCINE2000State;
 
-static void ne2000_map(PCIDevice *pci_dev, int region_num, 
+static void ne2000_map(PCIDevice *pci_dev, int region_num,
                        uint32_t addr, uint32_t size, int type)
 {
     PCINE2000State *d = (PCINE2000State *)pci_dev;
@@ -786,25 +786,25 @@
     PCINE2000State *d;
     NE2000State *s;
     uint8_t *pci_conf;
-    
+
     d = (PCINE2000State *)pci_register_device(bus,
                                               "NE2000", sizeof(PCINE2000State),
-                                              devfn, 
+                                              devfn,
                                               NULL, NULL);
     pci_conf = d->dev.config;
     pci_conf[0x00] = 0xec; // Realtek 8029
     pci_conf[0x01] = 0x10;
     pci_conf[0x02] = 0x29;
     pci_conf[0x03] = 0x80;
-    pci_conf[0x0a] = 0x00; // ethernet network controller 
+    pci_conf[0x0a] = 0x00; // ethernet network controller
     pci_conf[0x0b] = 0x02;
     pci_conf[0x0e] = 0x00; // header_type
     pci_conf[0x3d] = 1; // interrupt pin 0
-    
-    pci_register_io_region(&d->dev, 0, 0x100, 
+
+    pci_register_io_region(&d->dev, 0, 0x100,
                            PCI_ADDRESS_SPACE_IO, ne2000_map);
     s = &d->ne2000;
-    s->irq = 16; // PCI interrupt
+    s->irq = d->dev.irq[0];
     s->pci_dev = (PCIDevice *)d;
     memcpy(s->macaddr, nd->macaddr, 6);
     ne2000_reset(s);
@@ -819,7 +819,7 @@
              s->macaddr[3],
              s->macaddr[4],
              s->macaddr[5]);
-             
+
     /* XXX: instance number ? */
     register_savevm("ne2000", 0, 3, ne2000_save, ne2000_load, s);
 }
diff --git a/hw/omap.c b/hw/omap.c
new file mode 100644
index 0000000..ccd8f4e
--- /dev/null
+++ b/hw/omap.c
@@ -0,0 +1,2929 @@
+/*
+ * TI OMAP processors emulation.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "vl.h"
+#include "arm_pic.h"
+
+/* Should signal the TCMI */
+uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr)
+{
+    OMAP_16B_REG(addr);
+    return 0;
+}
+
+void omap_badwidth_write16(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_16B_REG(addr);
+}
+
+uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr)
+{
+    OMAP_32B_REG(addr);
+    return 0;
+}
+
+void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_32B_REG(addr);
+}
+
+/* Interrupt Handlers */
+struct omap_intr_handler_s {
+    qemu_irq *pins;
+    qemu_irq *parent_pic;
+    target_phys_addr_t base;
+
+    /* state */
+    uint32_t irqs;
+    uint32_t mask;
+    uint32_t sens_edge;
+    uint32_t fiq;
+    int priority[32];
+    uint32_t new_irq_agr;
+    uint32_t new_fiq_agr;
+    int sir_irq;
+    int sir_fiq;
+    int stats[32];
+};
+
+static void omap_inth_update(struct omap_intr_handler_s *s)
+{
+    uint32_t irq = s->irqs & ~s->mask & ~s->fiq;
+    uint32_t fiq = s->irqs & ~s->mask & s->fiq;
+
+    if (s->new_irq_agr || !irq) {
+       qemu_set_irq(s->parent_pic[ARM_PIC_CPU_IRQ], irq);
+       if (irq)
+           s->new_irq_agr = 0;
+    }
+
+    if (s->new_fiq_agr || !irq) {
+        qemu_set_irq(s->parent_pic[ARM_PIC_CPU_FIQ], fiq);
+        if (fiq)
+            s->new_fiq_agr = 0;
+    }
+}
+
+static void omap_inth_sir_update(struct omap_intr_handler_s *s)
+{
+    int i, intr_irq, intr_fiq, p_irq, p_fiq, p, f;
+    uint32_t level = s->irqs & ~s->mask;
+
+    intr_irq = 0;
+    intr_fiq = 0;
+    p_irq = -1;
+    p_fiq = -1;
+    /* Find the interrupt line with the highest dynamic priority */
+    for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, level >>= f) {
+        p = s->priority[i];
+        if (s->fiq & (1 << i)) {
+            if (p > p_fiq) {
+                p_fiq = p;
+                intr_fiq = i;
+            }
+        } else {
+            if (p > p_irq) {
+                p_irq = p;
+                intr_irq = i;
+            }
+        }
+
+        f = ffs(level >> 1);
+    }
+
+    s->sir_irq = intr_irq;
+    s->sir_fiq = intr_fiq;
+}
+
+#define INT_FALLING_EDGE	0
+#define INT_LOW_LEVEL		1
+
+static void omap_set_intr(void *opaque, int irq, int req)
+{
+    struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque;
+    uint32_t rise;
+
+    if (req) {
+        rise = ~ih->irqs & (1 << irq);
+        ih->irqs |= rise;
+        ih->stats[irq] += !!rise;
+    } else {
+        rise = ih->sens_edge & ih->irqs & (1 << irq);
+        ih->irqs &= ~rise;
+    }
+
+    if (rise & ~ih->mask) {
+        omap_inth_sir_update(ih);
+
+        omap_inth_update(ih);
+    }
+}
+
+static uint32_t omap_inth_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int i, offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00:	/* ITR */
+        return s->irqs;
+
+    case 0x04:	/* MIR */
+        return s->mask;
+
+    case 0x10:	/* SIR_IRQ_CODE */
+        i = s->sir_irq;
+        if (((s->sens_edge >> i) & 1) == INT_FALLING_EDGE && i) {
+            s->irqs &= ~(1 << i);
+            omap_inth_sir_update(s);
+            omap_inth_update(s);
+        }
+        return i;
+
+    case 0x14:	/* SIR_FIQ_CODE */
+        i = s->sir_fiq;
+        if (((s->sens_edge >> i) & 1) == INT_FALLING_EDGE && i) {
+            s->irqs &= ~(1 << i);
+            omap_inth_sir_update(s);
+            omap_inth_update(s);
+        }
+        return i;
+
+    case 0x18:	/* CONTROL_REG */
+        return 0;
+
+    case 0x1c:	/* ILR0 */
+    case 0x20:	/* ILR1 */
+    case 0x24:	/* ILR2 */
+    case 0x28:	/* ILR3 */
+    case 0x2c:	/* ILR4 */
+    case 0x30:	/* ILR5 */
+    case 0x34:	/* ILR6 */
+    case 0x38:	/* ILR7 */
+    case 0x3c:	/* ILR8 */
+    case 0x40:	/* ILR9 */
+    case 0x44:	/* ILR10 */
+    case 0x48:	/* ILR11 */
+    case 0x4c:	/* ILR12 */
+    case 0x50:	/* ILR13 */
+    case 0x54:	/* ILR14 */
+    case 0x58:	/* ILR15 */
+    case 0x5c:	/* ILR16 */
+    case 0x60:	/* ILR17 */
+    case 0x64:	/* ILR18 */
+    case 0x68:	/* ILR19 */
+    case 0x6c:	/* ILR20 */
+    case 0x70:	/* ILR21 */
+    case 0x74:	/* ILR22 */
+    case 0x78:	/* ILR23 */
+    case 0x7c:	/* ILR24 */
+    case 0x80:	/* ILR25 */
+    case 0x84:	/* ILR26 */
+    case 0x88:	/* ILR27 */
+    case 0x8c:	/* ILR28 */
+    case 0x90:	/* ILR29 */
+    case 0x94:	/* ILR30 */
+    case 0x98:	/* ILR31 */
+        i = (offset - 0x1c) >> 2;
+        return (s->priority[i] << 2) |
+                (((s->sens_edge >> i) & 1) << 1) |
+                ((s->fiq >> i) & 1);
+
+    case 0x9c:	/* ISR */
+        return 0x00000000;
+
+    default:
+        OMAP_BAD_REG(addr);
+        break;
+    }
+    return 0;
+}
+
+static void omap_inth_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque;
+    int i, offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00:	/* ITR */
+        s->irqs &= value;
+        omap_inth_sir_update(s);
+        omap_inth_update(s);
+        return;
+
+    case 0x04:	/* MIR */
+        s->mask = value;
+        omap_inth_sir_update(s);
+        omap_inth_update(s);
+        return;
+
+    case 0x10:	/* SIR_IRQ_CODE */
+    case 0x14:	/* SIR_FIQ_CODE */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x18:	/* CONTROL_REG */
+        if (value & 2)
+            s->new_fiq_agr = ~0;
+        if (value & 1)
+            s->new_irq_agr = ~0;
+        omap_inth_update(s);
+        return;
+
+    case 0x1c:	/* ILR0 */
+    case 0x20:	/* ILR1 */
+    case 0x24:	/* ILR2 */
+    case 0x28:	/* ILR3 */
+    case 0x2c:	/* ILR4 */
+    case 0x30:	/* ILR5 */
+    case 0x34:	/* ILR6 */
+    case 0x38:	/* ILR7 */
+    case 0x3c:	/* ILR8 */
+    case 0x40:	/* ILR9 */
+    case 0x44:	/* ILR10 */
+    case 0x48:	/* ILR11 */
+    case 0x4c:	/* ILR12 */
+    case 0x50:	/* ILR13 */
+    case 0x54:	/* ILR14 */
+    case 0x58:	/* ILR15 */
+    case 0x5c:	/* ILR16 */
+    case 0x60:	/* ILR17 */
+    case 0x64:	/* ILR18 */
+    case 0x68:	/* ILR19 */
+    case 0x6c:	/* ILR20 */
+    case 0x70:	/* ILR21 */
+    case 0x74:	/* ILR22 */
+    case 0x78:	/* ILR23 */
+    case 0x7c:	/* ILR24 */
+    case 0x80:	/* ILR25 */
+    case 0x84:	/* ILR26 */
+    case 0x88:	/* ILR27 */
+    case 0x8c:	/* ILR28 */
+    case 0x90:	/* ILR29 */
+    case 0x94:	/* ILR30 */
+    case 0x98:	/* ILR31 */
+        i = (offset - 0x1c) >> 2;
+        s->priority[i] = (value >> 2) & 0x1f;
+        s->sens_edge &= ~(1 << i);
+        s->sens_edge |= ((value >> 1) & 1) << i;
+        s->fiq &= ~(1 << i);
+        s->fiq |= (value & 1) << i;
+        return;
+
+    case 0x9c:	/* ISR */
+        for (i = 0; i < 32; i ++)
+            if (value & (1 << i)) {
+                omap_set_intr(s, i, 1);
+                return;
+            }
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_inth_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_inth_read,
+};
+
+static CPUWriteMemoryFunc *omap_inth_writefn[] = {
+    omap_inth_write,
+    omap_inth_write,
+    omap_inth_write,
+};
+
+static void omap_inth_reset(struct omap_intr_handler_s *s)
+{
+    s->irqs = 0x00000000;
+    s->mask = 0xffffffff;
+    s->sens_edge = 0x00000000;
+    s->fiq = 0x00000000;
+    memset(s->priority, 0, sizeof(s->priority));
+    s->new_irq_agr = ~0;
+    s->new_fiq_agr = ~0;
+    s->sir_irq = 0;
+    s->sir_fiq = 0;
+
+    omap_inth_update(s);
+}
+
+struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
+                unsigned long size, qemu_irq parent[2], omap_clk clk)
+{
+    int iomemtype;
+    struct omap_intr_handler_s *s = (struct omap_intr_handler_s *)
+            qemu_mallocz(sizeof(struct omap_intr_handler_s));
+
+    s->parent_pic = parent;
+    s->base = base;
+    s->pins = qemu_allocate_irqs(omap_set_intr, s, 32);
+    omap_inth_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_inth_readfn,
+                    omap_inth_writefn, s);
+    cpu_register_physical_memory(s->base, size, iomemtype);
+
+    return s;
+}
+
+/* OMAP1 DMA module */
+typedef enum {
+    constant = 0,
+    post_incremented,
+    single_index,
+    double_index,
+} omap_dma_addressing_t;
+
+struct omap_dma_channel_s {
+    int burst[2];
+    int pack[2];
+    enum omap_dma_port port[2];
+    target_phys_addr_t addr[2];
+    omap_dma_addressing_t mode[2];
+    int data_type;
+    int end_prog;
+    int repeat;
+    int auto_init;
+    int priority;
+    int fs;
+    int sync;
+    int running;
+    int interrupts;
+    int status;
+    int signalled;
+    int post_sync;
+    int transfer;
+    uint16_t elements;
+    uint16_t frames;
+    uint16_t frame_index;
+    uint16_t element_index;
+    uint16_t cpc;
+
+    struct omap_dma_reg_set_s {
+        target_phys_addr_t src, dest;
+        int frame;
+        int element;
+        int frame_delta[2];
+        int elem_delta[2];
+        int frames;
+        int elements;
+    } active_set;
+};
+
+struct omap_dma_s {
+    qemu_irq *ih;
+    QEMUTimer *tm;
+    struct omap_mpu_state_s *mpu;
+    target_phys_addr_t base;
+    omap_clk clk;
+    int64_t delay;
+    uint32_t drq;
+
+    uint16_t gcr;
+    int run_count;
+
+    int chans;
+    struct omap_dma_channel_s ch[16];
+    struct omap_dma_lcd_channel_s lcd_ch;
+};
+
+static void omap_dma_interrupts_update(struct omap_dma_s *s)
+{
+    /* First three interrupts are shared between two channels each.  */
+    qemu_set_irq(s->ih[OMAP_INT_DMA_CH0_6],
+                    (s->ch[0].status | s->ch[6].status) & 0x3f);
+    qemu_set_irq(s->ih[OMAP_INT_DMA_CH1_7],
+                    (s->ch[1].status | s->ch[7].status) & 0x3f);
+    qemu_set_irq(s->ih[OMAP_INT_DMA_CH2_8],
+                    (s->ch[2].status | s->ch[8].status) & 0x3f);
+    qemu_set_irq(s->ih[OMAP_INT_DMA_CH3],
+                    (s->ch[3].status) & 0x3f);
+    qemu_set_irq(s->ih[OMAP_INT_DMA_CH4],
+                    (s->ch[4].status) & 0x3f);
+    qemu_set_irq(s->ih[OMAP_INT_DMA_CH5],
+                    (s->ch[5].status) & 0x3f);
+}
+
+static void omap_dma_channel_load(struct omap_dma_s *s, int ch)
+{
+    struct omap_dma_reg_set_s *a = &s->ch[ch].active_set;
+    int i;
+
+    /*
+     * TODO: verify address ranges and alignment
+     * TODO: port endianness
+     */
+
+    a->src = s->ch[ch].addr[0];
+    a->dest = s->ch[ch].addr[1];
+    a->frames = s->ch[ch].frames;
+    a->elements = s->ch[ch].elements;
+    a->frame = 0;
+    a->element = 0;
+
+    if (unlikely(!s->ch[ch].elements || !s->ch[ch].frames)) {
+        printf("%s: bad DMA request\n", __FUNCTION__);
+        return;
+    }
+
+    for (i = 0; i < 2; i ++)
+        switch (s->ch[ch].mode[i]) {
+        case constant:
+            a->elem_delta[i] = 0;
+            a->frame_delta[i] = 0;
+            break;
+        case post_incremented:
+            a->elem_delta[i] = s->ch[ch].data_type;
+            a->frame_delta[i] = 0;
+            break;
+        case single_index:
+            a->elem_delta[i] = s->ch[ch].data_type +
+                s->ch[ch].element_index - 1;
+            if (s->ch[ch].element_index > 0x7fff)
+                a->elem_delta[i] -= 0x10000;
+            a->frame_delta[i] = 0;
+            break;
+        case double_index:
+            a->elem_delta[i] = s->ch[ch].data_type +
+                s->ch[ch].element_index - 1;
+            if (s->ch[ch].element_index > 0x7fff)
+                a->elem_delta[i] -= 0x10000;
+            a->frame_delta[i] = s->ch[ch].frame_index -
+                s->ch[ch].element_index;
+            if (s->ch[ch].frame_index > 0x7fff)
+                a->frame_delta[i] -= 0x10000;
+            break;
+        default:
+            break;
+        }
+}
+
+static inline void omap_dma_request_run(struct omap_dma_s *s,
+                int channel, int request)
+{
+next_channel:
+    if (request > 0)
+        for (; channel < 9; channel ++)
+            if (s->ch[channel].sync == request && s->ch[channel].running)
+                break;
+    if (channel >= 9)
+        return;
+
+    if (s->ch[channel].transfer) {
+        if (request > 0) {
+            s->ch[channel ++].post_sync = request;
+            goto next_channel;
+        }
+        s->ch[channel].status |= 0x02;	/* Synchronisation drop */
+        omap_dma_interrupts_update(s);
+        return;
+    }
+
+    if (!s->ch[channel].signalled)
+        s->run_count ++;
+    s->ch[channel].signalled = 1;
+
+    if (request > 0)
+        s->ch[channel].status |= 0x40;	/* External request */
+
+    if (s->delay && !qemu_timer_pending(s->tm))
+        qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
+
+    if (request > 0) {
+        channel ++;
+        goto next_channel;
+    }
+}
+
+static inline void omap_dma_request_stop(struct omap_dma_s *s, int channel)
+{
+    if (s->ch[channel].signalled)
+        s->run_count --;
+    s->ch[channel].signalled = 0;
+
+    if (!s->run_count)
+        qemu_del_timer(s->tm);
+}
+
+static void omap_dma_channel_run(struct omap_dma_s *s)
+{
+    int ch;
+    uint16_t status;
+    uint8_t value[4];
+    struct omap_dma_port_if_s *src_p, *dest_p;
+    struct omap_dma_reg_set_s *a;
+
+    for (ch = 0; ch < 9; ch ++) {
+        a = &s->ch[ch].active_set;
+
+        src_p = &s->mpu->port[s->ch[ch].port[0]];
+        dest_p = &s->mpu->port[s->ch[ch].port[1]];
+        if (s->ch[ch].signalled && (!src_p->addr_valid(s->mpu, a->src) ||
+                    !dest_p->addr_valid(s->mpu, a->dest))) {
+#if 0
+            /* Bus time-out */
+            if (s->ch[ch].interrupts & 0x01)
+                s->ch[ch].status |= 0x01;
+            omap_dma_request_stop(s, ch);
+            continue;
+#endif
+            printf("%s: Bus time-out in DMA%i operation\n", __FUNCTION__, ch);
+        }
+
+        status = s->ch[ch].status;
+        while (status == s->ch[ch].status && s->ch[ch].signalled) {
+            /* Transfer a single element */
+            s->ch[ch].transfer = 1;
+            cpu_physical_memory_read(a->src, value, s->ch[ch].data_type);
+            cpu_physical_memory_write(a->dest, value, s->ch[ch].data_type);
+            s->ch[ch].transfer = 0;
+
+            a->src += a->elem_delta[0];
+            a->dest += a->elem_delta[1];
+            a->element ++;
+
+            /* Check interrupt conditions */
+            if (a->element == a->elements) {
+                a->element = 0;
+                a->src += a->frame_delta[0];
+                a->dest += a->frame_delta[1];
+                a->frame ++;
+
+                if (a->frame == a->frames) {
+                    if (!s->ch[ch].repeat || !s->ch[ch].auto_init)
+                        s->ch[ch].running = 0;
+
+                    if (s->ch[ch].auto_init &&
+                            (s->ch[ch].repeat ||
+                             s->ch[ch].end_prog))
+                        omap_dma_channel_load(s, ch);
+
+                    if (s->ch[ch].interrupts & 0x20)
+                        s->ch[ch].status |= 0x20;
+
+                    if (!s->ch[ch].sync)
+                        omap_dma_request_stop(s, ch);
+                }
+
+                if (s->ch[ch].interrupts & 0x08)
+                    s->ch[ch].status |= 0x08;
+
+                if (s->ch[ch].sync && s->ch[ch].fs &&
+                                !(s->drq & (1 << s->ch[ch].sync))) {
+                    s->ch[ch].status &= ~0x40;
+                    omap_dma_request_stop(s, ch);
+                }
+            }
+
+            if (a->element == 1 && a->frame == a->frames - 1)
+                if (s->ch[ch].interrupts & 0x10)
+                    s->ch[ch].status |= 0x10;
+
+            if (a->element == (a->elements >> 1))
+                if (s->ch[ch].interrupts & 0x04)
+                    s->ch[ch].status |= 0x04;
+
+            if (s->ch[ch].sync && !s->ch[ch].fs &&
+                            !(s->drq & (1 << s->ch[ch].sync))) {
+                s->ch[ch].status &= ~0x40;
+                omap_dma_request_stop(s, ch);
+            }
+
+            /*
+             * Process requests made while the element was
+             * being transferred.
+             */
+            if (s->ch[ch].post_sync) {
+                omap_dma_request_run(s, 0, s->ch[ch].post_sync);
+                s->ch[ch].post_sync = 0;
+            }
+
+#if 0
+            break;
+#endif
+        }
+
+        s->ch[ch].cpc = a->dest & 0x0000ffff;
+    }
+
+    omap_dma_interrupts_update(s);
+    if (s->run_count && s->delay)
+        qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
+}
+
+static int omap_dma_ch_reg_read(struct omap_dma_s *s,
+                int ch, int reg, uint16_t *value) {
+    switch (reg) {
+    case 0x00:	/* SYS_DMA_CSDP_CH0 */
+        *value = (s->ch[ch].burst[1] << 14) |
+                (s->ch[ch].pack[1] << 13) |
+                (s->ch[ch].port[1] << 9) |
+                (s->ch[ch].burst[0] << 7) |
+                (s->ch[ch].pack[0] << 6) |
+                (s->ch[ch].port[0] << 2) |
+                (s->ch[ch].data_type >> 1);
+        break;
+
+    case 0x02:	/* SYS_DMA_CCR_CH0 */
+        *value = (s->ch[ch].mode[1] << 14) |
+                (s->ch[ch].mode[0] << 12) |
+                (s->ch[ch].end_prog << 11) |
+                (s->ch[ch].repeat << 9) |
+                (s->ch[ch].auto_init << 8) |
+                (s->ch[ch].running << 7) |
+                (s->ch[ch].priority << 6) |
+                (s->ch[ch].fs << 5) | s->ch[ch].sync;
+        break;
+
+    case 0x04:	/* SYS_DMA_CICR_CH0 */
+        *value = s->ch[ch].interrupts;
+        break;
+
+    case 0x06:	/* SYS_DMA_CSR_CH0 */
+        /* FIXME: shared CSR for channels sharing the interrupts */
+        *value = s->ch[ch].status;
+        s->ch[ch].status &= 0x40;
+        omap_dma_interrupts_update(s);
+        break;
+
+    case 0x08:	/* SYS_DMA_CSSA_L_CH0 */
+        *value = s->ch[ch].addr[0] & 0x0000ffff;
+        break;
+
+    case 0x0a:	/* SYS_DMA_CSSA_U_CH0 */
+        *value = s->ch[ch].addr[0] >> 16;
+        break;
+
+    case 0x0c:	/* SYS_DMA_CDSA_L_CH0 */
+        *value = s->ch[ch].addr[1] & 0x0000ffff;
+        break;
+
+    case 0x0e:	/* SYS_DMA_CDSA_U_CH0 */
+        *value = s->ch[ch].addr[1] >> 16;
+        break;
+
+    case 0x10:	/* SYS_DMA_CEN_CH0 */
+        *value = s->ch[ch].elements;
+        break;
+
+    case 0x12:	/* SYS_DMA_CFN_CH0 */
+        *value = s->ch[ch].frames;
+        break;
+
+    case 0x14:	/* SYS_DMA_CFI_CH0 */
+        *value = s->ch[ch].frame_index;
+        break;
+
+    case 0x16:	/* SYS_DMA_CEI_CH0 */
+        *value = s->ch[ch].element_index;
+        break;
+
+    case 0x18:	/* SYS_DMA_CPC_CH0 */
+        *value = s->ch[ch].cpc;
+        break;
+
+    default:
+        return 1;
+    }
+    return 0;
+}
+
+static int omap_dma_ch_reg_write(struct omap_dma_s *s,
+                int ch, int reg, uint16_t value) {
+    switch (reg) {
+    case 0x00:	/* SYS_DMA_CSDP_CH0 */
+        s->ch[ch].burst[1] = (value & 0xc000) >> 14;
+        s->ch[ch].pack[1] = (value & 0x2000) >> 13;
+        s->ch[ch].port[1] = (enum omap_dma_port) ((value & 0x1e00) >> 9);
+        s->ch[ch].burst[0] = (value & 0x0180) >> 7;
+        s->ch[ch].pack[0] = (value & 0x0040) >> 6;
+        s->ch[ch].port[0] = (enum omap_dma_port) ((value & 0x003c) >> 2);
+        s->ch[ch].data_type = (1 << (value & 3));
+        if (s->ch[ch].port[0] >= omap_dma_port_last)
+            printf("%s: invalid DMA port %i\n", __FUNCTION__,
+                            s->ch[ch].port[0]);
+        if (s->ch[ch].port[1] >= omap_dma_port_last)
+            printf("%s: invalid DMA port %i\n", __FUNCTION__,
+                            s->ch[ch].port[1]);
+        if ((value & 3) == 3)
+            printf("%s: bad data_type for DMA channel %i\n", __FUNCTION__, ch);
+        break;
+
+    case 0x02:	/* SYS_DMA_CCR_CH0 */
+        s->ch[ch].mode[1] = (omap_dma_addressing_t) ((value & 0xc000) >> 14);
+        s->ch[ch].mode[0] = (omap_dma_addressing_t) ((value & 0x3000) >> 12);
+        s->ch[ch].end_prog = (value & 0x0800) >> 11;
+        s->ch[ch].repeat = (value & 0x0200) >> 9;
+        s->ch[ch].auto_init = (value & 0x0100) >> 8;
+        s->ch[ch].priority = (value & 0x0040) >> 6;
+        s->ch[ch].fs = (value & 0x0020) >> 5;
+        s->ch[ch].sync = value & 0x001f;
+        if (value & 0x0080) {
+            if (s->ch[ch].running) {
+                if (!s->ch[ch].signalled &&
+                                s->ch[ch].auto_init && s->ch[ch].end_prog)
+                    omap_dma_channel_load(s, ch);
+            } else {
+                s->ch[ch].running = 1;
+                omap_dma_channel_load(s, ch);
+            }
+            if (!s->ch[ch].sync || (s->drq & (1 << s->ch[ch].sync)))
+                omap_dma_request_run(s, ch, 0);
+        } else {
+            s->ch[ch].running = 0;
+            omap_dma_request_stop(s, ch);
+        }
+        break;
+
+    case 0x04:	/* SYS_DMA_CICR_CH0 */
+        s->ch[ch].interrupts = value & 0x003f;
+        break;
+
+    case 0x06:	/* SYS_DMA_CSR_CH0 */
+        return 1;
+
+    case 0x08:	/* SYS_DMA_CSSA_L_CH0 */
+        s->ch[ch].addr[0] &= 0xffff0000;
+        s->ch[ch].addr[0] |= value;
+        break;
+
+    case 0x0a:	/* SYS_DMA_CSSA_U_CH0 */
+        s->ch[ch].addr[0] &= 0x0000ffff;
+        s->ch[ch].addr[0] |= value << 16;
+        break;
+
+    case 0x0c:	/* SYS_DMA_CDSA_L_CH0 */
+        s->ch[ch].addr[1] &= 0xffff0000;
+        s->ch[ch].addr[1] |= value;
+        break;
+
+    case 0x0e:	/* SYS_DMA_CDSA_U_CH0 */
+        s->ch[ch].addr[1] &= 0x0000ffff;
+        s->ch[ch].addr[1] |= value << 16;
+        break;
+
+    case 0x10:	/* SYS_DMA_CEN_CH0 */
+        s->ch[ch].elements = value & 0xffff;
+        break;
+
+    case 0x12:	/* SYS_DMA_CFN_CH0 */
+        s->ch[ch].frames = value & 0xffff;
+        break;
+
+    case 0x14:	/* SYS_DMA_CFI_CH0 */
+        s->ch[ch].frame_index = value & 0xffff;
+        break;
+
+    case 0x16:	/* SYS_DMA_CEI_CH0 */
+        s->ch[ch].element_index = value & 0xffff;
+        break;
+
+    case 0x18:	/* SYS_DMA_CPC_CH0 */
+        return 1;
+
+    default:
+        OMAP_BAD_REG((unsigned long) reg);
+    }
+    return 0;
+}
+
+static uint32_t omap_dma_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int i, reg, ch, offset = addr - s->base;
+    uint16_t ret;
+
+    switch (offset) {
+    case 0x000 ... 0x2fe:
+        reg = offset & 0x3f;
+        ch = (offset >> 6) & 0x0f;
+        if (omap_dma_ch_reg_read(s, ch, reg, &ret))
+            break;
+        return ret;
+
+    case 0x300:	/* SYS_DMA_LCD_CTRL */
+        i = s->lcd_ch.condition;
+        s->lcd_ch.condition = 0;
+        qemu_irq_lower(s->lcd_ch.irq);
+        return ((s->lcd_ch.src == imif) << 6) | (i << 3) |
+                (s->lcd_ch.interrupts << 1) | s->lcd_ch.dual;
+
+    case 0x302:	/* SYS_DMA_LCD_TOP_F1_L */
+        return s->lcd_ch.src_f1_top & 0xffff;
+
+    case 0x304:	/* SYS_DMA_LCD_TOP_F1_U */
+        return s->lcd_ch.src_f1_top >> 16;
+
+    case 0x306:	/* SYS_DMA_LCD_BOT_F1_L */
+        return s->lcd_ch.src_f1_bottom & 0xffff;
+
+    case 0x308:	/* SYS_DMA_LCD_BOT_F1_U */
+        return s->lcd_ch.src_f1_bottom >> 16;
+
+    case 0x30a:	/* SYS_DMA_LCD_TOP_F2_L */
+        return s->lcd_ch.src_f2_top & 0xffff;
+
+    case 0x30c:	/* SYS_DMA_LCD_TOP_F2_U */
+        return s->lcd_ch.src_f2_top >> 16;
+
+    case 0x30e:	/* SYS_DMA_LCD_BOT_F2_L */
+        return s->lcd_ch.src_f2_bottom & 0xffff;
+
+    case 0x310:	/* SYS_DMA_LCD_BOT_F2_U */
+        return s->lcd_ch.src_f2_bottom >> 16;
+
+    case 0x400:	/* SYS_DMA_GCR */
+        return s->gcr;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_dma_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    int reg, ch, offset = addr - s->base;
+
+    switch (offset) {
+    case 0x000 ... 0x2fe:
+        reg = offset & 0x3f;
+        ch = (offset >> 6) & 0x0f;
+        if (omap_dma_ch_reg_write(s, ch, reg, value))
+            OMAP_RO_REG(addr);
+        break;
+
+    case 0x300:	/* SYS_DMA_LCD_CTRL */
+        s->lcd_ch.src = (value & 0x40) ? imif : emiff;
+        s->lcd_ch.condition = 0;
+        /* Assume no bus errors and thus no BUS_ERROR irq bits.  */
+        s->lcd_ch.interrupts = (value >> 1) & 1;
+        s->lcd_ch.dual = value & 1;
+        break;
+
+    case 0x302:	/* SYS_DMA_LCD_TOP_F1_L */
+        s->lcd_ch.src_f1_top &= 0xffff0000;
+        s->lcd_ch.src_f1_top |= 0x0000ffff & value;
+        break;
+
+    case 0x304:	/* SYS_DMA_LCD_TOP_F1_U */
+        s->lcd_ch.src_f1_top &= 0x0000ffff;
+        s->lcd_ch.src_f1_top |= value << 16;
+        break;
+
+    case 0x306:	/* SYS_DMA_LCD_BOT_F1_L */
+        s->lcd_ch.src_f1_bottom &= 0xffff0000;
+        s->lcd_ch.src_f1_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0x308:	/* SYS_DMA_LCD_BOT_F1_U */
+        s->lcd_ch.src_f1_bottom &= 0x0000ffff;
+        s->lcd_ch.src_f1_bottom |= value << 16;
+        break;
+
+    case 0x30a:	/* SYS_DMA_LCD_TOP_F2_L */
+        s->lcd_ch.src_f2_top &= 0xffff0000;
+        s->lcd_ch.src_f2_top |= 0x0000ffff & value;
+        break;
+
+    case 0x30c:	/* SYS_DMA_LCD_TOP_F2_U */
+        s->lcd_ch.src_f2_top &= 0x0000ffff;
+        s->lcd_ch.src_f2_top |= value << 16;
+        break;
+
+    case 0x30e:	/* SYS_DMA_LCD_BOT_F2_L */
+        s->lcd_ch.src_f2_bottom &= 0xffff0000;
+        s->lcd_ch.src_f2_bottom |= 0x0000ffff & value;
+        break;
+
+    case 0x310:	/* SYS_DMA_LCD_BOT_F2_U */
+        s->lcd_ch.src_f2_bottom &= 0x0000ffff;
+        s->lcd_ch.src_f2_bottom |= value << 16;
+        break;
+
+    case 0x400:	/* SYS_DMA_GCR */
+        s->gcr = value & 0x000c;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_dma_readfn[] = {
+    omap_badwidth_read16,
+    omap_dma_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc *omap_dma_writefn[] = {
+    omap_badwidth_write16,
+    omap_dma_write,
+    omap_badwidth_write16,
+};
+
+static void omap_dma_request(void *opaque, int drq, int req)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+    /* The request pins are level triggered.  */
+    if (req) {
+        if (~s->drq & (1 << drq)) {
+            s->drq |= 1 << drq;
+            omap_dma_request_run(s, 0, drq);
+        }
+    } else
+        s->drq &= ~(1 << drq);
+}
+
+static void omap_dma_clk_update(void *opaque, int line, int on)
+{
+    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
+
+    if (on) {
+        s->delay = ticks_per_sec >> 5;
+        if (s->run_count)
+            qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
+    } else {
+        s->delay = 0;
+        qemu_del_timer(s->tm);
+    }
+}
+
+static void omap_dma_reset(struct omap_dma_s *s)
+{
+    int i;
+
+    qemu_del_timer(s->tm);
+    s->gcr = 0x0004;
+    s->drq = 0x00000000;
+    s->run_count = 0;
+    s->lcd_ch.src = emiff;
+    s->lcd_ch.condition = 0;
+    s->lcd_ch.interrupts = 0;
+    s->lcd_ch.dual = 0;
+    memset(s->ch, 0, sizeof(s->ch));
+    for (i = 0; i < s->chans; i ++)
+        s->ch[i].interrupts = 0x0003;
+}
+
+struct omap_dma_s *omap_dma_init(target_phys_addr_t base,
+                qemu_irq pic[], struct omap_mpu_state_s *mpu, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_dma_s *s = (struct omap_dma_s *)
+            qemu_mallocz(sizeof(struct omap_dma_s));
+
+    s->ih = pic;
+    s->base = base;
+    s->chans = 9;
+    s->mpu = mpu;
+    s->clk = clk;
+    s->lcd_ch.irq = pic[OMAP_INT_DMA_LCD];
+    s->lcd_ch.mpu = mpu;
+    s->tm = qemu_new_timer(vm_clock, (QEMUTimerCB *) omap_dma_channel_run, s);
+    omap_clk_adduser(s->clk, qemu_allocate_irqs(omap_dma_clk_update, s, 1)[0]);
+    mpu->drq = qemu_allocate_irqs(omap_dma_request, s, 32);
+    omap_dma_reset(s);
+    omap_dma_clk_update(s, 0, 1);
+
+    iomemtype = cpu_register_io_memory(0, omap_dma_readfn,
+                    omap_dma_writefn, s);
+    cpu_register_physical_memory(s->base, 0x800, iomemtype);
+
+    return s;
+}
+
+/* DMA ports */
+int omap_validate_emiff_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return addr >= OMAP_EMIFF_BASE && addr < OMAP_EMIFF_BASE + s->sdram_size;
+}
+
+int omap_validate_emifs_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return addr >= OMAP_EMIFS_BASE && addr < OMAP_EMIFF_BASE;
+}
+
+int omap_validate_imif_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return addr >= OMAP_IMIF_BASE && addr < OMAP_IMIF_BASE + s->sram_size;
+}
+
+int omap_validate_tipb_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return addr >= 0xfffb0000 && addr < 0xffff0000;
+}
+
+int omap_validate_local_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return addr >= OMAP_LOCALBUS_BASE && addr < OMAP_LOCALBUS_BASE + 0x1000000;
+}
+
+int omap_validate_tipb_mpui_addr(struct omap_mpu_state_s *s,
+                target_phys_addr_t addr)
+{
+    return addr >= 0xe1010000 && addr < 0xe1020004;
+}
+
+/* MPU OS timers */
+struct omap_mpu_timer_s {
+    qemu_irq irq;
+    omap_clk clk;
+    target_phys_addr_t base;
+    uint32_t val;
+    int64_t time;
+    QEMUTimer *timer;
+    int64_t rate;
+    int it_ena;
+
+    int enable;
+    int ptv;
+    int ar;
+    int st;
+    uint32_t reset_val;
+};
+
+static inline uint32_t omap_timer_read(struct omap_mpu_timer_s *timer)
+{
+    uint64_t distance = qemu_get_clock(vm_clock) - timer->time;
+
+    if (timer->st && timer->enable && timer->rate)
+        return timer->val - muldiv64(distance >> (timer->ptv + 1),
+                        timer->rate, ticks_per_sec);
+    else
+        return timer->val;
+}
+
+static inline void omap_timer_sync(struct omap_mpu_timer_s *timer)
+{
+    timer->val = omap_timer_read(timer);
+    timer->time = qemu_get_clock(vm_clock);
+}
+
+static inline void omap_timer_update(struct omap_mpu_timer_s *timer)
+{
+    int64_t expires;
+
+    if (timer->enable && timer->st && timer->rate) {
+        timer->val = timer->reset_val;	/* Should skip this on clk enable */
+        expires = timer->time + muldiv64(timer->val << (timer->ptv + 1),
+                        ticks_per_sec, timer->rate);
+        qemu_mod_timer(timer->timer, expires);
+    } else
+        qemu_del_timer(timer->timer);
+}
+
+static void omap_timer_tick(void *opaque)
+{
+    struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque;
+    omap_timer_sync(timer);
+
+    if (!timer->ar) {
+        timer->val = 0;
+        timer->st = 0;
+    }
+
+    if (timer->it_ena)
+        qemu_irq_raise(timer->irq);
+    omap_timer_update(timer);
+}
+
+static void omap_timer_clk_update(void *opaque, int line, int on)
+{
+    struct omap_mpu_timer_s *timer = (struct omap_mpu_timer_s *) opaque;
+
+    omap_timer_sync(timer);
+    timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
+    omap_timer_update(timer);
+}
+
+static void omap_timer_clk_setup(struct omap_mpu_timer_s *timer)
+{
+    omap_clk_adduser(timer->clk,
+                    qemu_allocate_irqs(omap_timer_clk_update, timer, 1)[0]);
+    timer->rate = omap_clk_getrate(timer->clk);
+}
+
+static uint32_t omap_mpu_timer_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00:	/* CNTL_TIMER */
+        return (s->enable << 5) | (s->ptv << 2) | (s->ar << 1) | s->st;
+
+    case 0x04:	/* LOAD_TIM */
+        break;
+
+    case 0x08:	/* READ_TIM */
+        return omap_timer_read(s);
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mpu_timer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00:	/* CNTL_TIMER */
+        omap_timer_sync(s);
+        s->enable = (value >> 5) & 1;
+        s->ptv = (value >> 2) & 7;
+        s->ar = (value >> 1) & 1;
+        s->st = value & 1;
+        omap_timer_update(s);
+        return;
+
+    case 0x04:	/* LOAD_TIM */
+        s->reset_val = value;
+        return;
+
+    case 0x08:	/* READ_TIM */
+        OMAP_RO_REG(addr);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_mpu_timer_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_mpu_timer_read,
+};
+
+static CPUWriteMemoryFunc *omap_mpu_timer_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_mpu_timer_write,
+};
+
+static void omap_mpu_timer_reset(struct omap_mpu_timer_s *s)
+{
+    qemu_del_timer(s->timer);
+    s->enable = 0;
+    s->reset_val = 31337;
+    s->val = 0;
+    s->ptv = 0;
+    s->ar = 0;
+    s->st = 0;
+    s->it_ena = 1;
+}
+
+struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_mpu_timer_s *s = (struct omap_mpu_timer_s *)
+            qemu_mallocz(sizeof(struct omap_mpu_timer_s));
+
+    s->irq = irq;
+    s->clk = clk;
+    s->base = base;
+    s->timer = qemu_new_timer(vm_clock, omap_timer_tick, s);
+    omap_mpu_timer_reset(s);
+    omap_timer_clk_setup(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_mpu_timer_readfn,
+                    omap_mpu_timer_writefn, s);
+    cpu_register_physical_memory(s->base, 0x100, iomemtype);
+
+    return s;
+}
+
+/* Watchdog timer */
+struct omap_watchdog_timer_s {
+    struct omap_mpu_timer_s timer;
+    uint8_t last_wr;
+    int mode;
+    int free;
+    int reset;
+};
+
+static uint32_t omap_wd_timer_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
+    int offset = addr - s->timer.base;
+
+    switch (offset) {
+    case 0x00:	/* CNTL_TIMER */
+        return (s->timer.ptv << 9) | (s->timer.ar << 8) |
+                (s->timer.st << 7) | (s->free << 1);
+
+    case 0x04:	/* READ_TIMER */
+        return omap_timer_read(&s->timer);
+
+    case 0x08:	/* TIMER_MODE */
+        return s->mode << 15;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *) opaque;
+    int offset = addr - s->timer.base;
+
+    switch (offset) {
+    case 0x00:	/* CNTL_TIMER */
+        omap_timer_sync(&s->timer);
+        s->timer.ptv = (value >> 9) & 7;
+        s->timer.ar = (value >> 8) & 1;
+        s->timer.st = (value >> 7) & 1;
+        s->free = (value >> 1) & 1;
+        omap_timer_update(&s->timer);
+        break;
+
+    case 0x04:	/* LOAD_TIMER */
+        s->timer.reset_val = value & 0xffff;
+        break;
+
+    case 0x08:	/* TIMER_MODE */
+        if (!s->mode && ((value >> 15) & 1))
+            omap_clk_get(s->timer.clk);
+        s->mode |= (value >> 15) & 1;
+        if (s->last_wr == 0xf5) {
+            if ((value & 0xff) == 0xa0) {
+                s->mode = 0;
+                omap_clk_put(s->timer.clk);
+            } else {
+                /* XXX: on T|E hardware somehow this has no effect,
+                 * on Zire 71 it works as specified.  */
+                s->reset = 1;
+                qemu_system_reset_request();
+            }
+        }
+        s->last_wr = value & 0xff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_wd_timer_readfn[] = {
+    omap_badwidth_read16,
+    omap_wd_timer_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc *omap_wd_timer_writefn[] = {
+    omap_badwidth_write16,
+    omap_wd_timer_write,
+    omap_badwidth_write16,
+};
+
+static void omap_wd_timer_reset(struct omap_watchdog_timer_s *s)
+{
+    qemu_del_timer(s->timer.timer);
+    if (!s->mode)
+        omap_clk_get(s->timer.clk);
+    s->mode = 1;
+    s->free = 1;
+    s->reset = 0;
+    s->timer.enable = 1;
+    s->timer.it_ena = 1;
+    s->timer.reset_val = 0xffff;
+    s->timer.val = 0;
+    s->timer.st = 0;
+    s->timer.ptv = 0;
+    s->timer.ar = 0;
+    omap_timer_update(&s->timer);
+}
+
+struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_watchdog_timer_s *s = (struct omap_watchdog_timer_s *)
+            qemu_mallocz(sizeof(struct omap_watchdog_timer_s));
+
+    s->timer.irq = irq;
+    s->timer.clk = clk;
+    s->timer.base = base;
+    s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer);
+    omap_wd_timer_reset(s);
+    omap_timer_clk_setup(&s->timer);
+
+    iomemtype = cpu_register_io_memory(0, omap_wd_timer_readfn,
+                    omap_wd_timer_writefn, s);
+    cpu_register_physical_memory(s->timer.base, 0x100, iomemtype);
+
+    return s;
+}
+
+/* 32-kHz timer */
+struct omap_32khz_timer_s {
+    struct omap_mpu_timer_s timer;
+};
+
+static uint32_t omap_os_timer_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
+    int offset = addr - s->timer.base;
+
+    switch (offset) {
+    case 0x00:	/* TVR */
+        return s->timer.reset_val;
+
+    case 0x04:	/* TCR */
+        return omap_timer_read(&s->timer);
+
+    case 0x08:	/* CR */
+        return (s->timer.ar << 3) | (s->timer.it_ena << 2) | s->timer.st;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_os_timer_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *) opaque;
+    int offset = addr - s->timer.base;
+
+    switch (offset) {
+    case 0x00:	/* TVR */
+        s->timer.reset_val = value & 0x00ffffff;
+        break;
+
+    case 0x04:	/* TCR */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x08:	/* CR */
+        s->timer.ar = (value >> 3) & 1;
+        s->timer.it_ena = (value >> 2) & 1;
+        if (s->timer.st != (value & 1) || (value & 2)) {
+            omap_timer_sync(&s->timer);
+            s->timer.enable = value & 1;
+            s->timer.st = value & 1;
+            omap_timer_update(&s->timer);
+        }
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_os_timer_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_os_timer_read,
+};
+
+static CPUWriteMemoryFunc *omap_os_timer_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_os_timer_write,
+};
+
+static void omap_os_timer_reset(struct omap_32khz_timer_s *s)
+{
+    qemu_del_timer(s->timer.timer);
+    s->timer.enable = 0;
+    s->timer.it_ena = 0;
+    s->timer.reset_val = 0x00ffffff;
+    s->timer.val = 0;
+    s->timer.st = 0;
+    s->timer.ptv = 0;
+    s->timer.ar = 1;
+}
+
+struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_32khz_timer_s *s = (struct omap_32khz_timer_s *)
+            qemu_mallocz(sizeof(struct omap_32khz_timer_s));
+
+    s->timer.irq = irq;
+    s->timer.clk = clk;
+    s->timer.base = base;
+    s->timer.timer = qemu_new_timer(vm_clock, omap_timer_tick, &s->timer);
+    omap_os_timer_reset(s);
+    omap_timer_clk_setup(&s->timer);
+
+    iomemtype = cpu_register_io_memory(0, omap_os_timer_readfn,
+                    omap_os_timer_writefn, s);
+    cpu_register_physical_memory(s->timer.base, 0x800, iomemtype);
+
+    return s;
+}
+
+/* Ultra Low-Power Device Module */
+static uint32_t omap_ulpd_pm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->ulpd_pm_base;
+    uint16_t ret;
+
+    switch (offset) {
+    case 0x14:	/* IT_STATUS */
+        ret = s->ulpd_pm_regs[offset >> 2];
+        s->ulpd_pm_regs[offset >> 2] = 0;
+        qemu_irq_lower(s->irq[1][OMAP_INT_GAUGE_32K]);
+        return ret;
+
+    case 0x18:	/* Reserved */
+    case 0x1c:	/* Reserved */
+    case 0x20:	/* Reserved */
+    case 0x28:	/* Reserved */
+    case 0x2c:	/* Reserved */
+        OMAP_BAD_REG(addr);
+    case 0x00:	/* COUNTER_32_LSB */
+    case 0x04:	/* COUNTER_32_MSB */
+    case 0x08:	/* COUNTER_HIGH_FREQ_LSB */
+    case 0x0c:	/* COUNTER_HIGH_FREQ_MSB */
+    case 0x10:	/* GAUGING_CTRL */
+    case 0x24:	/* SETUP_ANALOG_CELL3_ULPD1 */
+    case 0x30:	/* CLOCK_CTRL */
+    case 0x34:	/* SOFT_REQ */
+    case 0x38:	/* COUNTER_32_FIQ */
+    case 0x3c:	/* DPLL_CTRL */
+    case 0x40:	/* STATUS_REQ */
+        /* XXX: check clk::usecount state for every clock */
+    case 0x48:	/* LOCL_TIME */
+    case 0x4c:	/* APLL_CTRL */
+    case 0x50:	/* POWER_CTRL */
+        return s->ulpd_pm_regs[offset >> 2];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static inline void omap_ulpd_clk_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    if (diff & (1 << 4))				/* USB_MCLK_EN */
+        omap_clk_onoff(omap_findclk(s, "usb_clk0"), (value >> 4) & 1);
+    if (diff & (1 << 5))				/* DIS_USB_PVCI_CLK */
+        omap_clk_onoff(omap_findclk(s, "usb_w2fc_ck"), (~value >> 5) & 1);
+}
+
+static inline void omap_ulpd_req_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    if (diff & (1 << 0))				/* SOFT_DPLL_REQ */
+        omap_clk_canidle(omap_findclk(s, "dpll4"), (~value >> 0) & 1);
+    if (diff & (1 << 1))				/* SOFT_COM_REQ */
+        omap_clk_canidle(omap_findclk(s, "com_mclk_out"), (~value >> 1) & 1);
+    if (diff & (1 << 2))				/* SOFT_SDW_REQ */
+        omap_clk_canidle(omap_findclk(s, "bt_mclk_out"), (~value >> 2) & 1);
+    if (diff & (1 << 3))				/* SOFT_USB_REQ */
+        omap_clk_canidle(omap_findclk(s, "usb_clk0"), (~value >> 3) & 1);
+}
+
+static void omap_ulpd_pm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->ulpd_pm_base;
+    int64_t now, ticks;
+    int div, mult;
+    static const int bypass_div[4] = { 1, 2, 4, 4 };
+    uint16_t diff;
+
+    switch (offset) {
+    case 0x00:	/* COUNTER_32_LSB */
+    case 0x04:	/* COUNTER_32_MSB */
+    case 0x08:	/* COUNTER_HIGH_FREQ_LSB */
+    case 0x0c:	/* COUNTER_HIGH_FREQ_MSB */
+    case 0x14:	/* IT_STATUS */
+    case 0x40:	/* STATUS_REQ */
+        OMAP_RO_REG(addr);
+        break;
+
+    case 0x10:	/* GAUGING_CTRL */
+        /* Bits 0 and 1 seem to be confused in the OMAP 310 TRM */
+        if ((s->ulpd_pm_regs[offset >> 2] ^ value) & 1) {
+            now = qemu_get_clock(vm_clock);
+
+            if (value & 1)
+                s->ulpd_gauge_start = now;
+            else {
+                now -= s->ulpd_gauge_start;
+
+                /* 32-kHz ticks */
+                ticks = muldiv64(now, 32768, ticks_per_sec);
+                s->ulpd_pm_regs[0x00 >> 2] = (ticks >>  0) & 0xffff;
+                s->ulpd_pm_regs[0x04 >> 2] = (ticks >> 16) & 0xffff;
+                if (ticks >> 32)	/* OVERFLOW_32K */
+                    s->ulpd_pm_regs[0x14 >> 2] |= 1 << 2;
+
+                /* High frequency ticks */
+                ticks = muldiv64(now, 12000000, ticks_per_sec);
+                s->ulpd_pm_regs[0x08 >> 2] = (ticks >>  0) & 0xffff;
+                s->ulpd_pm_regs[0x0c >> 2] = (ticks >> 16) & 0xffff;
+                if (ticks >> 32)	/* OVERFLOW_HI_FREQ */
+                    s->ulpd_pm_regs[0x14 >> 2] |= 1 << 1;
+
+                s->ulpd_pm_regs[0x14 >> 2] |= 1 << 0;	/* IT_GAUGING */
+                qemu_irq_raise(s->irq[1][OMAP_INT_GAUGE_32K]);
+            }
+        }
+        s->ulpd_pm_regs[offset >> 2] = value;
+        break;
+
+    case 0x18:	/* Reserved */
+    case 0x1c:	/* Reserved */
+    case 0x20:	/* Reserved */
+    case 0x28:	/* Reserved */
+    case 0x2c:	/* Reserved */
+        OMAP_BAD_REG(addr);
+    case 0x24:	/* SETUP_ANALOG_CELL3_ULPD1 */
+    case 0x38:	/* COUNTER_32_FIQ */
+    case 0x48:	/* LOCL_TIME */
+    case 0x50:	/* POWER_CTRL */
+        s->ulpd_pm_regs[offset >> 2] = value;
+        break;
+
+    case 0x30:	/* CLOCK_CTRL */
+        diff = s->ulpd_pm_regs[offset >> 2] ^ value;
+        s->ulpd_pm_regs[offset >> 2] = value & 0x3f;
+        omap_ulpd_clk_update(s, diff, value);
+        break;
+
+    case 0x34:	/* SOFT_REQ */
+        diff = s->ulpd_pm_regs[offset >> 2] ^ value;
+        s->ulpd_pm_regs[offset >> 2] = value & 0x1f;
+        omap_ulpd_req_update(s, diff, value);
+        break;
+
+    case 0x3c:	/* DPLL_CTRL */
+        /* XXX: OMAP310 TRM claims bit 3 is PLL_ENABLE, and bit 4 is
+         * omitted altogether, probably a typo.  */
+        /* This register has identical semantics with DPLL(1:3) control
+         * registers, see omap_dpll_write() */
+        diff = s->ulpd_pm_regs[offset >> 2] & value;
+        s->ulpd_pm_regs[offset >> 2] = value & 0x2fff;
+        if (diff & (0x3ff << 2)) {
+            if (value & (1 << 4)) {			/* PLL_ENABLE */
+                div = ((value >> 5) & 3) + 1;		/* PLL_DIV */
+                mult = MIN((value >> 7) & 0x1f, 1);	/* PLL_MULT */
+            } else {
+                div = bypass_div[((value >> 2) & 3)];	/* BYPASS_DIV */
+                mult = 1;
+            }
+            omap_clk_setrate(omap_findclk(s, "dpll4"), div, mult);
+        }
+
+        /* Enter the desired mode.  */
+        s->ulpd_pm_regs[offset >> 2] =
+                (s->ulpd_pm_regs[offset >> 2] & 0xfffe) |
+                ((s->ulpd_pm_regs[offset >> 2] >> 4) & 1);
+
+        /* Act as if the lock is restored.  */
+        s->ulpd_pm_regs[offset >> 2] |= 2;
+        break;
+
+    case 0x4c:	/* APLL_CTRL */
+        diff = s->ulpd_pm_regs[offset >> 2] & value;
+        s->ulpd_pm_regs[offset >> 2] = value & 0xf;
+        if (diff & (1 << 0))				/* APLL_NDPLL_SWITCH */
+            omap_clk_reparent(omap_findclk(s, "ck_48m"), omap_findclk(s,
+                                    (value & (1 << 0)) ? "apll" : "dpll4"));
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_ulpd_pm_readfn[] = {
+    omap_badwidth_read16,
+    omap_ulpd_pm_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc *omap_ulpd_pm_writefn[] = {
+    omap_badwidth_write16,
+    omap_ulpd_pm_write,
+    omap_badwidth_write16,
+};
+
+static void omap_ulpd_pm_reset(struct omap_mpu_state_s *mpu)
+{
+    mpu->ulpd_pm_regs[0x00 >> 2] = 0x0001;
+    mpu->ulpd_pm_regs[0x04 >> 2] = 0x0000;
+    mpu->ulpd_pm_regs[0x08 >> 2] = 0x0001;
+    mpu->ulpd_pm_regs[0x0c >> 2] = 0x0000;
+    mpu->ulpd_pm_regs[0x10 >> 2] = 0x0000;
+    mpu->ulpd_pm_regs[0x18 >> 2] = 0x01;
+    mpu->ulpd_pm_regs[0x1c >> 2] = 0x01;
+    mpu->ulpd_pm_regs[0x20 >> 2] = 0x01;
+    mpu->ulpd_pm_regs[0x24 >> 2] = 0x03ff;
+    mpu->ulpd_pm_regs[0x28 >> 2] = 0x01;
+    mpu->ulpd_pm_regs[0x2c >> 2] = 0x01;
+    omap_ulpd_clk_update(mpu, mpu->ulpd_pm_regs[0x30 >> 2], 0x0000);
+    mpu->ulpd_pm_regs[0x30 >> 2] = 0x0000;
+    omap_ulpd_req_update(mpu, mpu->ulpd_pm_regs[0x34 >> 2], 0x0000);
+    mpu->ulpd_pm_regs[0x34 >> 2] = 0x0000;
+    mpu->ulpd_pm_regs[0x38 >> 2] = 0x0001;
+    mpu->ulpd_pm_regs[0x3c >> 2] = 0x2211;
+    mpu->ulpd_pm_regs[0x40 >> 2] = 0x0000; /* FIXME: dump a real STATUS_REQ */
+    mpu->ulpd_pm_regs[0x48 >> 2] = 0x960;
+    mpu->ulpd_pm_regs[0x4c >> 2] = 0x08;
+    mpu->ulpd_pm_regs[0x50 >> 2] = 0x08;
+    omap_clk_setrate(omap_findclk(mpu, "dpll4"), 1, 4);
+    omap_clk_reparent(omap_findclk(mpu, "ck_48m"), omap_findclk(mpu, "dpll4"));
+}
+
+static void omap_ulpd_pm_init(target_phys_addr_t base,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(0, omap_ulpd_pm_readfn,
+                    omap_ulpd_pm_writefn, mpu);
+
+    mpu->ulpd_pm_base = base;
+    cpu_register_physical_memory(mpu->ulpd_pm_base, 0x800, iomemtype);
+    omap_ulpd_pm_reset(mpu);
+}
+
+/* OMAP Pin Configuration */
+static uint32_t omap_pin_cfg_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->pin_cfg_base;
+
+    switch (offset) {
+    case 0x00:	/* FUNC_MUX_CTRL_0 */
+    case 0x04:	/* FUNC_MUX_CTRL_1 */
+    case 0x08:	/* FUNC_MUX_CTRL_2 */
+        return s->func_mux_ctrl[offset >> 2];
+
+    case 0x0c:	/* COMP_MODE_CTRL_0 */
+        return s->comp_mode_ctrl[0];
+
+    case 0x10:	/* FUNC_MUX_CTRL_3 */
+    case 0x14:	/* FUNC_MUX_CTRL_4 */
+    case 0x18:	/* FUNC_MUX_CTRL_5 */
+    case 0x1c:	/* FUNC_MUX_CTRL_6 */
+    case 0x20:	/* FUNC_MUX_CTRL_7 */
+    case 0x24:	/* FUNC_MUX_CTRL_8 */
+    case 0x28:	/* FUNC_MUX_CTRL_9 */
+    case 0x2c:	/* FUNC_MUX_CTRL_A */
+    case 0x30:	/* FUNC_MUX_CTRL_B */
+    case 0x34:	/* FUNC_MUX_CTRL_C */
+    case 0x38:	/* FUNC_MUX_CTRL_D */
+        return s->func_mux_ctrl[(offset >> 2) - 1];
+
+    case 0x40:	/* PULL_DWN_CTRL_0 */
+    case 0x44:	/* PULL_DWN_CTRL_1 */
+    case 0x48:	/* PULL_DWN_CTRL_2 */
+    case 0x4c:	/* PULL_DWN_CTRL_3 */
+        return s->pull_dwn_ctrl[(offset & 0xf) >> 2];
+
+    case 0x50:	/* GATE_INH_CTRL_0 */
+        return s->gate_inh_ctrl[0];
+
+    case 0x60:	/* VOLTAGE_CTRL_0 */
+        return s->voltage_ctrl[0];
+
+    case 0x70:	/* TEST_DBG_CTRL_0 */
+        return s->test_dbg_ctrl[0];
+
+    case 0x80:	/* MOD_CONF_CTRL_0 */
+        return s->mod_conf_ctrl[0];
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static inline void omap_pin_funcmux0_update(struct omap_mpu_state_s *s,
+                uint32_t diff, uint32_t value)
+{
+    if (s->compat1509) {
+        if (diff & (1 << 9))			/* BLUETOOTH */
+            omap_clk_onoff(omap_findclk(s, "bt_mclk_out"),
+                            (~value >> 9) & 1);
+        if (diff & (1 << 7))			/* USB.CLKO */
+            omap_clk_onoff(omap_findclk(s, "usb.clko"),
+                            (value >> 7) & 1);
+    }
+}
+
+static inline void omap_pin_funcmux1_update(struct omap_mpu_state_s *s,
+                uint32_t diff, uint32_t value)
+{
+    if (s->compat1509) {
+        if (diff & (1 << 31))			/* MCBSP3_CLK_HIZ_DI */
+            omap_clk_onoff(omap_findclk(s, "mcbsp3.clkx"),
+                            (value >> 31) & 1);
+        if (diff & (1 << 1))			/* CLK32K */
+            omap_clk_onoff(omap_findclk(s, "clk32k_out"),
+                            (~value >> 1) & 1);
+    }
+}
+
+static inline void omap_pin_modconf1_update(struct omap_mpu_state_s *s,
+                uint32_t diff, uint32_t value)
+{
+    if (diff & (1 << 31))			/* CONF_MOD_UART3_CLK_MODE_R */
+         omap_clk_reparent(omap_findclk(s, "uart3_ck"),
+                         omap_findclk(s, ((value >> 31) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 30))			/* CONF_MOD_UART2_CLK_MODE_R */
+         omap_clk_reparent(omap_findclk(s, "uart2_ck"),
+                         omap_findclk(s, ((value >> 30) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 29))			/* CONF_MOD_UART1_CLK_MODE_R */
+         omap_clk_reparent(omap_findclk(s, "uart1_ck"),
+                         omap_findclk(s, ((value >> 29) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 23))			/* CONF_MOD_MMC_SD_CLK_REQ_R */
+         omap_clk_reparent(omap_findclk(s, "mmc_ck"),
+                         omap_findclk(s, ((value >> 23) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 12))			/* CONF_MOD_COM_MCLK_12_48_S */
+         omap_clk_reparent(omap_findclk(s, "com_mclk_out"),
+                         omap_findclk(s, ((value >> 12) & 1) ?
+                                 "ck_48m" : "armper_ck"));
+    if (diff & (1 << 9))			/* CONF_MOD_USB_HOST_HHC_UHO */
+         omap_clk_onoff(omap_findclk(s, "usb_hhc_ck"), (value >> 9) & 1);
+}
+
+static void omap_pin_cfg_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->pin_cfg_base;
+    uint32_t diff;
+
+    switch (offset) {
+    case 0x00:	/* FUNC_MUX_CTRL_0 */
+        diff = s->func_mux_ctrl[offset >> 2] ^ value;
+        s->func_mux_ctrl[offset >> 2] = value;
+        omap_pin_funcmux0_update(s, diff, value);
+        return;
+
+    case 0x04:	/* FUNC_MUX_CTRL_1 */
+        diff = s->func_mux_ctrl[offset >> 2] ^ value;
+        s->func_mux_ctrl[offset >> 2] = value;
+        omap_pin_funcmux1_update(s, diff, value);
+        return;
+
+    case 0x08:	/* FUNC_MUX_CTRL_2 */
+        s->func_mux_ctrl[offset >> 2] = value;
+        return;
+
+    case 0x0c:	/* COMP_MODE_CTRL_0 */
+        s->comp_mode_ctrl[0] = value;
+        s->compat1509 = (value != 0x0000eaef);
+        omap_pin_funcmux0_update(s, ~0, s->func_mux_ctrl[0]);
+        omap_pin_funcmux1_update(s, ~0, s->func_mux_ctrl[1]);
+        return;
+
+    case 0x10:	/* FUNC_MUX_CTRL_3 */
+    case 0x14:	/* FUNC_MUX_CTRL_4 */
+    case 0x18:	/* FUNC_MUX_CTRL_5 */
+    case 0x1c:	/* FUNC_MUX_CTRL_6 */
+    case 0x20:	/* FUNC_MUX_CTRL_7 */
+    case 0x24:	/* FUNC_MUX_CTRL_8 */
+    case 0x28:	/* FUNC_MUX_CTRL_9 */
+    case 0x2c:	/* FUNC_MUX_CTRL_A */
+    case 0x30:	/* FUNC_MUX_CTRL_B */
+    case 0x34:	/* FUNC_MUX_CTRL_C */
+    case 0x38:	/* FUNC_MUX_CTRL_D */
+        s->func_mux_ctrl[(offset >> 2) - 1] = value;
+        return;
+
+    case 0x40:	/* PULL_DWN_CTRL_0 */
+    case 0x44:	/* PULL_DWN_CTRL_1 */
+    case 0x48:	/* PULL_DWN_CTRL_2 */
+    case 0x4c:	/* PULL_DWN_CTRL_3 */
+        s->pull_dwn_ctrl[(offset & 0xf) >> 2] = value;
+        return;
+
+    case 0x50:	/* GATE_INH_CTRL_0 */
+        s->gate_inh_ctrl[0] = value;
+        return;
+
+    case 0x60:	/* VOLTAGE_CTRL_0 */
+        s->voltage_ctrl[0] = value;
+        return;
+
+    case 0x70:	/* TEST_DBG_CTRL_0 */
+        s->test_dbg_ctrl[0] = value;
+        return;
+
+    case 0x80:	/* MOD_CONF_CTRL_0 */
+        diff = s->mod_conf_ctrl[0] ^ value;
+        s->mod_conf_ctrl[0] = value;
+        omap_pin_modconf1_update(s, diff, value);
+        return;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_pin_cfg_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_pin_cfg_read,
+};
+
+static CPUWriteMemoryFunc *omap_pin_cfg_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_pin_cfg_write,
+};
+
+static void omap_pin_cfg_reset(struct omap_mpu_state_s *mpu)
+{
+    /* Start in Compatibility Mode.  */
+    mpu->compat1509 = 1;
+    omap_pin_funcmux0_update(mpu, mpu->func_mux_ctrl[0], 0);
+    omap_pin_funcmux1_update(mpu, mpu->func_mux_ctrl[1], 0);
+    omap_pin_modconf1_update(mpu, mpu->mod_conf_ctrl[0], 0);
+    memset(mpu->func_mux_ctrl, 0, sizeof(mpu->func_mux_ctrl));
+    memset(mpu->comp_mode_ctrl, 0, sizeof(mpu->comp_mode_ctrl));
+    memset(mpu->pull_dwn_ctrl, 0, sizeof(mpu->pull_dwn_ctrl));
+    memset(mpu->gate_inh_ctrl, 0, sizeof(mpu->gate_inh_ctrl));
+    memset(mpu->voltage_ctrl, 0, sizeof(mpu->voltage_ctrl));
+    memset(mpu->test_dbg_ctrl, 0, sizeof(mpu->test_dbg_ctrl));
+    memset(mpu->mod_conf_ctrl, 0, sizeof(mpu->mod_conf_ctrl));
+}
+
+static void omap_pin_cfg_init(target_phys_addr_t base,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(0, omap_pin_cfg_readfn,
+                    omap_pin_cfg_writefn, mpu);
+
+    mpu->pin_cfg_base = base;
+    cpu_register_physical_memory(mpu->pin_cfg_base, 0x800, iomemtype);
+    omap_pin_cfg_reset(mpu);
+}
+
+/* Device Identification, Die Identification */
+static uint32_t omap_id_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+
+    switch (addr) {
+    case 0xfffe1800:	/* DIE_ID_LSB */
+        return 0xc9581f0e;
+    case 0xfffe1804:	/* DIE_ID_MSB */
+        return 0xa8858bfa;
+
+    case 0xfffe2000:	/* PRODUCT_ID_LSB */
+        return 0x00aaaafc;
+    case 0xfffe2004:	/* PRODUCT_ID_MSB */
+        return 0xcafeb574;
+
+    case 0xfffed400:	/* JTAG_ID_LSB */
+        switch (s->mpu_model) {
+        case omap310:
+            return 0x03310315;
+        case omap1510:
+            return 0x03310115;
+        }
+        break;
+
+    case 0xfffed404:	/* JTAG_ID_MSB */
+        switch (s->mpu_model) {
+        case omap310:
+            return 0xfb57402f;
+        case omap1510:
+            return 0xfb47002f;
+        }
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_id_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    OMAP_BAD_REG(addr);
+}
+
+static CPUReadMemoryFunc *omap_id_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_id_read,
+};
+
+static CPUWriteMemoryFunc *omap_id_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_id_write,
+};
+
+static void omap_id_init(struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(0, omap_id_readfn,
+                    omap_id_writefn, mpu);
+    cpu_register_physical_memory(0xfffe1800, 0x800, iomemtype);
+    cpu_register_physical_memory(0xfffed400, 0x100, iomemtype);
+    if (!cpu_is_omap15xx(mpu))
+        cpu_register_physical_memory(0xfffe2000, 0x800, iomemtype);
+}
+
+/* MPUI Control (Dummy) */
+static uint32_t omap_mpui_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->mpui_base;
+
+    switch (offset) {
+    case 0x00:	/* CTRL */
+        return s->mpui_ctrl;
+    case 0x04:	/* DEBUG_ADDR */
+        return 0x01ffffff;
+    case 0x08:	/* DEBUG_DATA */
+        return 0xffffffff;
+    case 0x0c:	/* DEBUG_FLAG */
+        return 0x00000800;
+    case 0x10:	/* STATUS */
+        return 0x00000000;
+
+    /* Not in OMAP310 */
+    case 0x14:	/* DSP_STATUS */
+    case 0x18:	/* DSP_BOOT_CONFIG */
+        return 0x00000000;
+    case 0x1c:	/* DSP_MPUI_CONFIG */
+        return 0x0000ffff;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_mpui_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->mpui_base;
+
+    switch (offset) {
+    case 0x00:	/* CTRL */
+        s->mpui_ctrl = value & 0x007fffff;
+        break;
+
+    case 0x04:	/* DEBUG_ADDR */
+    case 0x08:	/* DEBUG_DATA */
+    case 0x0c:	/* DEBUG_FLAG */
+    case 0x10:	/* STATUS */
+    /* Not in OMAP310 */
+    case 0x14:	/* DSP_STATUS */
+        OMAP_RO_REG(addr);
+    case 0x18:	/* DSP_BOOT_CONFIG */
+    case 0x1c:	/* DSP_MPUI_CONFIG */
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_mpui_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_mpui_read,
+};
+
+static CPUWriteMemoryFunc *omap_mpui_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_mpui_write,
+};
+
+static void omap_mpui_reset(struct omap_mpu_state_s *s)
+{
+    s->mpui_ctrl = 0x0003ff1b;
+}
+
+static void omap_mpui_init(target_phys_addr_t base,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(0, omap_mpui_readfn,
+                    omap_mpui_writefn, mpu);
+
+    mpu->mpui_base = base;
+    cpu_register_physical_memory(mpu->mpui_base, 0x100, iomemtype);
+
+    omap_mpui_reset(mpu);
+}
+
+/* TIPB Bridges */
+struct omap_tipb_bridge_s {
+    target_phys_addr_t base;
+    qemu_irq abort;
+
+    int width_intr;
+    uint16_t control;
+    uint16_t alloc;
+    uint16_t buffer;
+    uint16_t enh_control;
+};
+
+static uint32_t omap_tipb_bridge_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00:	/* TIPB_CNTL */
+        return s->control;
+    case 0x04:	/* TIPB_BUS_ALLOC */
+        return s->alloc;
+    case 0x08:	/* MPU_TIPB_CNTL */
+        return s->buffer;
+    case 0x0c:	/* ENHANCED_TIPB_CNTL */
+        return s->enh_control;
+    case 0x10:	/* ADDRESS_DBG */
+    case 0x14:	/* DATA_DEBUG_LOW */
+    case 0x18:	/* DATA_DEBUG_HIGH */
+        return 0xffff;
+    case 0x1c:	/* DEBUG_CNTR_SIG */
+        return 0x00f8;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_tipb_bridge_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00:	/* TIPB_CNTL */
+        s->control = value & 0xffff;
+        break;
+
+    case 0x04:	/* TIPB_BUS_ALLOC */
+        s->alloc = value & 0x003f;
+        break;
+
+    case 0x08:	/* MPU_TIPB_CNTL */
+        s->buffer = value & 0x0003;
+        break;
+
+    case 0x0c:	/* ENHANCED_TIPB_CNTL */
+        s->width_intr = !(value & 2);
+        s->enh_control = value & 0x000f;
+        break;
+
+    case 0x10:	/* ADDRESS_DBG */
+    case 0x14:	/* DATA_DEBUG_LOW */
+    case 0x18:	/* DATA_DEBUG_HIGH */
+    case 0x1c:	/* DEBUG_CNTR_SIG */
+        OMAP_RO_REG(addr);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_tipb_bridge_readfn[] = {
+    omap_badwidth_read16,
+    omap_tipb_bridge_read,
+    omap_tipb_bridge_read,
+};
+
+static CPUWriteMemoryFunc *omap_tipb_bridge_writefn[] = {
+    omap_badwidth_write16,
+    omap_tipb_bridge_write,
+    omap_tipb_bridge_write,
+};
+
+static void omap_tipb_bridge_reset(struct omap_tipb_bridge_s *s)
+{
+    s->control = 0xffff;
+    s->alloc = 0x0009;
+    s->buffer = 0x0000;
+    s->enh_control = 0x000f;
+}
+
+struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base,
+                qemu_irq abort_irq, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_tipb_bridge_s *s = (struct omap_tipb_bridge_s *)
+            qemu_mallocz(sizeof(struct omap_tipb_bridge_s));
+
+    s->abort = abort_irq;
+    s->base = base;
+    omap_tipb_bridge_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_tipb_bridge_readfn,
+                    omap_tipb_bridge_writefn, s);
+    cpu_register_physical_memory(s->base, 0x100, iomemtype);
+
+    return s;
+}
+
+/* Dummy Traffic Controller's Memory Interface */
+static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->tcmi_base;
+    uint32_t ret;
+
+    switch (offset) {
+    case 0xfffecc00:	/* IMIF_PRIO */
+    case 0xfffecc04:	/* EMIFS_PRIO */
+    case 0xfffecc08:	/* EMIFF_PRIO */
+    case 0xfffecc0c:	/* EMIFS_CONFIG */
+    case 0xfffecc10:	/* EMIFS_CS0_CONFIG */
+    case 0xfffecc14:	/* EMIFS_CS1_CONFIG */
+    case 0xfffecc18:	/* EMIFS_CS2_CONFIG */
+    case 0xfffecc1c:	/* EMIFS_CS3_CONFIG */
+    case 0xfffecc24:	/* EMIFF_MRS */
+    case 0xfffecc28:	/* TIMEOUT1 */
+    case 0xfffecc2c:	/* TIMEOUT2 */
+    case 0xfffecc30:	/* TIMEOUT3 */
+    case 0xfffecc3c:	/* EMIFF_SDRAM_CONFIG_2 */
+    case 0xfffecc40:	/* EMIFS_CFG_DYN_WAIT */
+        return s->tcmi_regs[offset >> 2];
+
+    case 0xfffecc20:	/* EMIFF_SDRAM_CONFIG */
+        ret = s->tcmi_regs[offset >> 2];
+        s->tcmi_regs[offset >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */
+        /* XXX: We can try using the VGA_DIRTY flag for this */
+        return ret;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_tcmi_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->tcmi_base;
+
+    switch (offset) {
+    case 0xfffecc00:	/* IMIF_PRIO */
+    case 0xfffecc04:	/* EMIFS_PRIO */
+    case 0xfffecc08:	/* EMIFF_PRIO */
+    case 0xfffecc10:	/* EMIFS_CS0_CONFIG */
+    case 0xfffecc14:	/* EMIFS_CS1_CONFIG */
+    case 0xfffecc18:	/* EMIFS_CS2_CONFIG */
+    case 0xfffecc1c:	/* EMIFS_CS3_CONFIG */
+    case 0xfffecc20:	/* EMIFF_SDRAM_CONFIG */
+    case 0xfffecc24:	/* EMIFF_MRS */
+    case 0xfffecc28:	/* TIMEOUT1 */
+    case 0xfffecc2c:	/* TIMEOUT2 */
+    case 0xfffecc30:	/* TIMEOUT3 */
+    case 0xfffecc3c:	/* EMIFF_SDRAM_CONFIG_2 */
+    case 0xfffecc40:	/* EMIFS_CFG_DYN_WAIT */
+        s->tcmi_regs[offset >> 2] = value;
+        break;
+    case 0xfffecc0c:	/* EMIFS_CONFIG */
+        s->tcmi_regs[offset >> 2] = (value & 0xf) | (1 << 4);
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_tcmi_readfn[] = {
+    omap_badwidth_read32,
+    omap_badwidth_read32,
+    omap_tcmi_read,
+};
+
+static CPUWriteMemoryFunc *omap_tcmi_writefn[] = {
+    omap_badwidth_write32,
+    omap_badwidth_write32,
+    omap_tcmi_write,
+};
+
+static void omap_tcmi_reset(struct omap_mpu_state_s *mpu)
+{
+    mpu->tcmi_regs[0x00 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x04 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x08 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x0c >> 2] = 0x00000010;
+    mpu->tcmi_regs[0x10 >> 2] = 0x0010fffb;
+    mpu->tcmi_regs[0x14 >> 2] = 0x0010fffb;
+    mpu->tcmi_regs[0x18 >> 2] = 0x0010fffb;
+    mpu->tcmi_regs[0x1c >> 2] = 0x0010fffb;
+    mpu->tcmi_regs[0x20 >> 2] = 0x00618800;
+    mpu->tcmi_regs[0x24 >> 2] = 0x00000037;
+    mpu->tcmi_regs[0x28 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x2c >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x30 >> 2] = 0x00000000;
+    mpu->tcmi_regs[0x3c >> 2] = 0x00000003;
+    mpu->tcmi_regs[0x40 >> 2] = 0x00000000;
+}
+
+static void omap_tcmi_init(target_phys_addr_t base,
+                struct omap_mpu_state_s *mpu)
+{
+    int iomemtype = cpu_register_io_memory(0, omap_tcmi_readfn,
+                    omap_tcmi_writefn, mpu);
+
+    mpu->tcmi_base = base;
+    cpu_register_physical_memory(mpu->tcmi_base, 0x100, iomemtype);
+    omap_tcmi_reset(mpu);
+}
+
+/* Digital phase-locked loops control */
+static uint32_t omap_dpll_read(void *opaque, target_phys_addr_t addr)
+{
+    struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
+    int offset = addr - s->base;
+
+    if (offset == 0x00)	/* CTL_REG */
+        return s->mode;
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_dpll_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct dpll_ctl_s *s = (struct dpll_ctl_s *) opaque;
+    uint16_t diff;
+    int offset = addr - s->base;
+    static const int bypass_div[4] = { 1, 2, 4, 4 };
+    int div, mult;
+
+    if (offset == 0x00) {	/* CTL_REG */
+        /* See omap_ulpd_pm_write() too */
+        diff = s->mode & value;
+        s->mode = value & 0x2fff;
+        if (diff & (0x3ff << 2)) {
+            if (value & (1 << 4)) {			/* PLL_ENABLE */
+                div = ((value >> 5) & 3) + 1;		/* PLL_DIV */
+                mult = MIN((value >> 7) & 0x1f, 1);	/* PLL_MULT */
+            } else {
+                div = bypass_div[((value >> 2) & 3)];	/* BYPASS_DIV */
+                mult = 1;
+            }
+            omap_clk_setrate(s->dpll, div, mult);
+        }
+
+        /* Enter the desired mode.  */
+        s->mode = (s->mode & 0xfffe) | ((s->mode >> 4) & 1);
+
+        /* Act as if the lock is restored.  */
+        s->mode |= 2;
+    } else {
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_dpll_readfn[] = {
+    omap_badwidth_read16,
+    omap_dpll_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc *omap_dpll_writefn[] = {
+    omap_badwidth_write16,
+    omap_dpll_write,
+    omap_badwidth_write16,
+};
+
+static void omap_dpll_reset(struct dpll_ctl_s *s)
+{
+    s->mode = 0x2002;
+    omap_clk_setrate(s->dpll, 1, 1);
+}
+
+static void omap_dpll_init(struct dpll_ctl_s *s, target_phys_addr_t base,
+                omap_clk clk)
+{
+    int iomemtype = cpu_register_io_memory(0, omap_dpll_readfn,
+                    omap_dpll_writefn, s);
+
+    s->base = base;
+    s->dpll = clk;
+    omap_dpll_reset(s);
+
+    cpu_register_physical_memory(s->base, 0x100, iomemtype);
+}
+
+/* UARTs */
+struct omap_uart_s {
+    SerialState *serial; /* TODO */
+};
+
+static void omap_uart_reset(struct omap_uart_s *s)
+{
+}
+
+struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk, CharDriverState *chr)
+{
+    struct omap_uart_s *s = (struct omap_uart_s *)
+            qemu_mallocz(sizeof(struct omap_uart_s));
+    if (chr)
+        s->serial = serial_mm_init(base, 2, irq, chr, 1);
+    return s;
+}
+
+/* MPU Clock/Reset/Power Mode Control */
+static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->clkm.mpu_base;
+
+    switch (offset) {
+    case 0x00:	/* ARM_CKCTL */
+        return s->clkm.arm_ckctl;
+
+    case 0x04:	/* ARM_IDLECT1 */
+        return s->clkm.arm_idlect1;
+
+    case 0x08:	/* ARM_IDLECT2 */
+        return s->clkm.arm_idlect2;
+
+    case 0x0c:	/* ARM_EWUPCT */
+        return s->clkm.arm_ewupct;
+
+    case 0x10:	/* ARM_RSTCT1 */
+        return s->clkm.arm_rstct1;
+
+    case 0x14:	/* ARM_RSTCT2 */
+        return s->clkm.arm_rstct2;
+
+    case 0x18:	/* ARM_SYSST */
+        return (s->clkm.clocking_scheme < 11) | s->clkm.cold_start;
+
+    case 0x1c:	/* ARM_CKOUT1 */
+        return s->clkm.arm_ckout1;
+
+    case 0x20:	/* ARM_CKOUT2 */
+        break;
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static inline void omap_clkm_ckctl_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    if (diff & (1 << 14)) {				/* ARM_INTHCK_SEL */
+        if (value & (1 << 14))
+            /* Reserved */;
+        else {
+            clk = omap_findclk(s, "arminth_ck");
+            omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
+        }
+    }
+    if (diff & (1 << 12)) {				/* ARM_TIMXO */
+        clk = omap_findclk(s, "armtim_ck");
+        if (value & (1 << 12))
+            omap_clk_reparent(clk, omap_findclk(s, "clkin"));
+        else
+            omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
+    }
+    /* XXX: en_dspck */
+    if (diff & (3 << 10)) {				/* DSPMMUDIV */
+        clk = omap_findclk(s, "dspmmu_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 10) & 3), 1);
+    }
+    if (diff & (3 << 8)) {				/* TCDIV */
+        clk = omap_findclk(s, "tc_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 8) & 3), 1);
+    }
+    if (diff & (3 << 6)) {				/* DSPDIV */
+        clk = omap_findclk(s, "dsp_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 6) & 3), 1);
+    }
+    if (diff & (3 << 4)) {				/* ARMDIV */
+        clk = omap_findclk(s, "arm_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 4) & 3), 1);
+    }
+    if (diff & (3 << 2)) {				/* LCDDIV */
+        clk = omap_findclk(s, "lcd_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 2) & 3), 1);
+    }
+    if (diff & (3 << 0)) {				/* PERDIV */
+        clk = omap_findclk(s, "armper_ck");
+        omap_clk_setrate(clk, 1 << ((value >> 0) & 3), 1);
+    }
+}
+
+static inline void omap_clkm_idlect1_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    if (value & (1 << 11))				/* SETARM_IDLE */
+        cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+    if (!(value & (1 << 10)))				/* WKUP_MODE */
+        qemu_system_shutdown_request();	/* XXX: disable wakeup from IRQ */
+
+#define SET_CANIDLE(clock, bit)				\
+    if (diff & (1 << bit)) {				\
+        clk = omap_findclk(s, clock);			\
+        omap_clk_canidle(clk, (value >> bit) & 1);	\
+    }
+    SET_CANIDLE("mpuwd_ck", 0)				/* IDLWDT_ARM */
+    SET_CANIDLE("armxor_ck", 1)				/* IDLXORP_ARM */
+    SET_CANIDLE("mpuper_ck", 2)				/* IDLPER_ARM */
+    SET_CANIDLE("lcd_ck", 3)				/* IDLLCD_ARM */
+    SET_CANIDLE("lb_ck", 4)				/* IDLLB_ARM */
+    SET_CANIDLE("hsab_ck", 5)				/* IDLHSAB_ARM */
+    SET_CANIDLE("tipb_ck", 6)				/* IDLIF_ARM */
+    SET_CANIDLE("dma_ck", 6)				/* IDLIF_ARM */
+    SET_CANIDLE("tc_ck", 6)				/* IDLIF_ARM */
+    SET_CANIDLE("dpll1", 7)				/* IDLDPLL_ARM */
+    SET_CANIDLE("dpll2", 7)				/* IDLDPLL_ARM */
+    SET_CANIDLE("dpll3", 7)				/* IDLDPLL_ARM */
+    SET_CANIDLE("mpui_ck", 8)				/* IDLAPI_ARM */
+    SET_CANIDLE("armtim_ck", 9)				/* IDLTIM_ARM */
+}
+
+static inline void omap_clkm_idlect2_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+#define SET_ONOFF(clock, bit)				\
+    if (diff & (1 << bit)) {				\
+        clk = omap_findclk(s, clock);			\
+        omap_clk_onoff(clk, (value >> bit) & 1);	\
+    }
+    SET_ONOFF("mpuwd_ck", 0)				/* EN_WDTCK */
+    SET_ONOFF("armxor_ck", 1)				/* EN_XORPCK */
+    SET_ONOFF("mpuper_ck", 2)				/* EN_PERCK */
+    SET_ONOFF("lcd_ck", 3)				/* EN_LCDCK */
+    SET_ONOFF("lb_ck", 4)				/* EN_LBCK */
+    SET_ONOFF("hsab_ck", 5)				/* EN_HSABCK */
+    SET_ONOFF("mpui_ck", 6)				/* EN_APICK */
+    SET_ONOFF("armtim_ck", 7)				/* EN_TIMCK */
+    SET_CANIDLE("dma_ck", 8)				/* DMACK_REQ */
+    SET_ONOFF("arm_gpio_ck", 9)				/* EN_GPIOCK */
+    SET_ONOFF("lbfree_ck", 10)				/* EN_LBFREECK */
+}
+
+static inline void omap_clkm_ckout1_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    if (diff & (3 << 4)) {				/* TCLKOUT */
+        clk = omap_findclk(s, "tclk_out");
+        switch ((value >> 4) & 3) {
+        case 1:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_gen3"));
+            omap_clk_onoff(clk, 1);
+            break;
+        case 2:
+            omap_clk_reparent(clk, omap_findclk(s, "tc_ck"));
+            omap_clk_onoff(clk, 1);
+            break;
+        default:
+            omap_clk_onoff(clk, 0);
+        }
+    }
+    if (diff & (3 << 2)) {				/* DCLKOUT */
+        clk = omap_findclk(s, "dclk_out");
+        switch ((value >> 2) & 3) {
+        case 0:
+            omap_clk_reparent(clk, omap_findclk(s, "dspmmu_ck"));
+            break;
+        case 1:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_gen2"));
+            break;
+        case 2:
+            omap_clk_reparent(clk, omap_findclk(s, "dsp_ck"));
+            break;
+        case 3:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_ref14"));
+            break;
+        }
+    }
+    if (diff & (3 << 0)) {				/* ACLKOUT */
+        clk = omap_findclk(s, "aclk_out");
+        switch ((value >> 0) & 3) {
+        case 1:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_gen1"));
+            omap_clk_onoff(clk, 1);
+            break;
+        case 2:
+            omap_clk_reparent(clk, omap_findclk(s, "arm_ck"));
+            omap_clk_onoff(clk, 1);
+            break;
+        case 3:
+            omap_clk_reparent(clk, omap_findclk(s, "ck_ref14"));
+            omap_clk_onoff(clk, 1);
+            break;
+        default:
+            omap_clk_onoff(clk, 0);
+        }
+    }
+}
+
+static void omap_clkm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->clkm.mpu_base;
+    uint16_t diff;
+    omap_clk clk;
+    static const char *clkschemename[8] = {
+        "fully synchronous", "fully asynchronous", "synchronous scalable",
+        "mix mode 1", "mix mode 2", "bypass mode", "mix mode 3", "mix mode 4",
+    };
+
+    switch (offset) {
+    case 0x00:	/* ARM_CKCTL */
+        diff = s->clkm.arm_ckctl ^ value;
+        s->clkm.arm_ckctl = value & 0x7fff;
+        omap_clkm_ckctl_update(s, diff, value);
+        return;
+
+    case 0x04:	/* ARM_IDLECT1 */
+        diff = s->clkm.arm_idlect1 ^ value;
+        s->clkm.arm_idlect1 = value & 0x0fff;
+        omap_clkm_idlect1_update(s, diff, value);
+        return;
+
+    case 0x08:	/* ARM_IDLECT2 */
+        diff = s->clkm.arm_idlect2 ^ value;
+        s->clkm.arm_idlect2 = value & 0x07ff;
+        omap_clkm_idlect2_update(s, diff, value);
+        return;
+
+    case 0x0c:	/* ARM_EWUPCT */
+        diff = s->clkm.arm_ewupct ^ value;
+        s->clkm.arm_ewupct = value & 0x003f;
+        return;
+
+    case 0x10:	/* ARM_RSTCT1 */
+        diff = s->clkm.arm_rstct1 ^ value;
+        s->clkm.arm_rstct1 = value & 0x0007;
+        if (value & 9) {
+            qemu_system_reset_request();
+            s->clkm.cold_start = 0xa;
+        }
+        if (diff & ~value & 4) {				/* DSP_RST */
+            omap_mpui_reset(s);
+            omap_tipb_bridge_reset(s->private_tipb);
+            omap_tipb_bridge_reset(s->public_tipb);
+        }
+        if (diff & 2) {						/* DSP_EN */
+            clk = omap_findclk(s, "dsp_ck");
+            omap_clk_canidle(clk, (~value >> 1) & 1);
+        }
+        return;
+
+    case 0x14:	/* ARM_RSTCT2 */
+        s->clkm.arm_rstct2 = value & 0x0001;
+        return;
+
+    case 0x18:	/* ARM_SYSST */
+        if ((s->clkm.clocking_scheme ^ (value >> 11)) & 7) {
+            s->clkm.clocking_scheme = (value >> 11) & 7;
+            printf("%s: clocking scheme set to %s\n", __FUNCTION__,
+                            clkschemename[s->clkm.clocking_scheme]);
+        }
+        s->clkm.cold_start &= value & 0x3f;
+        return;
+
+    case 0x1c:	/* ARM_CKOUT1 */
+        diff = s->clkm.arm_ckout1 ^ value;
+        s->clkm.arm_ckout1 = value & 0x003f;
+        omap_clkm_ckout1_update(s, diff, value);
+        return;
+
+    case 0x20:	/* ARM_CKOUT2 */
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_clkm_readfn[] = {
+    omap_badwidth_read16,
+    omap_clkm_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc *omap_clkm_writefn[] = {
+    omap_badwidth_write16,
+    omap_clkm_write,
+    omap_badwidth_write16,
+};
+
+static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->clkm.dsp_base;
+
+    switch (offset) {
+    case 0x04:	/* DSP_IDLECT1 */
+        return s->clkm.dsp_idlect1;
+
+    case 0x08:	/* DSP_IDLECT2 */
+        return s->clkm.dsp_idlect2;
+
+    case 0x14:	/* DSP_RSTCT2 */
+        return s->clkm.dsp_rstct2;
+
+    case 0x18:	/* DSP_SYSST */
+        return (s->clkm.clocking_scheme < 11) | s->clkm.cold_start |
+                (s->env->halted << 6);	/* Quite useless... */
+    }
+
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static inline void omap_clkdsp_idlect1_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    SET_CANIDLE("dspxor_ck", 1);			/* IDLXORP_DSP */
+}
+
+static inline void omap_clkdsp_idlect2_update(struct omap_mpu_state_s *s,
+                uint16_t diff, uint16_t value)
+{
+    omap_clk clk;
+
+    SET_ONOFF("dspxor_ck", 1);				/* EN_XORPCK */
+}
+
+static void omap_clkdsp_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *) opaque;
+    int offset = addr - s->clkm.dsp_base;
+    uint16_t diff;
+
+    switch (offset) {
+    case 0x04:	/* DSP_IDLECT1 */
+        diff = s->clkm.dsp_idlect1 ^ value;
+        s->clkm.dsp_idlect1 = value & 0x01f7;
+        omap_clkdsp_idlect1_update(s, diff, value);
+        break;
+
+    case 0x08:	/* DSP_IDLECT2 */
+        s->clkm.dsp_idlect2 = value & 0x0037;
+        diff = s->clkm.dsp_idlect1 ^ value;
+        omap_clkdsp_idlect2_update(s, diff, value);
+        break;
+
+    case 0x14:	/* DSP_RSTCT2 */
+        s->clkm.dsp_rstct2 = value & 0x0001;
+        break;
+
+    case 0x18:	/* DSP_SYSST */
+        s->clkm.cold_start &= value & 0x3f;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_clkdsp_readfn[] = {
+    omap_badwidth_read16,
+    omap_clkdsp_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc *omap_clkdsp_writefn[] = {
+    omap_badwidth_write16,
+    omap_clkdsp_write,
+    omap_badwidth_write16,
+};
+
+static void omap_clkm_reset(struct omap_mpu_state_s *s)
+{
+    if (s->wdt && s->wdt->reset)
+        s->clkm.cold_start = 0x6;
+    s->clkm.clocking_scheme = 0;
+    omap_clkm_ckctl_update(s, ~0, 0x3000);
+    s->clkm.arm_ckctl = 0x3000;
+    omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 & 0x0400, 0x0400);
+    s->clkm.arm_idlect1 = 0x0400;
+    omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 & 0x0100, 0x0100);
+    s->clkm.arm_idlect2 = 0x0100;
+    s->clkm.arm_ewupct = 0x003f;
+    s->clkm.arm_rstct1 = 0x0000;
+    s->clkm.arm_rstct2 = 0x0000;
+    s->clkm.arm_ckout1 = 0x0015;
+    s->clkm.dpll1_mode = 0x2002;
+    omap_clkdsp_idlect1_update(s, s->clkm.dsp_idlect1 ^ 0x0040, 0x0040);
+    s->clkm.dsp_idlect1 = 0x0040;
+    omap_clkdsp_idlect2_update(s, ~0, 0x0000);
+    s->clkm.dsp_idlect2 = 0x0000;
+    s->clkm.dsp_rstct2 = 0x0000;
+}
+
+static void omap_clkm_init(target_phys_addr_t mpu_base,
+                target_phys_addr_t dsp_base, struct omap_mpu_state_s *s)
+{
+    int iomemtype[2] = {
+        cpu_register_io_memory(0, omap_clkm_readfn, omap_clkm_writefn, s),
+        cpu_register_io_memory(0, omap_clkdsp_readfn, omap_clkdsp_writefn, s),
+    };
+
+    s->clkm.mpu_base = mpu_base;
+    s->clkm.dsp_base = dsp_base;
+    s->clkm.cold_start = 0x3a;
+    omap_clkm_reset(s);
+
+    cpu_register_physical_memory(s->clkm.mpu_base, 0x100, iomemtype[0]);
+    cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]);
+}
+
+/* General chip reset */
+static void omap_mpu_reset(void *opaque)
+{
+    struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
+
+    omap_clkm_reset(mpu);
+    omap_inth_reset(mpu->ih[0]);
+    omap_inth_reset(mpu->ih[1]);
+    omap_dma_reset(mpu->dma);
+    omap_mpu_timer_reset(mpu->timer[0]);
+    omap_mpu_timer_reset(mpu->timer[1]);
+    omap_mpu_timer_reset(mpu->timer[2]);
+    omap_wd_timer_reset(mpu->wdt);
+    omap_os_timer_reset(mpu->os_timer);
+    omap_lcdc_reset(mpu->lcd);
+    omap_ulpd_pm_reset(mpu);
+    omap_pin_cfg_reset(mpu);
+    omap_mpui_reset(mpu);
+    omap_tipb_bridge_reset(mpu->private_tipb);
+    omap_tipb_bridge_reset(mpu->public_tipb);
+    omap_dpll_reset(&mpu->dpll[0]);
+    omap_dpll_reset(&mpu->dpll[1]);
+    omap_dpll_reset(&mpu->dpll[2]);
+    omap_uart_reset(mpu->uart1);
+    omap_uart_reset(mpu->uart2);
+    omap_uart_reset(mpu->uart3);
+    omap_mmc_reset(mpu->mmc);
+    cpu_reset(mpu->env);
+}
+
+static void omap_mpu_wakeup(void *opaque, int irq, int req)
+{
+    struct omap_mpu_state_s *mpu = (struct omap_mpu_state_s *) opaque;
+
+    cpu_interrupt(mpu->env, CPU_INTERRUPT_EXITTB);
+}
+
+struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
+                DisplayState *ds, const char *core)
+{
+    struct omap_mpu_state_s *s = (struct omap_mpu_state_s *)
+            qemu_mallocz(sizeof(struct omap_mpu_state_s));
+    ram_addr_t imif_base, emiff_base;
+
+    /* Core */
+    s->mpu_model = omap310;
+    s->env = cpu_init();
+    s->sdram_size = sdram_size;
+    s->sram_size = OMAP15XX_SRAM_SIZE;
+
+    cpu_arm_set_model(s->env, core ?: "ti925t");
+
+    /* Clocks */
+    omap_clk_init(s);
+
+    /* Memory-mapped stuff */
+    cpu_register_physical_memory(OMAP_EMIFF_BASE, s->sdram_size,
+                    (emiff_base = qemu_ram_alloc(s->sdram_size)) | IO_MEM_RAM);
+    cpu_register_physical_memory(OMAP_IMIF_BASE, s->sram_size,
+                    (imif_base = qemu_ram_alloc(s->sram_size)) | IO_MEM_RAM);
+
+    omap_clkm_init(0xfffece00, 0xe1008000, s);
+
+    s->ih[0] = omap_inth_init(0xfffecb00, 0x100,
+                    arm_pic_init_cpu(s->env),
+                    omap_findclk(s, "arminth_ck"));
+    s->ih[1] = omap_inth_init(0xfffe0000, 0x800,
+                    &s->ih[0]->pins[OMAP_INT_15XX_IH2_IRQ],
+                    omap_findclk(s, "arminth_ck"));
+    s->irq[0] = s->ih[0]->pins;
+    s->irq[1] = s->ih[1]->pins;
+
+    s->dma = omap_dma_init(0xfffed800, s->irq[0], s,
+                    omap_findclk(s, "dma_ck"));
+    s->port[emiff    ].addr_valid = omap_validate_emiff_addr;
+    s->port[emifs    ].addr_valid = omap_validate_emifs_addr;
+    s->port[imif     ].addr_valid = omap_validate_imif_addr;
+    s->port[tipb     ].addr_valid = omap_validate_tipb_addr;
+    s->port[local    ].addr_valid = omap_validate_local_addr;
+    s->port[tipb_mpui].addr_valid = omap_validate_tipb_mpui_addr;
+
+    s->timer[0] = omap_mpu_timer_init(0xfffec500,
+                    s->irq[0][OMAP_INT_TIMER1],
+                    omap_findclk(s, "mputim_ck"));
+    s->timer[1] = omap_mpu_timer_init(0xfffec600,
+                    s->irq[0][OMAP_INT_TIMER2],
+                    omap_findclk(s, "mputim_ck"));
+    s->timer[2] = omap_mpu_timer_init(0xfffec700,
+                    s->irq[0][OMAP_INT_TIMER3],
+                    omap_findclk(s, "mputim_ck"));
+
+    s->wdt = omap_wd_timer_init(0xfffec800,
+                    s->irq[0][OMAP_INT_WD_TIMER],
+                    omap_findclk(s, "armwdt_ck"));
+
+    s->os_timer = omap_os_timer_init(0xfffb9000,
+                    s->irq[1][OMAP_INT_OS_TIMER],
+                    omap_findclk(s, "clk32-kHz"));
+
+    s->lcd = omap_lcdc_init(0xfffec000, s->irq[0][OMAP_INT_LCD_CTRL],
+                    &s->dma->lcd_ch, ds, imif_base, emiff_base,
+                    omap_findclk(s, "lcd_ck"));
+
+    omap_ulpd_pm_init(0xfffe0800, s);
+    omap_pin_cfg_init(0xfffe1000, s);
+    omap_id_init(s);
+
+    omap_mpui_init(0xfffec900, s);
+
+    s->private_tipb = omap_tipb_bridge_init(0xfffeca00,
+                    s->irq[0][OMAP_INT_BRIDGE_PRIV],
+                    omap_findclk(s, "tipb_ck"));
+    s->public_tipb = omap_tipb_bridge_init(0xfffed300,
+                    s->irq[0][OMAP_INT_BRIDGE_PUB],
+                    omap_findclk(s, "tipb_ck"));
+
+    omap_tcmi_init(0xfffecc00, s);
+
+    s->uart1 = omap_uart_init(0xfffb0000, s->irq[1][OMAP_INT_UART1],
+                    omap_findclk(s, "uart1_ck"),
+                    serial_hds[0]);
+    s->uart2 = omap_uart_init(0xfffb0800, s->irq[1][OMAP_INT_UART2],
+                    omap_findclk(s, "uart2_ck"),
+                    serial_hds[0] ? serial_hds[1] : 0);
+    s->uart3 = omap_uart_init(0xe1019800, s->irq[0][OMAP_INT_UART3],
+                    omap_findclk(s, "uart3_ck"),
+                    serial_hds[0] && serial_hds[1] ? serial_hds[2] : 0);
+
+    omap_dpll_init(&s->dpll[0], 0xfffecf00, omap_findclk(s, "dpll1"));
+    omap_dpll_init(&s->dpll[1], 0xfffed000, omap_findclk(s, "dpll2"));
+    omap_dpll_init(&s->dpll[2], 0xfffed100, omap_findclk(s, "dpll3"));
+
+    s->mmc = omap_mmc_init(0xfffb7800, s->irq[1][OMAP_INT_OQN],
+                    &s->drq[OMAP_DMA_MMC_TX], omap_findclk(s, "mmc_ck"));
+
+    qemu_register_reset(omap_mpu_reset, s);
+    s->wakeup = qemu_allocate_irqs(omap_mpu_wakeup, s, 1)[0];
+
+    return s;
+}
diff --git a/hw/omap.h b/hw/omap.h
new file mode 100644
index 0000000..96cd3af
--- /dev/null
+++ b/hw/omap.h
@@ -0,0 +1,596 @@
+/*
+ * Texas Instruments OMAP processors.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#ifndef hw_omap_h
+# define hw_omap_h		"omap.h"
+
+# define OMAP_EMIFS_BASE	0x00000000
+# define OMAP_CS0_BASE		0x00000000
+# define OMAP_CS1_BASE		0x04000000
+# define OMAP_CS2_BASE		0x08000000
+# define OMAP_CS3_BASE		0x0c000000
+# define OMAP_EMIFF_BASE	0x10000000
+# define OMAP_IMIF_BASE		0x20000000
+# define OMAP_LOCALBUS_BASE	0x30000000
+# define OMAP_MPUI_BASE		0xe1000000
+
+# define OMAP730_SRAM_SIZE	0x00032000
+# define OMAP15XX_SRAM_SIZE	0x00030000
+# define OMAP16XX_SRAM_SIZE	0x00004000
+# define OMAP1611_SRAM_SIZE	0x0003e800
+# define OMAP_CS0_SIZE		0x04000000
+# define OMAP_CS1_SIZE		0x04000000
+# define OMAP_CS2_SIZE		0x04000000
+# define OMAP_CS3_SIZE		0x04000000
+
+/* omap1_clk.c */
+struct omap_mpu_state_s;
+typedef struct clk *omap_clk;
+omap_clk omap_findclk(struct omap_mpu_state_s *mpu, const char *name);
+void omap_clk_init(struct omap_mpu_state_s *mpu);
+void omap_clk_adduser(struct clk *clk, qemu_irq user);
+void omap_clk_get(omap_clk clk);
+void omap_clk_put(omap_clk clk);
+void omap_clk_onoff(omap_clk clk, int on);
+void omap_clk_canidle(omap_clk clk, int can);
+void omap_clk_setrate(omap_clk clk, int divide, int multiply);
+int64_t omap_clk_getrate(omap_clk clk);
+void omap_clk_reparent(omap_clk clk, omap_clk parent);
+
+/* omap.c */
+struct omap_intr_handler_s;
+struct omap_intr_handler_s *omap_inth_init(target_phys_addr_t base,
+                unsigned long size, qemu_irq parent[2], omap_clk clk);
+
+/*
+ * Common IRQ numbers for level 1 interrupt handler
+ * See /usr/include/asm-arm/arch-omap/irqs.h in Linux.
+ */
+# define OMAP_INT_CAMERA		1
+# define OMAP_INT_FIQ			3
+# define OMAP_INT_RTDX			6
+# define OMAP_INT_DSP_MMU_ABORT		7
+# define OMAP_INT_HOST			8
+# define OMAP_INT_ABORT			9
+# define OMAP_INT_BRIDGE_PRIV		13
+# define OMAP_INT_GPIO_BANK1		14
+# define OMAP_INT_UART3			15
+# define OMAP_INT_TIMER3		16
+# define OMAP_INT_DMA_CH0_6		19
+# define OMAP_INT_DMA_CH1_7		20
+# define OMAP_INT_DMA_CH2_8		21
+# define OMAP_INT_DMA_CH3		22
+# define OMAP_INT_DMA_CH4		23
+# define OMAP_INT_DMA_CH5		24
+# define OMAP_INT_DMA_LCD		25
+# define OMAP_INT_TIMER1		26
+# define OMAP_INT_WD_TIMER		27
+# define OMAP_INT_BRIDGE_PUB		28
+# define OMAP_INT_TIMER2		30
+# define OMAP_INT_LCD_CTRL		31
+
+/*
+ * Common OMAP-15xx IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_15XX_IH2_IRQ		0
+# define OMAP_INT_15XX_LB_MMU		17
+# define OMAP_INT_15XX_LOCAL_BUS	29
+
+/*
+ * OMAP-1510 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_1510_SPI_TX		4
+# define OMAP_INT_1510_SPI_RX		5
+# define OMAP_INT_1510_DSP_MAILBOX1	10
+# define OMAP_INT_1510_DSP_MAILBOX2	11
+
+/*
+ * OMAP-310 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_310_McBSP2_TX		4
+# define OMAP_INT_310_McBSP2_RX		5
+# define OMAP_INT_310_HSB_MAILBOX1	12
+# define OMAP_INT_310_HSAB_MMU		18
+
+/*
+ * OMAP-1610 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_1610_IH2_IRQ		0
+# define OMAP_INT_1610_IH2_FIQ		2
+# define OMAP_INT_1610_McBSP2_TX	4
+# define OMAP_INT_1610_McBSP2_RX	5
+# define OMAP_INT_1610_DSP_MAILBOX1	10
+# define OMAP_INT_1610_DSP_MAILBOX2	11
+# define OMAP_INT_1610_LCD_LINE		12
+# define OMAP_INT_1610_GPTIMER1		17
+# define OMAP_INT_1610_GPTIMER2		18
+# define OMAP_INT_1610_SSR_FIFO_0	29
+
+/*
+ * OMAP-730 specific IRQ numbers for level 1 interrupt handler
+ */
+# define OMAP_INT_730_IH2_FIQ		0
+# define OMAP_INT_730_IH2_IRQ		1
+# define OMAP_INT_730_USB_NON_ISO	2
+# define OMAP_INT_730_USB_ISO		3
+# define OMAP_INT_730_ICR		4
+# define OMAP_INT_730_EAC		5
+# define OMAP_INT_730_GPIO_BANK1	6
+# define OMAP_INT_730_GPIO_BANK2	7
+# define OMAP_INT_730_GPIO_BANK3	8
+# define OMAP_INT_730_McBSP2TX		10
+# define OMAP_INT_730_McBSP2RX		11
+# define OMAP_INT_730_McBSP2RX_OVF	12
+# define OMAP_INT_730_LCD_LINE		14
+# define OMAP_INT_730_GSM_PROTECT	15
+# define OMAP_INT_730_TIMER3		16
+# define OMAP_INT_730_GPIO_BANK5	17
+# define OMAP_INT_730_GPIO_BANK6	18
+# define OMAP_INT_730_SPGIO_WR		29
+
+/*
+ * Common IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_KEYBOARD		1
+# define OMAP_INT_uWireTX		2
+# define OMAP_INT_uWireRX		3
+# define OMAP_INT_I2C			4
+# define OMAP_INT_MPUIO			5
+# define OMAP_INT_USB_HHC_1		6
+# define OMAP_INT_McBSP3TX		10
+# define OMAP_INT_McBSP3RX		11
+# define OMAP_INT_McBSP1TX		12
+# define OMAP_INT_McBSP1RX		13
+# define OMAP_INT_UART1			14
+# define OMAP_INT_UART2			15
+# define OMAP_INT_USB_W2FC		20
+# define OMAP_INT_1WIRE			21
+# define OMAP_INT_OS_TIMER		22
+# define OMAP_INT_OQN			23
+# define OMAP_INT_GAUGE_32K		24
+# define OMAP_INT_RTC_TIMER		25
+# define OMAP_INT_RTC_ALARM		26
+# define OMAP_INT_DSP_MMU		28
+
+/*
+ * OMAP-1510 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_1510_BT_MCSI1TX	16
+# define OMAP_INT_1510_BT_MCSI1RX	17
+# define OMAP_INT_1510_SoSSI_MATCH	19
+# define OMAP_INT_1510_MEM_STICK	27
+# define OMAP_INT_1510_COM_SPI_RO	31
+
+/*
+ * OMAP-310 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_310_FAC		0
+# define OMAP_INT_310_USB_HHC_2		7
+# define OMAP_INT_310_MCSI1_FE		16
+# define OMAP_INT_310_MCSI2_FE		17
+# define OMAP_INT_310_USB_W2FC_ISO	29
+# define OMAP_INT_310_USB_W2FC_NON_ISO	30
+# define OMAP_INT_310_McBSP2RX_OF	31
+
+/*
+ * OMAP-1610 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_1610_FAC		0
+# define OMAP_INT_1610_USB_HHC_2	7
+# define OMAP_INT_1610_USB_OTG		8
+# define OMAP_INT_1610_SoSSI		9
+# define OMAP_INT_1610_BT_MCSI1TX	16
+# define OMAP_INT_1610_BT_MCSI1RX	17
+# define OMAP_INT_1610_SoSSI_MATCH	19
+# define OMAP_INT_1610_MEM_STICK	27
+# define OMAP_INT_1610_McBSP2RX_OF	31
+# define OMAP_INT_1610_STI		32
+# define OMAP_INT_1610_STI_WAKEUP	33
+# define OMAP_INT_1610_GPTIMER3		34
+# define OMAP_INT_1610_GPTIMER4		35
+# define OMAP_INT_1610_GPTIMER5		36
+# define OMAP_INT_1610_GPTIMER6		37
+# define OMAP_INT_1610_GPTIMER7		38
+# define OMAP_INT_1610_GPTIMER8		39
+# define OMAP_INT_1610_GPIO_BANK2	40
+# define OMAP_INT_1610_GPIO_BANK3	41
+# define OMAP_INT_1610_MMC2		42
+# define OMAP_INT_1610_CF		43
+# define OMAP_INT_1610_WAKE_UP_REQ	46
+# define OMAP_INT_1610_GPIO_BANK4	48
+# define OMAP_INT_1610_SPI		49
+# define OMAP_INT_1610_DMA_CH6		53
+# define OMAP_INT_1610_DMA_CH7		54
+# define OMAP_INT_1610_DMA_CH8		55
+# define OMAP_INT_1610_DMA_CH9		56
+# define OMAP_INT_1610_DMA_CH10		57
+# define OMAP_INT_1610_DMA_CH11		58
+# define OMAP_INT_1610_DMA_CH12		59
+# define OMAP_INT_1610_DMA_CH13		60
+# define OMAP_INT_1610_DMA_CH14		61
+# define OMAP_INT_1610_DMA_CH15		62
+# define OMAP_INT_1610_NAND		63
+
+/*
+ * OMAP-730 specific IRQ numbers for level 2 interrupt handler
+ */
+# define OMAP_INT_730_HW_ERRORS		0
+# define OMAP_INT_730_NFIQ_PWR_FAIL	1
+# define OMAP_INT_730_CFCD		2
+# define OMAP_INT_730_CFIREQ		3
+# define OMAP_INT_730_I2C		4
+# define OMAP_INT_730_PCC		5
+# define OMAP_INT_730_MPU_EXT_NIRQ	6
+# define OMAP_INT_730_SPI_100K_1	7
+# define OMAP_INT_730_SYREN_SPI		8
+# define OMAP_INT_730_VLYNQ		9
+# define OMAP_INT_730_GPIO_BANK4	10
+# define OMAP_INT_730_McBSP1TX		11
+# define OMAP_INT_730_McBSP1RX		12
+# define OMAP_INT_730_McBSP1RX_OF	13
+# define OMAP_INT_730_UART_MODEM_IRDA_2	14
+# define OMAP_INT_730_UART_MODEM_1	15
+# define OMAP_INT_730_MCSI		16
+# define OMAP_INT_730_uWireTX		17
+# define OMAP_INT_730_uWireRX		18
+# define OMAP_INT_730_SMC_CD		19
+# define OMAP_INT_730_SMC_IREQ		20
+# define OMAP_INT_730_HDQ_1WIRE		21
+# define OMAP_INT_730_TIMER32K		22
+# define OMAP_INT_730_MMC_SDIO		23
+# define OMAP_INT_730_UPLD		24
+# define OMAP_INT_730_USB_HHC_1		27
+# define OMAP_INT_730_USB_HHC_2		28
+# define OMAP_INT_730_USB_GENI		29
+# define OMAP_INT_730_USB_OTG		30
+# define OMAP_INT_730_CAMERA_IF		31
+# define OMAP_INT_730_RNG		32
+# define OMAP_INT_730_DUAL_MODE_TIMER	33
+# define OMAP_INT_730_DBB_RF_EN		34
+# define OMAP_INT_730_MPUIO_KEYPAD	35
+# define OMAP_INT_730_SHA1_MD5		36
+# define OMAP_INT_730_SPI_100K_2	37
+# define OMAP_INT_730_RNG_IDLE		38
+# define OMAP_INT_730_MPUIO		39
+# define OMAP_INT_730_LLPC_LCD_CTRL_OFF	40
+# define OMAP_INT_730_LLPC_OE_FALLING	41
+# define OMAP_INT_730_LLPC_OE_RISING	42
+# define OMAP_INT_730_LLPC_VSYNC	43
+# define OMAP_INT_730_WAKE_UP_REQ	46
+# define OMAP_INT_730_DMA_CH6		53
+# define OMAP_INT_730_DMA_CH7		54
+# define OMAP_INT_730_DMA_CH8		55
+# define OMAP_INT_730_DMA_CH9		56
+# define OMAP_INT_730_DMA_CH10		57
+# define OMAP_INT_730_DMA_CH11		58
+# define OMAP_INT_730_DMA_CH12		59
+# define OMAP_INT_730_DMA_CH13		60
+# define OMAP_INT_730_DMA_CH14		61
+# define OMAP_INT_730_DMA_CH15		62
+# define OMAP_INT_730_NAND		63
+
+/*
+ * OMAP-24xx common IRQ numbers
+ */
+# define OMAP_INT_24XX_SYS_NIRQ		7
+# define OMAP_INT_24XX_SDMA_IRQ0	12
+# define OMAP_INT_24XX_SDMA_IRQ1	13
+# define OMAP_INT_24XX_SDMA_IRQ2	14
+# define OMAP_INT_24XX_SDMA_IRQ3	15
+# define OMAP_INT_24XX_CAM_IRQ		24
+# define OMAP_INT_24XX_DSS_IRQ		25
+# define OMAP_INT_24XX_MAIL_U0_MPU	26
+# define OMAP_INT_24XX_DSP_UMA		27
+# define OMAP_INT_24XX_DSP_MMU		28
+# define OMAP_INT_24XX_GPIO_BANK1	29
+# define OMAP_INT_24XX_GPIO_BANK2	30
+# define OMAP_INT_24XX_GPIO_BANK3	31
+# define OMAP_INT_24XX_GPIO_BANK4	32
+# define OMAP_INT_24XX_GPIO_BANK5	33
+# define OMAP_INT_24XX_MAIL_U3_MPU	34
+# define OMAP_INT_24XX_GPTIMER1		37
+# define OMAP_INT_24XX_GPTIMER2		38
+# define OMAP_INT_24XX_GPTIMER3		39
+# define OMAP_INT_24XX_GPTIMER4		40
+# define OMAP_INT_24XX_GPTIMER5		41
+# define OMAP_INT_24XX_GPTIMER6		42
+# define OMAP_INT_24XX_GPTIMER7		43
+# define OMAP_INT_24XX_GPTIMER8		44
+# define OMAP_INT_24XX_GPTIMER9		45
+# define OMAP_INT_24XX_GPTIMER10	46
+# define OMAP_INT_24XX_GPTIMER11	47
+# define OMAP_INT_24XX_GPTIMER12	48
+# define OMAP_INT_24XX_MCBSP1_IRQ_TX	59
+# define OMAP_INT_24XX_MCBSP1_IRQ_RX	60
+# define OMAP_INT_24XX_MCBSP2_IRQ_TX	62
+# define OMAP_INT_24XX_MCBSP2_IRQ_RX	63
+# define OMAP_INT_24XX_UART1_IRQ	72
+# define OMAP_INT_24XX_UART2_IRQ	73
+# define OMAP_INT_24XX_UART3_IRQ	74
+# define OMAP_INT_24XX_USB_IRQ_GEN	75
+# define OMAP_INT_24XX_USB_IRQ_NISO	76
+# define OMAP_INT_24XX_USB_IRQ_ISO	77
+# define OMAP_INT_24XX_USB_IRQ_HGEN	78
+# define OMAP_INT_24XX_USB_IRQ_HSOF	79
+# define OMAP_INT_24XX_USB_IRQ_OTG	80
+# define OMAP_INT_24XX_MMC_IRQ		83
+# define OMAP_INT_243X_HS_USB_MC	92
+# define OMAP_INT_243X_HS_USB_DMA	93
+# define OMAP_INT_243X_CARKIT		94
+
+struct omap_dma_s;
+struct omap_dma_s *omap_dma_init(target_phys_addr_t base,
+                qemu_irq pic[], struct omap_mpu_state_s *mpu, omap_clk clk);
+
+enum omap_dma_port {
+    emiff = 0,
+    emifs,
+    imif,
+    tipb,
+    local,
+    tipb_mpui,
+    omap_dma_port_last,
+};
+
+struct omap_dma_lcd_channel_s {
+    enum omap_dma_port src;
+    target_phys_addr_t src_f1_top;
+    target_phys_addr_t src_f1_bottom;
+    target_phys_addr_t src_f2_top;
+    target_phys_addr_t src_f2_bottom;
+    /* Destination port is fixed.  */
+    int interrupts;
+    int condition;
+    int dual;
+
+    int current_frame;
+    ram_addr_t phys_framebuffer[2];
+    qemu_irq irq;
+    struct omap_mpu_state_s *mpu;
+};
+
+/*
+ * DMA request numbers for OMAP1
+ * See /usr/include/asm-arm/arch-omap/dma.h in Linux.
+ */
+# define OMAP_DMA_NO_DEVICE		0
+# define OMAP_DMA_MCSI1_TX		1
+# define OMAP_DMA_MCSI1_RX		2
+# define OMAP_DMA_I2C_RX		3
+# define OMAP_DMA_I2C_TX		4
+# define OMAP_DMA_EXT_NDMA_REQ0		5
+# define OMAP_DMA_EXT_NDMA_REQ1		6
+# define OMAP_DMA_UWIRE_TX		7
+# define OMAP_DMA_MCBSP1_TX		8
+# define OMAP_DMA_MCBSP1_RX		9
+# define OMAP_DMA_MCBSP3_TX		10
+# define OMAP_DMA_MCBSP3_RX		11
+# define OMAP_DMA_UART1_TX		12
+# define OMAP_DMA_UART1_RX		13
+# define OMAP_DMA_UART2_TX		14
+# define OMAP_DMA_UART2_RX		15
+# define OMAP_DMA_MCBSP2_TX		16
+# define OMAP_DMA_MCBSP2_RX		17
+# define OMAP_DMA_UART3_TX		18
+# define OMAP_DMA_UART3_RX		19
+# define OMAP_DMA_CAMERA_IF_RX		20
+# define OMAP_DMA_MMC_TX		21
+# define OMAP_DMA_MMC_RX		22
+# define OMAP_DMA_NAND			23	/* Not in OMAP310 */
+# define OMAP_DMA_IRQ_LCD_LINE		24	/* Not in OMAP310 */
+# define OMAP_DMA_MEMORY_STICK		25	/* Not in OMAP310 */
+# define OMAP_DMA_USB_W2FC_RX0		26
+# define OMAP_DMA_USB_W2FC_RX1		27
+# define OMAP_DMA_USB_W2FC_RX2		28
+# define OMAP_DMA_USB_W2FC_TX0		29
+# define OMAP_DMA_USB_W2FC_TX1		30
+# define OMAP_DMA_USB_W2FC_TX2		31
+
+/* These are only for 1610 */
+# define OMAP_DMA_CRYPTO_DES_IN		32
+# define OMAP_DMA_SPI_TX		33
+# define OMAP_DMA_SPI_RX		34
+# define OMAP_DMA_CRYPTO_HASH		35
+# define OMAP_DMA_CCP_ATTN		36
+# define OMAP_DMA_CCP_FIFO_NOT_EMPTY	37
+# define OMAP_DMA_CMT_APE_TX_CHAN_0	38
+# define OMAP_DMA_CMT_APE_RV_CHAN_0	39
+# define OMAP_DMA_CMT_APE_TX_CHAN_1	40
+# define OMAP_DMA_CMT_APE_RV_CHAN_1	41
+# define OMAP_DMA_CMT_APE_TX_CHAN_2	42
+# define OMAP_DMA_CMT_APE_RV_CHAN_2	43
+# define OMAP_DMA_CMT_APE_TX_CHAN_3	44
+# define OMAP_DMA_CMT_APE_RV_CHAN_3	45
+# define OMAP_DMA_CMT_APE_TX_CHAN_4	46
+# define OMAP_DMA_CMT_APE_RV_CHAN_4	47
+# define OMAP_DMA_CMT_APE_TX_CHAN_5	48
+# define OMAP_DMA_CMT_APE_RV_CHAN_5	49
+# define OMAP_DMA_CMT_APE_TX_CHAN_6	50
+# define OMAP_DMA_CMT_APE_RV_CHAN_6	51
+# define OMAP_DMA_CMT_APE_TX_CHAN_7	52
+# define OMAP_DMA_CMT_APE_RV_CHAN_7	53
+# define OMAP_DMA_MMC2_TX		54
+# define OMAP_DMA_MMC2_RX		55
+# define OMAP_DMA_CRYPTO_DES_OUT	56
+
+struct omap_mpu_timer_s;
+struct omap_mpu_timer_s *omap_mpu_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk);
+
+struct omap_watchdog_timer_s;
+struct omap_watchdog_timer_s *omap_wd_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk);
+
+struct omap_32khz_timer_s;
+struct omap_32khz_timer_s *omap_os_timer_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk);
+
+struct omap_tipb_bridge_s;
+struct omap_tipb_bridge_s *omap_tipb_bridge_init(target_phys_addr_t base,
+                qemu_irq abort_irq, omap_clk clk);
+
+struct omap_uart_s;
+struct omap_uart_s *omap_uart_init(target_phys_addr_t base,
+                qemu_irq irq, omap_clk clk, CharDriverState *chr);
+
+/* omap_lcdc.c */
+struct omap_lcd_panel_s;
+void omap_lcdc_reset(struct omap_lcd_panel_s *s);
+struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
+                struct omap_dma_lcd_channel_s *dma, DisplayState *ds,
+                ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk);
+
+/* omap_mmc.c */
+struct omap_mmc_s;
+struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
+                qemu_irq irq, qemu_irq dma[], omap_clk clk);
+void omap_mmc_reset(struct omap_mmc_s *s);
+
+# define cpu_is_omap310(cpu)		(cpu->mpu_model == omap310)
+# define cpu_is_omap1510(cpu)		(cpu->mpu_model == omap1510)
+# define cpu_is_omap15xx(cpu)		\
+        (cpu_is_omap310(cpu) || cpu_is_omap1510(cpu))
+# define cpu_class_omap1(cpu)		1
+
+struct omap_mpu_state_s {
+    enum omap1_mpu_model {
+        omap310,
+        omap1510,
+    } mpu_model;
+
+    CPUState *env;
+
+    qemu_irq *irq[2];
+    qemu_irq *drq;
+
+    qemu_irq wakeup;
+
+    struct omap_dma_port_if_s {
+        uint32_t (*read[3])(struct omap_mpu_state_s *s,
+                        target_phys_addr_t offset);
+        void (*write[3])(struct omap_mpu_state_s *s,
+                        target_phys_addr_t offset, uint32_t value);
+        int (*addr_valid)(struct omap_mpu_state_s *s,
+                        target_phys_addr_t addr);
+    } port[omap_dma_port_last];
+
+    unsigned long sdram_size;
+    unsigned long sram_size;
+
+    /* MPUI-TIPB peripherals */
+    struct omap_uart_s *uart3;
+
+    /* MPU public TIPB peripherals */
+    struct omap_32khz_timer_s *os_timer;
+
+    struct omap_uart_s *uart1;
+    struct omap_uart_s *uart2;
+
+    struct omap_mmc_s *mmc;
+
+    /* MPU private TIPB peripherals */
+    struct omap_intr_handler_s *ih[2];
+
+    struct omap_dma_s *dma;
+
+    struct omap_mpu_timer_s *timer[3];
+    struct omap_watchdog_timer_s *wdt;
+
+    struct omap_lcd_panel_s *lcd;
+
+    target_phys_addr_t ulpd_pm_base;
+    uint32_t ulpd_pm_regs[21];
+    int64_t ulpd_gauge_start;
+
+    target_phys_addr_t pin_cfg_base;
+    uint32_t func_mux_ctrl[14];
+    uint32_t comp_mode_ctrl[1];
+    uint32_t pull_dwn_ctrl[4];
+    uint32_t gate_inh_ctrl[1];
+    uint32_t voltage_ctrl[1];
+    uint32_t test_dbg_ctrl[1];
+    uint32_t mod_conf_ctrl[1];
+    int compat1509;
+
+    uint32_t mpui_ctrl;
+    target_phys_addr_t mpui_base;
+
+    struct omap_tipb_bridge_s *private_tipb;
+    struct omap_tipb_bridge_s *public_tipb;
+
+    target_phys_addr_t tcmi_base;
+    uint32_t tcmi_regs[17];
+
+    struct dpll_ctl_s {
+        target_phys_addr_t base;
+        uint16_t mode;
+        omap_clk dpll;
+    } dpll[3];
+
+    omap_clk clks;
+    struct {
+        target_phys_addr_t mpu_base;
+        target_phys_addr_t dsp_base;
+
+        int cold_start;
+        int clocking_scheme;
+        uint16_t arm_ckctl;
+        uint16_t arm_idlect1;
+        uint16_t arm_idlect2;
+        uint16_t arm_ewupct;
+        uint16_t arm_rstct1;
+        uint16_t arm_rstct2;
+        uint16_t arm_ckout1;
+        int dpll1_mode;
+        uint16_t dsp_idlect1;
+        uint16_t dsp_idlect2;
+        uint16_t dsp_rstct2;
+    } clkm;
+} *omap310_mpu_init(unsigned long sdram_size,
+                DisplayState *ds, const char *core);
+
+# if TARGET_PHYS_ADDR_BITS == 32
+#  define OMAP_FMT_plx "%#08x"
+# elif TARGET_PHYS_ADDR_BITS == 64
+#  define OMAP_FMT_plx "%#08" PRIx64
+# else
+#  error TARGET_PHYS_ADDR_BITS undefined
+# endif
+
+uint32_t omap_badwidth_read16(void *opaque, target_phys_addr_t addr);
+void omap_badwidth_write16(void *opaque, target_phys_addr_t addr,
+                uint32_t value);
+uint32_t omap_badwidth_read32(void *opaque, target_phys_addr_t addr);
+void omap_badwidth_write32(void *opaque, target_phys_addr_t addr,
+                uint32_t value);
+
+# define OMAP_BAD_REG(paddr)		\
+        printf("%s: Bad register " OMAP_FMT_plx "\n", __FUNCTION__, paddr)
+# define OMAP_RO_REG(paddr)		\
+        printf("%s: Read-only register " OMAP_FMT_plx "\n",	\
+                        __FUNCTION__, paddr)
+# define OMAP_16B_REG(paddr)		\
+        printf("%s: 16-bit register " OMAP_FMT_plx "\n",	\
+                        __FUNCTION__, paddr)
+# define OMAP_32B_REG(paddr)		\
+        printf("%s: 32-bit register " OMAP_FMT_plx "\n",	\
+                        __FUNCTION__, paddr)
+
+#endif /* hw_omap_h */
diff --git a/hw/omap1_clk.c b/hw/omap1_clk.c
new file mode 100644
index 0000000..7888e41
--- /dev/null
+++ b/hw/omap1_clk.c
@@ -0,0 +1,745 @@
+/*
+ * OMAP clocks.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * Clocks data comes in part from arch/arm/mach-omap1/clock.h in Linux.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "vl.h"
+
+struct clk {
+    const char *name;
+    const char *alias;
+    struct clk *parent;
+    struct clk *child1;
+    struct clk *sibling;
+#define ALWAYS_ENABLED		(1 << 0)
+#define CLOCK_IN_OMAP310	(1 << 10)
+#define CLOCK_IN_OMAP730	(1 << 11)
+#define CLOCK_IN_OMAP1510	(1 << 12)
+#define CLOCK_IN_OMAP16XX	(1 << 13)
+    uint32_t flags;
+    int id;
+
+    int running;		/* Is currently ticking */
+    int enabled;		/* Is enabled, regardless of its input clk */
+    unsigned long rate;		/* Current rate (if .running) */
+    unsigned int divisor;	/* Rate relative to input (if .enabled) */
+    unsigned int multiplier;	/* Rate relative to input (if .enabled) */
+    qemu_irq users[16];		/* Who to notify on change */
+    int usecount;		/* Automatically idle when unused */
+};
+
+static struct clk xtal_osc12m = {
+    .name	= "xtal_osc_12m",
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk xtal_osc32k = {
+    .name	= "xtal_osc_32k",
+    .rate	= 32768,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk ck_ref = {
+    .name	= "ck_ref",
+    .alias	= "clkin",
+    .parent	= &xtal_osc12m,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+/* If a dpll is disabled it becomes a bypass, child clocks don't stop */
+static struct clk dpll1 = {
+    .name	= "dpll1",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dpll2 = {
+    .name	= "dpll2",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk dpll3 = {
+    .name	= "dpll3",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk dpll4 = {
+    .name	= "dpll4",
+    .parent	= &ck_ref,
+    .multiplier	= 4,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk apll = {
+    .name	= "apll",
+    .parent	= &ck_ref,
+    .multiplier	= 48,
+    .divisor	= 12,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk ck_48m = {
+    .name	= "ck_48m",
+    .parent	= &dpll4,	/* either dpll4 or apll */
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk ck_dpll1out = {
+    .name	= "ck_dpll1out",
+    .parent	= &dpll1,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk sossi_ck = {
+    .name	= "ck_sossi",
+    .parent	= &ck_dpll1out,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk clkm1 = {
+    .name	= "clkm1",
+    .alias	= "ck_gen1",
+    .parent	= &dpll1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk clkm2 = {
+    .name	= "clkm2",
+    .alias	= "ck_gen2",
+    .parent	= &dpll1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk clkm3 = {
+    .name	= "clkm3",
+    .alias	= "ck_gen3",
+    .parent	= &dpll1,	/* either dpll1 or ck_ref */
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arm_ck = {
+    .name	= "arm_ck",
+    .alias	= "mpu_ck",
+    .parent	= &clkm1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk armper_ck = {
+    .name	= "armper_ck",
+    .alias	= "mpuper_ck",
+    .parent	= &clkm1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk arm_gpio_ck = {
+    .name	= "arm_gpio_ck",
+    .alias	= "mpu_gpio_ck",
+    .parent	= &clkm1,
+    .divisor	= 1,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk armxor_ck = {
+    .name	= "armxor_ck",
+    .alias	= "mpuxor_ck",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk armtim_ck = {
+    .name	= "armtim_ck",
+    .alias	= "mputim_ck",
+    .parent	= &ck_ref,	/* either CLKIN or DPLL1 */
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk armwdt_ck = {
+    .name	= "armwdt_ck",
+    .alias	= "mpuwd_ck",
+    .parent	= &clkm1,
+    .divisor	= 14,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arminth_ck16xx = {
+    .name	= "arminth_ck",
+    .parent	= &arm_ck,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+    /* Note: On 16xx the frequency can be divided by 2 by programming
+     * ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
+     *
+     * 1510 version is in TC clocks.
+     */
+};
+
+static struct clk dsp_ck = {
+    .name	= "dsp_ck",
+    .parent	= &clkm2,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dspmmu_ck = {
+    .name	= "dspmmu_ck",
+    .parent	= &clkm2,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dspper_ck = {
+    .name	= "dspper_ck",
+    .parent	= &clkm2,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dspxor_ck = {
+    .name	= "dspxor_ck",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dsptim_ck = {
+    .name	= "dsptim_ck",
+    .parent	= &ck_ref,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc_ck = {
+    .name	= "tc_ck",
+    .parent	= &clkm3,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            CLOCK_IN_OMAP730 | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk arminth_ck15xx = {
+    .name	= "arminth_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+    /* Note: On 1510 the frequency follows TC_CK
+     *
+     * 16xx version is in MPU clocks.
+     */
+};
+
+static struct clk tipb_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name	= "tipb_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk l3_ocpi_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name	= "l3_ocpi_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc1_ck = {
+    .name	= "tc1_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk tc2_ck = {
+    .name	= "tc2_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk dma_ck = {
+    /* No-idle controlled by "tc_ck" */
+    .name	= "dma_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk dma_lcdfree_ck = {
+    .name	= "dma_lcdfree_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk api_ck = {
+    .name	= "api_ck",
+    .alias	= "mpui_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk lb_ck = {
+    .name	= "lb_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk lbfree_ck = {
+    .name	= "lbfree_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk rhea1_ck = {
+    .name	= "rhea1_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk rhea2_ck = {
+    .name	= "rhea2_ck",
+    .parent	= &tc_ck,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+};
+
+static struct clk lcd_ck_16xx = {
+    .name	= "lcd_ck",
+    .parent	= &clkm3,
+    .flags	= CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP730,
+};
+
+static struct clk lcd_ck_1510 = {
+    .name	= "lcd_ck",
+    .parent	= &clkm3,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk uart1_1510 = {
+    .name	= "uart1_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,	/* either armper_ck or dpll4 */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk uart1_16xx = {
+    .name	= "uart1_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk uart2_ck = {
+    .name	= "uart2_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,	/* either armper_ck or dpll4 */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310 |
+            ALWAYS_ENABLED,
+};
+
+static struct clk uart3_1510 = {
+    .name	= "uart3_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,/* either armper_ck or dpll4 */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED,
+};
+
+static struct clk uart3_16xx = {
+    .name	= "uart3_ck",
+    /* Direct from ULPD, no real parent */
+    .parent	= &armper_ck,
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk usb_clk0 = {	/* 6 MHz output on W4_USB_CLK0 */
+    .name	= "usb_clk0",
+    .alias	= "usb.clko",
+    /* Direct from ULPD, no parent */
+    .rate	= 6000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk usb_hhc_ck1510 = {
+    .name	= "usb_hhc_ck",
+    /* Direct from ULPD, no parent */
+    .rate	= 48000000, /* Actually 2 clocks, 12MHz and 48MHz */
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310,
+};
+
+static struct clk usb_hhc_ck16xx = {
+    .name	= "usb_hhc_ck",
+    /* Direct from ULPD, no parent */
+    .rate	= 48000000,
+    /* OTG_SYSCON_2.OTG_PADEN == 0 (not 1510-compatible) */
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk usb_dc_ck = {
+    .name	= "usb_dc_ck",
+    /* Direct from ULPD, no parent */
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk mclk_1510 = {
+    .name	= "mclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510,
+};
+
+static struct clk bclk_310 = {
+    .name	= "bt_mclk_out",	/* Alias midi_mclk_out? */
+    .parent	= &armper_ck,
+    .flags	= CLOCK_IN_OMAP310,
+};
+
+static struct clk mclk_310 = {
+    .name	= "com_mclk_out",
+    .parent	= &armper_ck,
+    .flags	= CLOCK_IN_OMAP310,
+};
+
+static struct clk mclk_16xx = {
+    .name	= "mclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk bclk_1510 = {
+    .name	= "bclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .rate	= 12000000,
+    .flags	= CLOCK_IN_OMAP1510,
+};
+
+static struct clk bclk_16xx = {
+    .name	= "bclk",
+    /* Direct from ULPD, no parent. May be enabled by ext hardware. */
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk mmc1_ck = {
+    .name	= "mmc_ck",
+    .id		= 1,
+    /* Functional clock is direct from ULPD, interface clock is ARMPER */
+    .parent	= &armper_ck,	/* either armper_ck or dpll4 */
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | CLOCK_IN_OMAP310,
+};
+
+static struct clk mmc2_ck = {
+    .name	= "mmc_ck",
+    .id		= 2,
+    /* Functional clock is direct from ULPD, interface clock is ARMPER */
+    .parent	= &armper_ck,
+    .rate	= 48000000,
+    .flags	= CLOCK_IN_OMAP16XX,
+};
+
+static struct clk cam_mclk = {
+    .name	= "cam.mclk",
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+    .rate	= 12000000,
+};
+
+static struct clk cam_exclk = {
+    .name	= "cam.exclk",
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+    /* Either 12M from cam.mclk or 48M from dpll4 */
+    .parent	= &cam_mclk,
+};
+
+static struct clk cam_lclk = {
+    .name	= "cam.lclk",
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+};
+
+static struct clk i2c_fck = {
+    .name	= "i2c_fck",
+    .id		= 1,
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            ALWAYS_ENABLED,
+    .parent	= &armxor_ck,
+};
+
+static struct clk i2c_ick = {
+    .name	= "i2c_ick",
+    .id		= 1,
+    .flags	= CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
+    .parent	= &armper_ck,
+};
+
+static struct clk clk32k = {
+    .name	= "clk32-kHz",
+    .flags	= CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+            ALWAYS_ENABLED,
+    .parent     = &xtal_osc32k,
+};
+
+static struct clk *onchip_clks[] = {
+    /* non-ULPD clocks */
+    &xtal_osc12m,
+    &xtal_osc32k,
+    &ck_ref,
+    &dpll1,
+    &dpll2,
+    &dpll3,
+    &dpll4,
+    &apll,
+    &ck_48m,
+    /* CK_GEN1 clocks */
+    &clkm1,
+    &ck_dpll1out,
+    &sossi_ck,
+    &arm_ck,
+    &armper_ck,
+    &arm_gpio_ck,
+    &armxor_ck,
+    &armtim_ck,
+    &armwdt_ck,
+    &arminth_ck15xx,  &arminth_ck16xx,
+    /* CK_GEN2 clocks */
+    &clkm2,
+    &dsp_ck,
+    &dspmmu_ck,
+    &dspper_ck,
+    &dspxor_ck,
+    &dsptim_ck,
+    /* CK_GEN3 clocks */
+    &clkm3,
+    &tc_ck,
+    &tipb_ck,
+    &l3_ocpi_ck,
+    &tc1_ck,
+    &tc2_ck,
+    &dma_ck,
+    &dma_lcdfree_ck,
+    &api_ck,
+    &lb_ck,
+    &lbfree_ck,
+    &rhea1_ck,
+    &rhea2_ck,
+    &lcd_ck_16xx,
+    &lcd_ck_1510,
+    /* ULPD clocks */
+    &uart1_1510,
+    &uart1_16xx,
+    &uart2_ck,
+    &uart3_1510,
+    &uart3_16xx,
+    &usb_clk0,
+    &usb_hhc_ck1510, &usb_hhc_ck16xx,
+    &usb_dc_ck,
+    &mclk_1510,  &mclk_16xx, &mclk_310,
+    &bclk_1510,  &bclk_16xx, &bclk_310,
+    &mmc1_ck,
+    &mmc2_ck,
+    &cam_mclk,
+    &cam_exclk,
+    &cam_lclk,
+    &clk32k,
+    /* Virtual clocks */
+    &i2c_fck,
+    &i2c_ick,
+    0
+};
+
+void omap_clk_adduser(struct clk *clk, qemu_irq user)
+{
+    qemu_irq *i;
+
+    for (i = clk->users; *i; i ++);
+    *i = user;
+}
+
+/* If a clock is allowed to idle, it is disabled automatically when
+ * all of clock domains using it are disabled.  */
+int omap_clk_is_idle(struct clk *clk)
+{
+    struct clk *chld;
+
+    if (!clk->enabled && (!clk->usecount || !(clk->flags && ALWAYS_ENABLED)))
+        return 1;
+    if (clk->usecount)
+        return 0;
+
+    for (chld = clk->child1; chld; chld = chld->sibling)
+        if (!omap_clk_is_idle(chld))
+            return 0;
+    return 1;
+}
+
+struct clk *omap_findclk(struct omap_mpu_state_s *mpu, const char *name)
+{
+    struct clk *i;
+
+    for (i = mpu->clks; i->name; i ++)
+        if (!strcmp(i->name, name) || (i->alias && !strcmp(i->alias, name)))
+            return i;
+    cpu_abort(mpu->env, "%s: %s not found\n", __FUNCTION__, name);
+}
+
+void omap_clk_get(struct clk *clk)
+{
+    clk->usecount ++;
+}
+
+void omap_clk_put(struct clk *clk)
+{
+    if (!(clk->usecount --))
+        cpu_abort(cpu_single_env, "%s: %s is not in use\n",
+                        __FUNCTION__, clk->name);
+}
+
+static void omap_clk_update(struct clk *clk)
+{
+    int parent, running;
+    qemu_irq *user;
+    struct clk *i;
+
+    if (clk->parent)
+        parent = clk->parent->running;
+    else
+        parent = 1;
+
+    running = parent && (clk->enabled ||
+                    ((clk->flags & ALWAYS_ENABLED) && clk->usecount));
+    if (clk->running != running) {
+        clk->running = running;
+        for (user = clk->users; *user; user ++)
+            qemu_set_irq(*user, running);
+        for (i = clk->child1; i; i = i->sibling)
+            omap_clk_update(i);
+    }
+}
+
+static void omap_clk_rate_update_full(struct clk *clk, unsigned long int rate,
+                unsigned long int div, unsigned long int mult)
+{
+    struct clk *i;
+    qemu_irq *user;
+
+    clk->rate = muldiv64(rate, mult, div);
+    if (clk->running)
+        for (user = clk->users; *user; user ++)
+            qemu_irq_raise(*user);
+    for (i = clk->child1; i; i = i->sibling)
+        omap_clk_rate_update_full(i, rate,
+                        div * i->divisor, mult * i->multiplier);
+}
+
+static void omap_clk_rate_update(struct clk *clk)
+{
+    struct clk *i;
+    unsigned long int div, mult = div = 1;
+
+    for (i = clk; i->parent; i = i->parent) {
+        div *= i->divisor;
+        mult *= i->multiplier;
+    }
+
+    omap_clk_rate_update_full(clk, i->rate, div, mult);
+}
+
+void omap_clk_reparent(struct clk *clk, struct clk *parent)
+{
+    struct clk **p;
+
+    if (clk->parent) {
+        for (p = &clk->parent->child1; *p != clk; p = &(*p)->sibling);
+        *p = clk->sibling;
+    }
+
+    clk->parent = parent;
+    if (parent) {
+        clk->sibling = parent->child1;
+        parent->child1 = clk;
+        omap_clk_update(clk);
+        omap_clk_rate_update(clk);
+    } else
+        clk->sibling = 0;
+}
+
+void omap_clk_onoff(struct clk *clk, int on)
+{
+    clk->enabled = on;
+    omap_clk_update(clk);
+}
+
+void omap_clk_canidle(struct clk *clk, int can)
+{
+    if (can)
+        omap_clk_put(clk);
+    else
+        omap_clk_get(clk);
+}
+
+void omap_clk_setrate(struct clk *clk, int divide, int multiply)
+{
+    clk->divisor = divide;
+    clk->multiplier = multiply;
+    omap_clk_rate_update(clk);
+}
+
+int64_t omap_clk_getrate(omap_clk clk)
+{
+    return clk->rate;
+}
+
+void omap_clk_init(struct omap_mpu_state_s *mpu)
+{
+    struct clk **i, *j, *k;
+    int count;
+    int flag;
+
+    if (cpu_is_omap310(mpu))
+        flag = CLOCK_IN_OMAP310;
+    else if (cpu_is_omap1510(mpu))
+        flag = CLOCK_IN_OMAP1510;
+    else
+        return;
+
+    for (i = onchip_clks, count = 0; *i; i ++)
+        if ((*i)->flags & flag)
+            count ++;
+    mpu->clks = (struct clk *) qemu_mallocz(sizeof(struct clk) * (count + 1));
+    for (i = onchip_clks, j = mpu->clks; *i; i ++)
+        if ((*i)->flags & flag) {
+            memcpy(j, *i, sizeof(struct clk));
+            for (k = mpu->clks; k < j; k ++)
+                if (j->parent && !strcmp(j->parent->name, k->name)) {
+                    j->parent = k;
+                    j->sibling = k->child1;
+                    k->child1 = j;
+                } else if (k->parent && !strcmp(k->parent->name, j->name)) {
+                    k->parent = j;
+                    k->sibling = j->child1;
+                    j->child1 = k;
+                }
+            j->divisor = j->divisor ?: 1;
+            j->multiplier = j->multiplier ?: 1;
+            j ++;
+        }
+}
diff --git a/hw/omap_lcd_template.h b/hw/omap_lcd_template.h
new file mode 100644
index 0000000..4e84fa1
--- /dev/null
+++ b/hw/omap_lcd_template.h
@@ -0,0 +1,172 @@
+/*
+ * QEMU OMAP LCD Emulator templates
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if DEPTH == 8
+# define BPP 1
+# define PIXEL_TYPE uint8_t
+#elif DEPTH == 15 || DEPTH == 16
+# define BPP 2
+# define PIXEL_TYPE uint16_t
+#elif DEPTH == 32
+# define BPP 4
+# define PIXEL_TYPE uint32_t
+#else
+# error unsupport depth
+#endif
+
+/*
+ * 2-bit colour
+ */
+static void glue(draw_line2_, DEPTH)(
+                uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+{
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 2;
+        r = (pal[v & 3] >> 4) & 0xf0;
+        g = pal[v & 3] & 0xf0;
+        b = (pal[v & 3] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        s ++;
+        width -= 4;
+    } while (width > 0);
+}
+
+/*
+ * 4-bit colour
+ */
+static void glue(draw_line4_, DEPTH)(
+                uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+{
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v & 0xf] >> 4) & 0xf0;
+        g = pal[v & 0xf] & 0xf0;
+        b = (pal[v & 0xf] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        v >>= 4;
+        r = (pal[v & 0xf] >> 4) & 0xf0;
+        g = pal[v & 0xf] & 0xf0;
+        b = (pal[v & 0xf] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        d += BPP;
+        s ++;
+        width -= 2;
+    } while (width > 0);
+}
+
+/*
+ * 8-bit colour
+ */
+static void glue(draw_line8_, DEPTH)(
+                uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+{
+    uint8_t v, r, g, b;
+
+    do {
+        v = ldub_raw((void *) s);
+        r = (pal[v] >> 4) & 0xf0;
+        g = pal[v] & 0xf0;
+        b = (pal[v] << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s ++;
+        d += BPP;
+    } while (-- width != 0);
+}
+
+/*
+ * 12-bit colour
+ */
+static void glue(draw_line12_, DEPTH)(
+                uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+{
+    uint16_t v;
+    uint8_t r, g, b;
+
+    do {
+        v = lduw_raw((void *) s);
+        r = (v >> 4) & 0xf0;
+        g = v & 0xf0;
+        b = (v << 4) & 0xf0;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (-- width != 0);
+}
+
+/*
+ * 16-bit colour
+ */
+static void glue(draw_line16_, DEPTH)(
+                uint8_t *d, const uint8_t *s, int width, const uint16_t *pal)
+{
+#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
+    memcpy(d, s, width * 2);
+#else
+    uint16_t v;
+    uint8_t r, g, b;
+
+    do {
+        v = lduw_raw((void *) s);
+        r = (v >> 8) & 0xf8;
+        g = (v >> 3) & 0xfc;
+        b = (v << 3) & 0xf8;
+        ((PIXEL_TYPE *) d)[0] = glue(rgb_to_pixel, DEPTH)(r, g, b);
+        s += 2;
+        d += BPP;
+    } while (-- width != 0);
+#endif
+}
+
+#undef DEPTH
+#undef BPP
+#undef PIXEL_TYPE
diff --git a/hw/omap_lcdc.c b/hw/omap_lcdc.c
new file mode 100644
index 0000000..543d1f2
--- /dev/null
+++ b/hw/omap_lcdc.c
@@ -0,0 +1,499 @@
+/*
+ * OMAP LCD controller.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "vl.h"
+
+struct omap_lcd_panel_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    DisplayState *state;
+    ram_addr_t imif_base;
+    ram_addr_t emiff_base;
+
+    int plm;
+    int tft;
+    int mono;
+    int enable;
+    int width;
+    int height;
+    int interrupts;
+    uint32_t timing[3];
+    uint32_t subpanel;
+    uint32_t ctrl;
+
+    struct omap_dma_lcd_channel_s *dma;
+    uint16_t palette[256];
+    int palette_done;
+    int frame_done;
+    int invalidate;
+    int sync_error;
+};
+
+static void omap_lcd_interrupts(struct omap_lcd_panel_s *s)
+{
+    if (s->frame_done && (s->interrupts & 1)) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    if (s->palette_done && (s->interrupts & 2)) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    if (s->sync_error) {
+        qemu_irq_raise(s->irq);
+        return;
+    }
+
+    qemu_irq_lower(s->irq);
+}
+
+#include "pixel_ops.h"
+
+typedef void draw_line_func(
+                uint8_t *d, const uint8_t *s, int width, const uint16_t *pal);
+
+#define DEPTH 8
+#include "omap_lcd_template.h"
+#define DEPTH 15
+#include "omap_lcd_template.h"
+#define DEPTH 16
+#include "omap_lcd_template.h"
+#define DEPTH 32
+#include "omap_lcd_template.h"
+
+static draw_line_func *draw_line_table2[33] = {
+    [0 ... 32]	= 0,
+    [8]		= draw_line2_8,
+    [15]	= draw_line2_15,
+    [16]	= draw_line2_16,
+    [32]	= draw_line2_32,
+}, *draw_line_table4[33] = {
+    [0 ... 32]	= 0,
+    [8]		= draw_line4_8,
+    [15]	= draw_line4_15,
+    [16]	= draw_line4_16,
+    [32]	= draw_line4_32,
+}, *draw_line_table8[33] = {
+    [0 ... 32]	= 0,
+    [8]		= draw_line8_8,
+    [15]	= draw_line8_15,
+    [16]	= draw_line8_16,
+    [32]	= draw_line8_32,
+}, *draw_line_table12[33] = {
+    [0 ... 32]	= 0,
+    [8]		= draw_line12_8,
+    [15]	= draw_line12_15,
+    [16]	= draw_line12_16,
+    [32]	= draw_line12_32,
+}, *draw_line_table16[33] = {
+    [0 ... 32]	= 0,
+    [8]		= draw_line16_8,
+    [15]	= draw_line16_15,
+    [16]	= draw_line16_16,
+    [32]	= draw_line16_32,
+};
+
+void omap_update_display(void *opaque)
+{
+    struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque;
+    draw_line_func *draw_line;
+    int size, dirty[2], minline, maxline, height;
+    int line, width, linesize, step, bpp, frame_offset;
+    ram_addr_t frame_base, scanline, newline, x;
+    uint8_t *s, *d;
+
+    if (!omap_lcd || omap_lcd->plm == 1 ||
+                    !omap_lcd->enable || !omap_lcd->state->depth)
+        return;
+
+    frame_offset = 0;
+    if (omap_lcd->plm != 2) {
+        memcpy(omap_lcd->palette, phys_ram_base +
+                        omap_lcd->dma->phys_framebuffer[
+                        omap_lcd->dma->current_frame], 0x200);
+        switch (omap_lcd->palette[0] >> 12 & 7) {
+        case 3 ... 7:
+            frame_offset += 0x200;
+            break;
+        default:
+            frame_offset += 0x20;
+        }
+    }
+
+    /* Colour depth */
+    switch ((omap_lcd->palette[0] >> 12) & 7) {
+    case 1:
+        draw_line = draw_line_table2[omap_lcd->state->depth];
+        bpp = 2;
+        break;
+
+    case 2:
+        draw_line = draw_line_table4[omap_lcd->state->depth];
+        bpp = 4;
+        break;
+
+    case 3:
+        draw_line = draw_line_table8[omap_lcd->state->depth];
+        bpp = 8;
+        break;
+
+    case 4 ... 7:
+        if (!omap_lcd->tft)
+            draw_line = draw_line_table12[omap_lcd->state->depth];
+        else
+            draw_line = draw_line_table16[omap_lcd->state->depth];
+        bpp = 16;
+        break;
+
+    default:
+        /* Unsupported at the moment.  */
+        return;
+    }
+
+    /* Resolution */
+    width = omap_lcd->width;
+    if (width != omap_lcd->state->width ||
+            omap_lcd->height != omap_lcd->state->height) {
+        dpy_resize(omap_lcd->state,
+                omap_lcd->width, omap_lcd->height);
+        omap_lcd->invalidate = 1;
+    }
+
+    if (omap_lcd->dma->current_frame == 0)
+        size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top;
+    else
+        size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top;
+
+    if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) {
+        omap_lcd->sync_error = 1;
+        omap_lcd_interrupts(omap_lcd);
+        omap_lcd->enable = 0;
+        return;
+    }
+
+    /* Content */
+    frame_base = omap_lcd->dma->phys_framebuffer[
+            omap_lcd->dma->current_frame] + frame_offset;
+    omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame;
+    if (omap_lcd->dma->interrupts & 1)
+        qemu_irq_raise(omap_lcd->dma->irq);
+    if (omap_lcd->dma->dual)
+        omap_lcd->dma->current_frame ^= 1;
+
+    if (!omap_lcd->state->depth)
+        return;
+
+    line = 0;
+    height = omap_lcd->height;
+    if (omap_lcd->subpanel & (1 << 31)) {
+        if (omap_lcd->subpanel & (1 << 29))
+            line = (omap_lcd->subpanel >> 16) & 0x3ff;
+        else
+            height = (omap_lcd->subpanel >> 16) & 0x3ff;
+        /* TODO: fill the rest of the panel with DPD */
+    }
+    step = width * bpp >> 3;
+    scanline = frame_base + step * line;
+    s = (uint8_t *) (phys_ram_base + scanline);
+    d = omap_lcd->state->data;
+    linesize = omap_lcd->state->linesize;
+
+    dirty[0] = dirty[1] =
+            cpu_physical_memory_get_dirty(scanline, VGA_DIRTY_FLAG);
+    minline = height;
+    maxline = line;
+    for (; line < height; line ++) {
+        newline = scanline + step;
+        for (x = scanline + TARGET_PAGE_SIZE; x < newline;
+                        x += TARGET_PAGE_SIZE) {
+            dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
+            dirty[0] |= dirty[1];
+        }
+        if (dirty[0] || omap_lcd->invalidate) {
+            draw_line(d, s, width, omap_lcd->palette);
+            if (line < minline)
+                minline = line;
+            maxline = line + 1;
+        }
+        scanline = newline;
+        dirty[0] = dirty[1];
+        s += step;
+        d += linesize;
+    }
+
+    if (maxline >= minline) {
+        dpy_update(omap_lcd->state, 0, minline, width, maxline);
+        cpu_physical_memory_reset_dirty(frame_base + step * minline,
+                        frame_base + step * maxline, VGA_DIRTY_FLAG);
+    }
+}
+
+static int ppm_save(const char *filename, uint8_t *data,
+                int w, int h, int linesize)
+{
+    FILE *f;
+    uint8_t *d, *d1;
+    unsigned int v;
+    int y, x, bpp;
+
+    f = fopen(filename, "wb");
+    if (!f)
+        return -1;
+    fprintf(f, "P6\n%d %d\n%d\n", w, h, 255);
+    d1 = data;
+    bpp = linesize / w;
+    for (y = 0; y < h; y ++) {
+        d = d1;
+        for (x = 0; x < w; x ++) {
+            v = *(uint32_t *) d;
+            switch (bpp) {
+            case 2:
+                fputc((v >> 8) & 0xf8, f);
+                fputc((v >> 3) & 0xfc, f);
+                fputc((v << 3) & 0xf8, f);
+                break;
+            case 3:
+            case 4:
+            default:
+                fputc((v >> 16) & 0xff, f);
+                fputc((v >> 8) & 0xff, f);
+                fputc((v) & 0xff, f);
+                break;
+            }
+            d += bpp;
+        }
+        d1 += linesize;
+    }
+    fclose(f);
+    return 0;
+}
+
+void omap_screen_dump(void *opaque, const char *filename) {
+    struct omap_lcd_panel_s *omap_lcd = opaque;
+    omap_update_display(opaque);
+    if (omap_lcd && omap_lcd->state->data)
+        ppm_save(filename, omap_lcd->state->data,
+                omap_lcd->width, omap_lcd->height,
+                omap_lcd->state->linesize);
+}
+
+void omap_invalidate_display(void *opaque) {
+    struct omap_lcd_panel_s *omap_lcd = opaque;
+    omap_lcd->invalidate = 1;
+}
+
+void omap_lcd_update(struct omap_lcd_panel_s *s) {
+    if (!s->enable) {
+        s->dma->current_frame = -1;
+        s->sync_error = 0;
+        if (s->plm != 1)
+            s->frame_done = 1;
+        omap_lcd_interrupts(s);
+        return;
+    }
+
+    if (s->dma->current_frame == -1) {
+        s->frame_done = 0;
+        s->palette_done = 0;
+        s->dma->current_frame = 0;
+    }
+
+    if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu,
+                            s->dma->src_f1_top) ||
+                    !s->dma->mpu->port[
+                    s->dma->src].addr_valid(s->dma->mpu,
+                            s->dma->src_f1_bottom) ||
+                    (s->dma->dual &&
+                     (!s->dma->mpu->port[
+                      s->dma->src].addr_valid(s->dma->mpu,
+                              s->dma->src_f2_top) ||
+                      !s->dma->mpu->port[
+                      s->dma->src].addr_valid(s->dma->mpu,
+                              s->dma->src_f2_bottom)))) {
+        s->dma->condition |= 1 << 2;
+        if (s->dma->interrupts & (1 << 1))
+            qemu_irq_raise(s->dma->irq);
+        s->enable = 0;
+        return;
+    }
+
+     if (s->dma->src == imif) {
+        /* Framebuffers are in SRAM */
+        s->dma->phys_framebuffer[0] = s->imif_base +
+                s->dma->src_f1_top - OMAP_IMIF_BASE;
+
+        s->dma->phys_framebuffer[1] = s->imif_base +
+                s->dma->src_f2_top - OMAP_IMIF_BASE;
+    } else {
+        /* Framebuffers are in RAM */
+        s->dma->phys_framebuffer[0] = s->emiff_base +
+                s->dma->src_f1_top - OMAP_EMIFF_BASE;
+
+        s->dma->phys_framebuffer[1] = s->emiff_base +
+                s->dma->src_f2_top - OMAP_EMIFF_BASE;
+    }
+
+    if (s->plm != 2 && !s->palette_done) {
+        memcpy(s->palette, phys_ram_base +
+                s->dma->phys_framebuffer[s->dma->current_frame], 0x200);
+        s->palette_done = 1;
+        omap_lcd_interrupts(s);
+    }
+}
+
+static uint32_t omap_lcdc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00:	/* LCD_CONTROL */
+        return (s->tft << 23) | (s->plm << 20) |
+                (s->tft << 7) | (s->interrupts << 3) |
+                (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34;
+
+    case 0x04:	/* LCD_TIMING0 */
+        return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f;
+
+    case 0x08:	/* LCD_TIMING1 */
+        return (s->timing[1] << 10) | (s->height - 1);
+
+    case 0x0c:	/* LCD_TIMING2 */
+        return s->timing[2] | 0xfc000000;
+
+    case 0x10:	/* LCD_STATUS */
+        return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done;
+
+    case 0x14:	/* LCD_SUBPANEL */
+        return s->subpanel;
+
+    default:
+        break;
+    }
+    OMAP_BAD_REG(addr);
+    return 0;
+}
+
+static void omap_lcdc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque;
+    int offset = addr - s->base;
+
+    switch (offset) {
+    case 0x00:	/* LCD_CONTROL */
+        s->plm = (value >> 20) & 3;
+        s->tft = (value >> 7) & 1;
+        s->interrupts = (value >> 3) & 3;
+        s->mono = (value >> 1) & 1;
+        s->ctrl = value & 0x01cff300;
+        if (s->enable != (value & 1)) {
+            s->enable = value & 1;
+            omap_lcd_update(s);
+        }
+        break;
+
+    case 0x04:	/* LCD_TIMING0 */
+        s->timing[0] = value >> 10;
+        s->width = (value & 0x3ff) + 1;
+        break;
+
+    case 0x08:	/* LCD_TIMING1 */
+        s->timing[1] = value >> 10;
+        s->height = (value & 0x3ff) + 1;
+        break;
+
+    case 0x0c:	/* LCD_TIMING2 */
+        s->timing[2] = value;
+        break;
+
+    case 0x10:	/* LCD_STATUS */
+        break;
+
+    case 0x14:	/* LCD_SUBPANEL */
+        s->subpanel = value & 0xa1ffffff;
+        break;
+
+    default:
+        OMAP_BAD_REG(addr);
+    }
+}
+
+static CPUReadMemoryFunc *omap_lcdc_readfn[] = {
+    omap_lcdc_read,
+    omap_lcdc_read,
+    omap_lcdc_read,
+};
+
+static CPUWriteMemoryFunc *omap_lcdc_writefn[] = {
+    omap_lcdc_write,
+    omap_lcdc_write,
+    omap_lcdc_write,
+};
+
+void omap_lcdc_reset(struct omap_lcd_panel_s *s)
+{
+    s->dma->current_frame = -1;
+    s->plm = 0;
+    s->tft = 0;
+    s->mono = 0;
+    s->enable = 0;
+    s->width = 0;
+    s->height = 0;
+    s->interrupts = 0;
+    s->timing[0] = 0;
+    s->timing[1] = 0;
+    s->timing[2] = 0;
+    s->subpanel = 0;
+    s->palette_done = 0;
+    s->frame_done = 0;
+    s->sync_error = 0;
+    s->invalidate = 1;
+    s->subpanel = 0;
+    s->ctrl = 0;
+}
+
+struct omap_lcd_panel_s *omap_lcdc_init(target_phys_addr_t base, qemu_irq irq,
+                struct omap_dma_lcd_channel_s *dma, DisplayState *ds,
+                ram_addr_t imif_base, ram_addr_t emiff_base, omap_clk clk)
+{
+    int iomemtype;
+    struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *)
+            qemu_mallocz(sizeof(struct omap_lcd_panel_s));
+
+    s->irq = irq;
+    s->dma = dma;
+    s->base = base;
+    s->state = ds;
+    s->imif_base = imif_base;
+    s->emiff_base = emiff_base;
+    omap_lcdc_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, omap_lcdc_readfn,
+                    omap_lcdc_writefn, s);
+    cpu_register_physical_memory(s->base, 0x100, iomemtype);
+
+    graphic_console_init(ds, omap_update_display,
+                    omap_invalidate_display, omap_screen_dump, s);
+
+    return s;
+}
diff --git a/hw/omap_mmc.c b/hw/omap_mmc.c
new file mode 100644
index 0000000..aa77660
--- /dev/null
+++ b/hw/omap_mmc.c
@@ -0,0 +1,531 @@
+/*
+ * OMAP on-chip MMC/SD host emulation.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "vl.h"
+#include "sd.h"
+
+struct omap_mmc_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    qemu_irq *dma;
+    omap_clk clk;
+    SDState *card;
+    uint16_t last_cmd;
+    uint16_t sdio;
+    uint16_t rsp[8];
+    uint32_t arg;
+    int dw;
+    int mode;
+    int enable;
+    uint16_t status;
+    uint16_t mask;
+    uint8_t cto;
+    uint16_t dto;
+    uint16_t fifo[32];
+    int fifo_start;
+    int fifo_len;
+    uint16_t blen;
+    uint16_t blen_counter;
+    uint16_t nblk;
+    uint16_t nblk_counter;
+    int tx_dma;
+    int rx_dma;
+    int af_level;
+    int ae_level;
+
+    int ddir;
+    int transfer;
+};
+
+static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
+{
+    qemu_set_irq(s->irq, !!(s->status & s->mask));
+}
+
+static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
+{
+    if (!host->transfer && !host->fifo_len) {
+        host->status &= 0xf3ff;
+        return;
+    }
+
+    if (host->fifo_len > host->af_level && host->ddir) {
+        if (host->rx_dma) {
+            host->status &= 0xfbff;
+            qemu_irq_raise(host->dma[1]);
+        } else
+            host->status |= 0x0400;
+    } else {
+        host->status &= 0xfbff;
+        qemu_irq_lower(host->dma[1]);
+    }
+
+    if (host->fifo_len < host->ae_level && !host->ddir) {
+        if (host->tx_dma) {
+            host->status &= 0xf7ff;
+            qemu_irq_raise(host->dma[0]);
+        } else
+            host->status |= 0x0800;
+    } else {
+        qemu_irq_lower(host->dma[0]);
+        host->status &= 0xf7ff;
+    }
+}
+
+typedef enum {
+    sd_nore = 0,	/* no response */
+    sd_r1,		/* normal response command */
+    sd_r2,		/* CID, CSD registers */
+    sd_r3,		/* OCR register */
+    sd_r6 = 6,		/* Published RCA response */
+    sd_r1b = -1,
+} sd_rsp_type_t;
+
+static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
+                sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
+{
+    uint32_t rspstatus, mask;
+    int rsplen, timeout;
+    struct sd_request_s request;
+    uint8_t response[16];
+
+    if (resptype == sd_r1 && busy)
+        resptype = sd_r1b;
+
+    if (type == sd_adtc) {
+        host->fifo_start = 0;
+        host->fifo_len = 0;
+        host->transfer = 1;
+        host->ddir = dir;
+    } else
+        host->transfer = 0;
+    timeout = 0;
+    mask = 0;
+    rspstatus = 0;
+
+    request.cmd = cmd;
+    request.arg = host->arg;
+    request.crc = 0; /* FIXME */
+
+    rsplen = sd_do_command(host->card, &request, response);
+
+    /* TODO: validate CRCs */
+    switch (resptype) {
+    case sd_nore:
+        rsplen = 0;
+        break;
+
+    case sd_r1:
+    case sd_r1b:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
+                ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
+                LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
+                CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
+                CID_CSD_OVERWRITE;
+        if (host->sdio & (1 << 13))
+            mask |= AKE_SEQ_ERROR;
+        rspstatus = (response[0] << 24) | (response[1] << 16) |
+                (response[2] << 8) | (response[3] << 0);
+        break;
+
+    case sd_r2:
+        if (rsplen < 16) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 16;
+        break;
+
+    case sd_r3:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        rspstatus = (response[0] << 24) | (response[1] << 16) |
+                (response[2] << 8) | (response[3] << 0);
+        if (rspstatus & 0x80000000)
+            host->status &= 0xe000;
+        else
+            host->status |= 0x1000;
+        break;
+
+    case sd_r6:
+        if (rsplen < 4) {
+            timeout = 1;
+            break;
+        }
+        rsplen = 4;
+
+        mask = 0xe000 | AKE_SEQ_ERROR;
+        rspstatus = (response[2] << 8) | (response[3] << 0);
+    }
+
+    if (rspstatus & mask)
+        host->status |= 0x4000;
+    else
+        host->status &= 0xb000;
+
+    if (rsplen)
+        for (rsplen = 0; rsplen < 8; rsplen ++)
+            host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] |
+                    (response[(rsplen << 1) | 0] << 8);
+
+    if (timeout)
+        host->status |= 0x0080;
+    else if (cmd == 12)
+        host->status |= 0x0005;	/* Makes it more real */
+    else
+        host->status |= 0x0001;
+}
+
+static void omap_mmc_transfer(struct omap_mmc_s *host)
+{
+    uint8_t value;
+
+    if (!host->transfer)
+        return;
+
+    while (1) {
+        if (host->ddir) {
+            if (host->fifo_len > host->af_level)
+                break;
+
+            value = sd_read_data(host->card);
+            host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
+            if (-- host->blen_counter) {
+                value = sd_read_data(host->card);
+                host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
+                        value << 8;
+                host->blen_counter --;
+            }
+
+            host->fifo_len ++;
+        } else {
+            if (!host->fifo_len)
+                break;
+
+            value = host->fifo[host->fifo_start] & 0xff;
+            sd_write_data(host->card, value);
+            if (-- host->blen_counter) {
+                value = host->fifo[host->fifo_start] >> 8;
+                sd_write_data(host->card, value);
+                host->blen_counter --;
+            }
+
+            host->fifo_start ++;
+            host->fifo_len --;
+            host->fifo_start &= 31;
+        }
+
+        if (host->blen_counter == 0) {
+            host->nblk_counter --;
+            host->blen_counter = host->blen;
+
+            if (host->nblk_counter == 0) {
+                host->nblk_counter = host->nblk;
+                host->transfer = 0;
+                host->status |= 0x0008;
+                break;
+            }
+        }
+    }
+}
+
+static void omap_mmc_update(void *opaque)
+{
+    struct omap_mmc_s *s = opaque;
+    omap_mmc_transfer(s);
+    omap_mmc_fifolevel_update(s);
+    omap_mmc_interrupts_update(s);
+}
+
+static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
+{
+    uint16_t i;
+    struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case 0x00:	/* MMC_CMD */
+        return s->last_cmd;
+
+    case 0x04:	/* MMC_ARGL */
+        return s->arg & 0x0000ffff;
+
+    case 0x08:	/* MMC_ARGH */
+        return s->arg >> 16;
+
+    case 0x0c:	/* MMC_CON */
+        return (s->dw << 15) | (s->mode << 12) | (s->enable << 11);
+
+    case 0x10:	/* MMC_STAT */
+        return s->status;
+
+    case 0x14:	/* MMC_IE */
+        return s->mask;
+
+    case 0x18:	/* MMC_CTO */
+        return s->cto;
+
+    case 0x1c:	/* MMC_DTO */
+        return s->dto;
+
+    case 0x20:	/* MMC_DATA */
+        /* TODO: support 8-bit access */
+        i = s->fifo[s->fifo_start];
+        if (s->fifo_len == 0) {
+            printf("MMC: FIFO underrun\n");
+            return i;
+        }
+        s->fifo_start ++;
+        s->fifo_len --;
+        s->fifo_start &= 31;
+        omap_mmc_transfer(s);
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        return i;
+
+    case 0x24:	/* MMC_BLEN */
+        return s->blen_counter;
+
+    case 0x28:	/* MMC_NBLK */
+        return s->nblk_counter;
+
+    case 0x2c:	/* MMC_BUF */
+        return (s->rx_dma << 15) | (s->af_level << 8) |
+            (s->tx_dma << 7) | s->ae_level;
+
+    case 0x30:	/* MMC_SPI */
+        return 0x0000;
+    case 0x34:	/* MMC_SDIO */
+        return s->sdio;
+    case 0x38:	/* MMC_SYST */
+        return 0x0000;
+
+    case 0x3c:	/* MMC_REV */
+        return 0x0001;
+
+    case 0x40:	/* MMC_RSP0 */
+    case 0x44:	/* MMC_RSP1 */
+    case 0x48:	/* MMC_RSP2 */
+    case 0x4c:	/* MMC_RSP3 */
+    case 0x50:	/* MMC_RSP4 */
+    case 0x54:	/* MMC_RSP5 */
+    case 0x58:	/* MMC_RSP6 */
+    case 0x5c:	/* MMC_RSP7 */
+        return s->rsp[(offset - 0x40) >> 2];
+    }
+
+    OMAP_BAD_REG(offset);
+    return 0;
+}
+
+static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    int i;
+    struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case 0x00:	/* MMC_CMD */
+        if (!s->enable)
+            break;
+
+        s->last_cmd = value;
+        for (i = 0; i < 8; i ++)
+            s->rsp[i] = 0x0000;
+        omap_mmc_command(s, value & 63, (value >> 15) & 1,
+                (sd_cmd_type_t) ((value >> 12) & 3),
+                (value >> 11) & 1,
+                (sd_rsp_type_t) ((value >> 8) & 7),
+                (value >> 7) & 1);
+        omap_mmc_update(s);
+        break;
+
+    case 0x04:	/* MMC_ARGL */
+        s->arg &= 0xffff0000;
+        s->arg |= 0x0000ffff & value;
+        break;
+
+    case 0x08:	/* MMC_ARGH */
+        s->arg &= 0x0000ffff;
+        s->arg |= value << 16;
+        break;
+
+    case 0x0c:	/* MMC_CON */
+        s->dw = (value >> 15) & 1;
+        s->mode = (value >> 12) & 3;
+        s->enable = (value >> 11) & 1;
+        if (s->mode != 0)
+            printf("SD mode %i unimplemented!\n", s->mode);
+        if (s->dw != 0)
+            printf("4-bit SD bus enabled\n");
+        break;
+
+    case 0x10:	/* MMC_STAT */
+        s->status &= ~value;
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x14:	/* MMC_IE */
+        s->mask = value;
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x18:	/* MMC_CTO */
+        s->cto = value & 0xff;
+        if (s->cto > 0xfd)
+            printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
+        break;
+
+    case 0x1c:	/* MMC_DTO */
+        s->dto = value & 0xffff;
+        break;
+
+    case 0x20:	/* MMC_DATA */
+        /* TODO: support 8-bit access */
+        if (s->fifo_len == 32)
+            break;
+        s->fifo[(s->fifo_start + s->fifo_len) & 31] = value;
+        s->fifo_len ++;
+        omap_mmc_transfer(s);
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        break;
+
+    case 0x24:	/* MMC_BLEN */
+        s->blen = (value & 0x07ff) + 1;
+        s->blen_counter = s->blen;
+        break;
+
+    case 0x28:	/* MMC_NBLK */
+        s->nblk = (value & 0x07ff) + 1;
+        s->nblk_counter = s->nblk;
+        s->blen_counter = s->blen;
+        break;
+
+    case 0x2c:	/* MMC_BUF */
+        s->rx_dma = (value >> 15) & 1;
+        s->af_level = (value >> 8) & 0x1f;
+        s->tx_dma = (value >> 7) & 1;
+        s->ae_level = value & 0x1f;
+
+        if (s->rx_dma)
+            s->status &= 0xfbff;
+        if (s->tx_dma)
+            s->status &= 0xf7ff;
+        omap_mmc_fifolevel_update(s);
+        omap_mmc_interrupts_update(s);
+        break;
+
+    /* SPI, SDIO and TEST modes unimplemented */
+    case 0x30:	/* MMC_SPI */
+        break;
+    case 0x34:	/* MMC_SDIO */
+        s->sdio = value & 0x2020;
+        break;
+    case 0x38:	/* MMC_SYST */
+        break;
+
+    case 0x3c:	/* MMC_REV */
+    case 0x40:	/* MMC_RSP0 */
+    case 0x44:	/* MMC_RSP1 */
+    case 0x48:	/* MMC_RSP2 */
+    case 0x4c:	/* MMC_RSP3 */
+    case 0x50:	/* MMC_RSP4 */
+    case 0x54:	/* MMC_RSP5 */
+    case 0x58:	/* MMC_RSP6 */
+    case 0x5c:	/* MMC_RSP7 */
+        OMAP_RO_REG(offset);
+        break;
+
+    default:
+        OMAP_BAD_REG(offset);
+    }
+}
+
+static CPUReadMemoryFunc *omap_mmc_readfn[] = {
+    omap_badwidth_read16,
+    omap_mmc_read,
+    omap_badwidth_read16,
+};
+
+static CPUWriteMemoryFunc *omap_mmc_writefn[] = {
+    omap_badwidth_write16,
+    omap_mmc_write,
+    omap_badwidth_write16,
+};
+
+void omap_mmc_reset(struct omap_mmc_s *host)
+{
+    host->last_cmd = 0;
+    memset(host->rsp, 0, sizeof(host->rsp));
+    host->arg = 0;
+    host->dw = 0;
+    host->mode = 0;
+    host->enable = 0;
+    host->status = 0;
+    host->mask = 0;
+    host->cto = 0;
+    host->dto = 0;
+    host->fifo_len = 0;
+    host->blen = 0;
+    host->blen_counter = 0;
+    host->nblk = 0;
+    host->nblk_counter = 0;
+    host->tx_dma = 0;
+    host->rx_dma = 0;
+    host->ae_level = 0x00;
+    host->af_level = 0x1f;
+    host->transfer = 0;
+}
+
+struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
+                qemu_irq irq, qemu_irq dma[], omap_clk clk)
+{
+    int iomemtype;
+    struct omap_mmc_s *s = (struct omap_mmc_s *)
+            qemu_mallocz(sizeof(struct omap_mmc_s));
+
+    s->irq = irq;
+    s->base = base;
+    s->dma = dma;
+    s->clk = clk;
+
+    iomemtype = cpu_register_io_memory(0, omap_mmc_readfn,
+                    omap_mmc_writefn, s);
+    cpu_register_physical_memory(s->base, 0x800, iomemtype);
+
+    /* Instantiate the storage */
+    s->card = sd_init(sd_bdrv);
+
+    return s;
+}
+
+/* TODO: insertion and read-only handlers */
diff --git a/hw/openpic.c b/hw/openpic.c
index 3177337..54830c3 100644
--- a/hw/openpic.c
+++ b/hw/openpic.c
@@ -1,8 +1,8 @@
 /*
  * OpenPIC emulation
- * 
+ *
  * Copyright (c) 2004 Jocelyn Mayer
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -30,7 +30,7 @@
  * - Motorola Harrier programmer manuel
  *
  * Serial interrupts, as implemented in Raven chipset are not supported yet.
- * 
+ *
  */
 #include "vl.h"
 
@@ -159,10 +159,10 @@
     uint32_t pcsr; /* CPU sensitivity register */
     IRQ_queue_t raised;
     IRQ_queue_t servicing;
-    CPUState *env;
+    qemu_irq *irqs;
 } IRQ_dst_t;
 
-struct openpic_t {
+typedef struct openpic_t {
     PCIDevice pci_dev;
     int mem_index;
     /* Global registers */
@@ -170,6 +170,7 @@
     uint32_t glbc; /* Global configuration register  */
     uint32_t micr; /* MPIC interrupt configuration register */
     uint32_t veni; /* Vendor identification register */
+    uint32_t pint; /* Processor initialization register */
     uint32_t spve; /* Spurious vector register */
     uint32_t tifr; /* Timer frequency reporting register */
     /* Source registers */
@@ -195,7 +196,9 @@
 	uint32_t mbr;    /* Mailbox register */
     } mailboxes[MAX_MAILBOXES];
 #endif
-};
+    /* IRQ out is used when in bypass mode (not implemented) */
+    qemu_irq irq_out;
+} openpic_t;
 
 static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
 {
@@ -221,7 +224,7 @@
     priority = -1;
     for (i = 0; i < MAX_IRQ; i++) {
 	if (IRQ_testbit(q, i)) {
-            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", 
+            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
                     i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
 	    if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
 		next = i;
@@ -254,19 +257,34 @@
     priority = IPVP_PRIORITY(src->ipvp);
     if (priority <= dst->pctp) {
 	/* Too low priority */
+        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
+                __func__, n_IRQ, n_CPU);
 	return;
     }
     if (IRQ_testbit(&dst->raised, n_IRQ)) {
 	/* Interrupt miss */
+        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
+                __func__, n_IRQ, n_CPU);
 	return;
     }
     set_bit(&src->ipvp, IPVP_ACTIVITY);
     IRQ_setbit(&dst->raised, n_IRQ);
-    if (priority > dst->raised.priority) {
-        IRQ_get_next(opp, &dst->raised);
-        DPRINTF("Raise CPU IRQ\n");
-        cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
+    if (priority < dst->raised.priority) {
+        /* An higher priority IRQ is already raised */
+        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
+                __func__, n_IRQ, dst->raised.next, n_CPU);
+        return;
     }
+    IRQ_get_next(opp, &dst->raised);
+    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
+        priority < dst->servicing.priority) {
+        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+                __func__, n_IRQ, dst->servicing.next, n_CPU);
+        /* Already servicing a higher priority IRQ */
+        return;
+    }
+    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
+    qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
 }
 
 /* update pic state because registers for n_IRQ have changed value */
@@ -279,27 +297,34 @@
 
     if (!src->pending) {
         /* no irq pending */
+        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
         return;
     }
     if (test_bit(&src->ipvp, IPVP_MASK)) {
 	/* Interrupt source is disabled */
+        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
 	return;
     }
     if (IPVP_PRIORITY(src->ipvp) == 0) {
 	/* Priority set to zero */
+        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
 	return;
     }
     if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
         /* IRQ already active */
+        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
         return;
     }
     if (src->ide == 0x00000000) {
 	/* No target */
+        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
 	return;
     }
 
-    if (!test_bit(&src->ipvp, IPVP_MODE) ||
-        src->ide == (1 << src->last_cpu)) {
+    if (src->ide == (1 << src->last_cpu)) {
+        /* Only one CPU is allowed to receive this IRQ */
+        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
+    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
         /* Directed delivery mode */
         for (i = 0; i < opp->nb_cpus; i++) {
             if (test_bit(&src->ide, i))
@@ -307,9 +332,8 @@
         }
     } else {
         /* Distributed delivery mode */
-        /* XXX: incorrect code */
-        for (i = src->last_cpu; i < src->last_cpu; i++) {
-            if (i == MAX_IRQ)
+        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
+            if (i == opp->nb_cpus)
                 i = 0;
             if (test_bit(&src->ide, i)) {
                 IRQ_local_pipe(opp, i, n_IRQ);
@@ -320,13 +344,13 @@
     }
 }
 
-void openpic_set_irq(void *opaque, int n_IRQ, int level)
+static void openpic_set_irq(void *opaque, int n_IRQ, int level)
 {
     openpic_t *opp = opaque;
     IRQ_src_t *src;
 
     src = &opp->src[n_IRQ];
-    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", 
+    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
             n_IRQ, level, src->ipvp);
     if (test_bit(&src->ipvp, IPVP_SENSE)) {
         /* level-sensitive irq */
@@ -349,6 +373,7 @@
     /* Initialise controller registers */
     opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
     opp->veni = VENI;
+    opp->pint = 0x00000000;
     opp->spve = 0x000000FF;
     opp->tifr = 0x003F7A00;
     /* ? */
@@ -359,7 +384,7 @@
 	opp->src[i].ide  = 0x00000000;
     }
     /* Initialise IRQ destinations */
-    for (i = 0; i < opp->nb_cpus; i++) {
+    for (i = 0; i < MAX_CPU; i++) {
 	opp->dst[i].pctp      = 0x0000000F;
 	opp->dst[i].pcsr      = 0x00000000;
 	memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
@@ -413,11 +438,11 @@
         /* NOTE: not fully accurate for special IRQs, but simple and
            sufficient */
         /* ACTIVITY bit is read-only */
-	opp->src[n_IRQ].ipvp = 
+	opp->src[n_IRQ].ipvp =
             (opp->src[n_IRQ].ipvp & 0x40000000) |
             (val & 0x800F00FF);
         openpic_update_irq(opp, n_IRQ);
-        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", 
+        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
                 n_IRQ, val, opp->src[n_IRQ].ipvp);
 	break;
     case IRQ_IDE:
@@ -450,7 +475,7 @@
 
     return retval;
 }
-     
+
 static void write_doorbell_register (penpic_t *opp, int n_dbl,
 				     uint32_t offset, uint32_t value)
 {
@@ -510,6 +535,8 @@
 static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
 {
     openpic_t *opp = opaque;
+    IRQ_dst_t *dst;
+    int idx;
 
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
@@ -529,11 +556,18 @@
     case 0x80: /* VENI */
 	break;
     case 0x90: /* PINT */
-        /* XXX: Should be able to reset any CPU */
-        if (val & 1) {
-            DPRINTF("Reset CPU IRQ\n");
-            //            cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
+        for (idx = 0; idx < opp->nb_cpus; idx++) {
+            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
+                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
+                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
+                dst = &opp->dst[idx];
+                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
+            }
         }
+        opp->pint = val;
 	break;
 #if MAX_IPI > 0
     case 0xA0: /* IPI_IPVP */
@@ -734,7 +768,7 @@
     openpic_t *opp = opaque;
     IRQ_src_t *src;
     IRQ_dst_t *dst;
-    int idx, n_IRQ;
+    int idx, s_IRQ, n_IRQ;
 
     DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
     if (addr & 0xF)
@@ -769,21 +803,21 @@
 	break;
     case 0xB0: /* PEOI */
         DPRINTF("PEOI\n");
-	n_IRQ = IRQ_get_next(opp, &dst->servicing);
-	IRQ_resetbit(&dst->servicing, n_IRQ);
+	s_IRQ = IRQ_get_next(opp, &dst->servicing);
+	IRQ_resetbit(&dst->servicing, s_IRQ);
 	dst->servicing.next = -1;
-	src = &opp->src[n_IRQ];
 	/* Set up next servicing IRQ */
-	IRQ_get_next(opp, &dst->servicing);
-	/* Check queued interrupts. */
-	n_IRQ = IRQ_get_next(opp, &dst->raised);
-	if (n_IRQ != -1) {
-	    src = &opp->src[n_IRQ];
-	    if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
-                DPRINTF("Raise CPU IRQ\n");
-                cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
-            }
-	}
+	s_IRQ = IRQ_get_next(opp, &dst->servicing);
+        /* Check queued interrupts. */
+        n_IRQ = IRQ_get_next(opp, &dst->raised);
+        src = &opp->src[n_IRQ];
+        if (n_IRQ != -1 &&
+            (s_IRQ == -1 ||
+             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
+            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
+                    idx, n_IRQ);
+            qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
+        }
 	break;
     default:
         break;
@@ -797,7 +831,7 @@
     IRQ_dst_t *dst;
     uint32_t retval;
     int idx, n_IRQ;
-    
+
     DPRINTF("%s: addr %08x\n", __func__, addr);
     retval = 0xFFFFFFFF;
     if (addr & 0xF)
@@ -814,11 +848,13 @@
 	retval = idx;
 	break;
     case 0xA0: /* PIAC */
+        DPRINTF("Lower OpenPIC INT output\n");
+        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
 	n_IRQ = IRQ_get_next(opp, &dst->raised);
         DPRINTF("PIAC: irq=%d\n", n_IRQ);
 	if (n_IRQ == -1) {
 	    /* No more interrupt pending */
-            retval = opp->spve;
+            retval = IPVP_VECTOR(opp->spve);
 	} else {
 	    src = &opp->src[n_IRQ];
 	    if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
@@ -935,7 +971,7 @@
     &openpic_readl,
 };
 
-static void openpic_map(PCIDevice *pci_dev, int region_num, 
+static void openpic_map(PCIDevice *pci_dev, int region_num,
                         uint32_t addr, uint32_t size, int type)
 {
     openpic_t *opp;
@@ -963,13 +999,13 @@
 #endif
 }
 
-openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
-                         CPUPPCState **envp)
+qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out)
 {
     openpic_t *opp;
     uint8_t *pci_conf;
     int i, m;
-    
+
     /* XXX: for now, only one CPU is supported */
     if (nb_cpus != 1)
         return NULL;
@@ -987,17 +1023,16 @@
         pci_conf[0x0b] = 0x08;
         pci_conf[0x0e] = 0x00; // header_type
         pci_conf[0x3d] = 0x00; // no interrupt pin
-        
+
         /* Register I/O spaces */
         pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
                                PCI_ADDRESS_SPACE_MEM, &openpic_map);
     } else {
         opp = qemu_mallocz(sizeof(openpic_t));
     }
-
     opp->mem_index = cpu_register_io_memory(0, openpic_read,
                                             openpic_write, opp);
-    
+
     //    isu_base &= 0xFFFC0000;
     opp->nb_cpus = nb_cpus;
     /* Set IRQ types */
@@ -1019,9 +1054,11 @@
         opp->src[i].type = IRQ_INTERNAL;
     }
     for (i = 0; i < nb_cpus; i++)
-        opp->dst[i].env = envp[i];
+        opp->dst[i].irqs = irqs[i];
+    opp->irq_out = irq_out;
     openpic_reset(opp);
     if (pmem_index)
         *pmem_index = opp->mem_index;
-    return opp;
+
+    return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
 }
diff --git a/hw/palm.c b/hw/palm.c
new file mode 100644
index 0000000..623fcd6
--- /dev/null
+++ b/hw/palm.c
@@ -0,0 +1,140 @@
+/*
+ * PalmOne's (TM) PDAs.
+ *
+ * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include "vl.h"
+
+static uint32_t static_readb(void *opaque, target_phys_addr_t offset)
+{
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 3) << 3);
+}
+
+static uint32_t static_readh(void *opaque, target_phys_addr_t offset) {
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 1) << 3);
+}
+
+static uint32_t static_readw(void *opaque, target_phys_addr_t offset) {
+    uint32_t *val = (uint32_t *) opaque;
+    return *val >> ((offset & 0) << 3);
+}
+
+static void static_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value) {
+#ifdef SPY
+    printf("%s: value %08lx written at " PA_FMT "\n",
+                    __FUNCTION__, value, offset);
+#endif
+}
+
+static CPUReadMemoryFunc *static_readfn[] = {
+    static_readb,
+    static_readh,
+    static_readw,
+};
+
+static CPUWriteMemoryFunc *static_writefn[] = {
+    static_write,
+    static_write,
+    static_write,
+};
+
+/* Palm Tunsgten|E support */
+static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
+{
+}
+
+static void palmte_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)
+{
+    struct omap_mpu_state_s *cpu;
+    int flash_size = 0x00800000;
+    int sdram_size = 0x02000000;
+    int io;
+    static uint32_t cs0val = 0xffffffff;
+    static uint32_t cs1val = 0x0000e1a0;
+    static uint32_t cs2val = 0x0000e1a0;
+    static uint32_t cs3val = 0xe1a0e1a0;
+    ram_addr_t phys_flash;
+    int rom_size, rom_loaded = 0;
+
+    if (ram_size < flash_size + sdram_size + OMAP15XX_SRAM_SIZE) {
+        fprintf(stderr, "This architecture uses %i bytes of memory\n",
+                        flash_size + sdram_size + OMAP15XX_SRAM_SIZE);
+        exit(1);
+    }
+
+    cpu = omap310_mpu_init(sdram_size, ds, cpu_model);
+
+    /* External Flash (EMIFS) */
+    cpu_register_physical_memory(OMAP_CS0_BASE, flash_size,
+                    (phys_flash = qemu_ram_alloc(flash_size)) | IO_MEM_ROM);
+
+    io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs0val);
+    cpu_register_physical_memory(OMAP_CS0_BASE + flash_size,
+                    OMAP_CS0_SIZE - flash_size, io);
+    io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs1val);
+    cpu_register_physical_memory(OMAP_CS1_BASE, OMAP_CS1_SIZE, io);
+    io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs2val);
+    cpu_register_physical_memory(OMAP_CS2_BASE, OMAP_CS2_SIZE, io);
+    io = cpu_register_io_memory(0, static_readfn, static_writefn, &cs3val);
+    cpu_register_physical_memory(OMAP_CS3_BASE, OMAP_CS3_SIZE, io);
+
+    palmte_microwire_setup(cpu);
+
+    /* Setup initial (reset) machine state */
+    if (nb_option_roms) {
+        rom_size = get_image_size(option_rom[0]);
+        if (rom_size > flash_size)
+            fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
+                            __FUNCTION__, rom_size, flash_size);
+        else if (rom_size > 0 && load_image(option_rom[0],
+                                phys_ram_base + phys_flash) > 0) {
+            rom_loaded = 1;
+            cpu->env->regs[15] = 0x00000000;
+        } else
+            fprintf(stderr, "%s: error loading '%s'\n",
+                            __FUNCTION__, option_rom[0]);
+    }
+
+    if (!rom_loaded && !kernel_filename) {
+        fprintf(stderr, "Kernel or ROM image must be specified\n");
+        exit(1);
+    }
+
+    /* Load the kernel.  */
+    if (kernel_filename) {
+        /* Start at bootloader.  */
+        cpu->env->regs[15] = OMAP_EMIFF_BASE;
+
+        arm_load_kernel(cpu->env, sdram_size, kernel_filename, kernel_cmdline,
+                        initrd_filename, 0x331, OMAP_EMIFF_BASE);
+    }
+
+    dpy_resize(ds, 320, 320);
+}
+
+QEMUMachine palmte_machine = {
+    "cheetah",
+    "Palm Tungsten|E aka. Cheetah PDA (OMAP310)",
+    palmte_init,
+};
diff --git a/hw/parallel.c b/hw/parallel.c
index cba9561..bda3f3a 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -1,8 +1,9 @@
 /*
  * QEMU Parallel PORT emulation
- * 
+ *
  * Copyright (c) 2003-2005 Fabrice Bellard
- * 
+ * Copyright (c) 2007 Marko Kohtala
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -25,6 +26,18 @@
 
 //#define DEBUG_PARALLEL
 
+#ifdef DEBUG_PARALLEL
+#define pdebug(fmt, arg...) printf("pp: " fmt, ##arg)
+#else
+#define pdebug(fmt, arg...) ((void)0)
+#endif
+
+#define PARA_REG_DATA 0
+#define PARA_REG_STS 1
+#define PARA_REG_CTR 2
+#define PARA_REG_EPP_ADDR 3
+#define PARA_REG_EPP_DATA 4
+
 /*
  * These are the definitions for the Printer Status Register
  */
@@ -33,129 +46,383 @@
 #define PARA_STS_PAPER	0x20	/* Out of paper */
 #define PARA_STS_ONLINE	0x10	/* Online */
 #define PARA_STS_ERROR	0x08	/* Error complement */
+#define PARA_STS_TMOUT	0x01	/* EPP timeout */
 
 /*
  * These are the definitions for the Printer Control Register
  */
+#define PARA_CTR_DIR	0x20	/* Direction (1=read, 0=write) */
 #define PARA_CTR_INTEN	0x10	/* IRQ Enable */
 #define PARA_CTR_SELECT	0x08	/* Select In complement */
 #define PARA_CTR_INIT	0x04	/* Initialize Printer complement */
 #define PARA_CTR_AUTOLF	0x02	/* Auto linefeed complement */
 #define PARA_CTR_STROBE	0x01	/* Strobe complement */
 
+#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
+
 struct ParallelState {
-    uint8_t data;
-    uint8_t status; /* read only register */
+    uint8_t dataw;
+    uint8_t datar;
+    uint8_t status;
     uint8_t control;
-    int irq;
+    qemu_irq irq;
     int irq_pending;
     CharDriverState *chr;
     int hw_driver;
+    int epp_timeout;
+    uint32_t last_read_offset; /* For debugging */
+    /* Memory-mapped interface */
+    target_phys_addr_t base;
+    int it_shift;
 };
 
 static void parallel_update_irq(ParallelState *s)
 {
     if (s->irq_pending)
-        pic_set_irq(s->irq, 1);
+        qemu_irq_raise(s->irq);
     else
-        pic_set_irq(s->irq, 0);
+        qemu_irq_lower(s->irq);
 }
 
-static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void
+parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
 {
     ParallelState *s = opaque;
-    
+
+    pdebug("write addr=0x%02x val=0x%02x\n", addr, val);
+
     addr &= 7;
-#ifdef DEBUG_PARALLEL
-    printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
     switch(addr) {
-    case 0:
-        if (s->hw_driver) {
-            s->data = val;
-            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data);
-        } else {
-            s->data = val;
-            parallel_update_irq(s);
-        }
+    case PARA_REG_DATA:
+        s->dataw = val;
+        parallel_update_irq(s);
         break;
-    case 2:
-        if (s->hw_driver) {
-            s->control = val;
-            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control);
-        } else {
-            if ((val & PARA_CTR_INIT) == 0 ) {
-                s->status = PARA_STS_BUSY;
-                s->status |= PARA_STS_ACK;
-                s->status |= PARA_STS_ONLINE;
-                s->status |= PARA_STS_ERROR;
-            }
-            else if (val & PARA_CTR_SELECT) {
-                if (val & PARA_CTR_STROBE) {
-                    s->status &= ~PARA_STS_BUSY;
-                    if ((s->control & PARA_CTR_STROBE) == 0)
-                        qemu_chr_write(s->chr, &s->data, 1);
-                } else {
-                    if (s->control & PARA_CTR_INTEN) {
-                        s->irq_pending = 1;
-                    }
+    case PARA_REG_CTR:
+        if ((val & PARA_CTR_INIT) == 0 ) {
+            s->status = PARA_STS_BUSY;
+            s->status |= PARA_STS_ACK;
+            s->status |= PARA_STS_ONLINE;
+            s->status |= PARA_STS_ERROR;
+        }
+        else if (val & PARA_CTR_SELECT) {
+            if (val & PARA_CTR_STROBE) {
+                s->status &= ~PARA_STS_BUSY;
+                if ((s->control & PARA_CTR_STROBE) == 0)
+                    qemu_chr_write(s->chr, &s->dataw, 1);
+            } else {
+                if (s->control & PARA_CTR_INTEN) {
+                    s->irq_pending = 1;
                 }
             }
-            parallel_update_irq(s);
-            s->control = val;
+        }
+        parallel_update_irq(s);
+        s->control = val;
+        break;
+    }
+}
+
+static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint8_t parm = val;
+
+    /* Sometimes programs do several writes for timing purposes on old
+       HW. Take care not to waste time on writes that do nothing. */
+
+    s->last_read_offset = ~0U;
+
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        if (s->dataw == val)
+            return;
+        pdebug("wd%02x\n", val);
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
+        s->dataw = val;
+        break;
+    case PARA_REG_STS:
+        pdebug("ws%02x\n", val);
+        if (val & PARA_STS_TMOUT)
+            s->epp_timeout = 0;
+        break;
+    case PARA_REG_CTR:
+        val |= 0xc0;
+        if (s->control == val)
+            return;
+        pdebug("wc%02x\n", val);
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
+        s->control = val;
+        break;
+    case PARA_REG_EPP_ADDR:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
+            /* Controls not correct for EPP address cycle, so do nothing */
+            pdebug("wa%02x s\n", val);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
+            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("wa%02x t\n", val);
+            }
+            else
+                pdebug("wa%02x\n", val);
+        }
+        break;
+    case PARA_REG_EPP_DATA:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
+            /* Controls not correct for EPP data cycle, so do nothing */
+            pdebug("we%02x s\n", val);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
+            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("we%02x t\n", val);
+            }
+            else
+                pdebug("we%02x\n", val);
         }
         break;
     }
 }
 
-static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
+static void
+parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint16_t eppdata = cpu_to_le16(val);
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("we%04x s\n", val);
+        return;
+    }
+    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("we%04x t\n", val);
+    }
+    else
+        pdebug("we%04x\n", val);
+}
+
+static void
+parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
+{
+    ParallelState *s = opaque;
+    uint32_t eppdata = cpu_to_le32(val);
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("we%08x s\n", val);
+        return;
+    }
+    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("we%08x t\n", val);
+    }
+    else
+        pdebug("we%08x\n", val);
+}
+
+static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr)
 {
     ParallelState *s = opaque;
     uint32_t ret = 0xff;
 
     addr &= 7;
     switch(addr) {
-    case 0:
-        if (s->hw_driver) {
-            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data);
-        } 
-        ret = s->data; 
+    case PARA_REG_DATA:
+        if (s->control & PARA_CTR_DIR)
+            ret = s->datar;
+        else
+            ret = s->dataw;
         break;
-    case 1:
-        if (s->hw_driver) {
-            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status);
-            ret = s->status; 
-        } else {
-            ret = s->status;
-            s->irq_pending = 0;
-            if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
+    case PARA_REG_STS:
+        ret = s->status;
+        s->irq_pending = 0;
+        if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
+            /* XXX Fixme: wait 5 microseconds */
+            if (s->status & PARA_STS_ACK)
+                s->status &= ~PARA_STS_ACK;
+            else {
                 /* XXX Fixme: wait 5 microseconds */
-                if (s->status & PARA_STS_ACK)
-                    s->status &= ~PARA_STS_ACK;
-                else {
-                    /* XXX Fixme: wait 5 microseconds */
-                    s->status |= PARA_STS_ACK;
-                    s->status |= PARA_STS_BUSY;
-                }
+                s->status |= PARA_STS_ACK;
+                s->status |= PARA_STS_BUSY;
             }
-            parallel_update_irq(s);
         }
+        parallel_update_irq(s);
         break;
-    case 2:
-        if (s->hw_driver) {
-            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control);
-        }
+    case PARA_REG_CTR:
         ret = s->control;
         break;
     }
-#ifdef DEBUG_PARALLEL
-    printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
+    pdebug("read addr=0x%02x val=0x%02x\n", addr, ret);
     return ret;
 }
 
+static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint8_t ret = 0xff;
+    addr &= 7;
+    switch(addr) {
+    case PARA_REG_DATA:
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
+        if (s->last_read_offset != addr || s->datar != ret)
+            pdebug("rd%02x\n", ret);
+        s->datar = ret;
+        break;
+    case PARA_REG_STS:
+        qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
+        ret &= ~PARA_STS_TMOUT;
+        if (s->epp_timeout)
+            ret |= PARA_STS_TMOUT;
+        if (s->last_read_offset != addr || s->status != ret)
+            pdebug("rs%02x\n", ret);
+        s->status = ret;
+        break;
+    case PARA_REG_CTR:
+        /* s->control has some bits fixed to 1. It is zero only when
+           it has not been yet written to.  */
+        if (s->control == 0) {
+            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
+            if (s->last_read_offset != addr)
+                pdebug("rc%02x\n", ret);
+            s->control = ret;
+        }
+        else {
+            ret = s->control;
+            if (s->last_read_offset != addr)
+                pdebug("rc%02x\n", ret);
+        }
+        break;
+    case PARA_REG_EPP_ADDR:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+            /* Controls not correct for EPP addr cycle, so do nothing */
+            pdebug("ra%02x s\n", ret);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
+            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("ra%02x t\n", ret);
+            }
+            else
+                pdebug("ra%02x\n", ret);
+        }
+        break;
+    case PARA_REG_EPP_DATA:
+        if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+            /* Controls not correct for EPP data cycle, so do nothing */
+            pdebug("re%02x s\n", ret);
+        else {
+            struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
+            if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
+                s->epp_timeout = 1;
+                pdebug("re%02x t\n", ret);
+            }
+            else
+                pdebug("re%02x\n", ret);
+        }
+        break;
+    }
+    s->last_read_offset = addr;
+    return ret;
+}
+
+static uint32_t
+parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint32_t ret;
+    uint16_t eppdata = ~0;
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("re%04x s\n", eppdata);
+        return eppdata;
+    }
+    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    ret = le16_to_cpu(eppdata);
+
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("re%04x t\n", ret);
+    }
+    else
+        pdebug("re%04x\n", ret);
+    return ret;
+}
+
+static uint32_t
+parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
+{
+    ParallelState *s = opaque;
+    uint32_t ret;
+    uint32_t eppdata = ~0U;
+    int err;
+    struct ParallelIOArg ioarg = {
+        .buffer = &eppdata, .count = sizeof(eppdata)
+    };
+    if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
+        /* Controls not correct for EPP data cycle, so do nothing */
+        pdebug("re%08x s\n", eppdata);
+        return eppdata;
+    }
+    err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+    ret = le32_to_cpu(eppdata);
+
+    if (err) {
+        s->epp_timeout = 1;
+        pdebug("re%08x t\n", ret);
+    }
+    else
+        pdebug("re%08x\n", ret);
+    return ret;
+}
+
+static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val)
+{
+    addr &= 7;
+    pdebug("wecp%d=%02x\n", addr, val);
+}
+
+static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr)
+{
+    uint8_t ret = 0xff;
+    addr &= 7;
+    pdebug("recp%d:%02x\n", addr, ret);
+    return ret;
+}
+
+static void parallel_reset(ParallelState *s, qemu_irq irq, CharDriverState *chr)
+{
+    s->datar = ~0;
+    s->dataw = ~0;
+    s->status = PARA_STS_BUSY;
+    s->status |= PARA_STS_ACK;
+    s->status |= PARA_STS_ONLINE;
+    s->status |= PARA_STS_ERROR;
+    s->control = PARA_CTR_SELECT;
+    s->control |= PARA_CTR_INIT;
+    s->irq = irq;
+    s->irq_pending = 0;
+    s->chr = chr;
+    s->hw_driver = 0;
+    s->epp_timeout = 0;
+    s->last_read_offset = ~0U;
+}
+
 /* If fd is zero, it means that the parallel device uses the console */
-ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
+ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr)
 {
     ParallelState *s;
     uint8_t dummy;
@@ -163,21 +430,102 @@
     s = qemu_mallocz(sizeof(ParallelState));
     if (!s)
         return NULL;
-    s->chr = chr;
-    s->hw_driver = 0;
-    if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0)
+    parallel_reset(s, irq, chr);
+
+    if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
         s->hw_driver = 1;
+        s->status = dummy;
+    }
 
-    s->irq = irq;
-    s->data = 0;
-    s->status = PARA_STS_BUSY;
-    s->status |= PARA_STS_ACK;
-    s->status |= PARA_STS_ONLINE;
-    s->status |= PARA_STS_ERROR;
-    s->control = PARA_CTR_SELECT;
-    s->control |= PARA_CTR_INIT;
+    if (s->hw_driver) {
+        register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s);
+        register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s);
+        register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s);
+        register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s);
+        register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s);
+        register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s);
+        register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s);
+        register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s);
+    }
+    else {
+        register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s);
+        register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s);
+    }
+    return s;
+}
 
-    register_ioport_write(base, 8, 1, parallel_ioport_write, s);
-    register_ioport_read(base, 8, 1, parallel_ioport_read, s);
+/* Memory mapped interface */
+uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift) & 0xFF;
+}
+
+void parallel_mm_writeb (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, (addr - s->base) >> s->it_shift, value & 0xFF);
+}
+
+uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
+}
+
+void parallel_mm_writew (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
+}
+
+uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+    ParallelState *s = opaque;
+
+    return parallel_ioport_read_sw(s, (addr - s->base) >> s->it_shift);
+}
+
+void parallel_mm_writel (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
+{
+    ParallelState *s = opaque;
+
+    parallel_ioport_write_sw(s, (addr - s->base) >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc *parallel_mm_read_sw[] = {
+    &parallel_mm_readb,
+    &parallel_mm_readw,
+    &parallel_mm_readl,
+};
+
+static CPUWriteMemoryFunc *parallel_mm_write_sw[] = {
+    &parallel_mm_writeb,
+    &parallel_mm_writew,
+    &parallel_mm_writel,
+};
+
+/* If fd is zero, it means that the parallel device uses the console */
+ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr)
+{
+    ParallelState *s;
+    int io_sw;
+
+    s = qemu_mallocz(sizeof(ParallelState));
+    if (!s)
+        return NULL;
+    parallel_reset(s, irq, chr);
+    s->base = base;
+    s->it_shift = it_shift;
+
+    io_sw = cpu_register_io_memory(0, parallel_mm_read_sw, parallel_mm_write_sw, s);
+    cpu_register_physical_memory(base, 8 << it_shift, io_sw);
     return s;
 }
diff --git a/hw/pc.c b/hw/pc.c
index bd33f3d..4d0bb93 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1,8 +1,8 @@
 /*
  * QEMU PC System Emulator
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -33,12 +33,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
 
@@ -53,15 +48,16 @@
 }
 
 /* MSDOS compatibility mode FPU exception support */
+static qemu_irq ferr_irq;
 /* XXX: add IGNNE support */
 void cpu_set_ferr(CPUX86State *s)
 {
-    pic_set_irq(13, 1);
+    qemu_irq_raise(ferr_irq);
 }
 
 static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
 {
-    pic_set_irq(13, 0);
+    qemu_irq_lower(ferr_irq);
 }
 
 /* TSC handling */
@@ -73,7 +69,7 @@
 #if USE_KQEMU
     if (env->kqemu_enabled) {
         return cpu_get_real_ticks();
-    } else 
+    } else
 #endif
     {
         return cpu_get_ticks();
@@ -97,7 +93,7 @@
     if (intno >= 0) {
         /* set irq request if a PIC irq is still pending */
         /* XXX: improve that */
-        pic_update_irq(isa_pic); 
+        pic_update_irq(isa_pic);
         return intno;
     }
     /* read the irq from the PIC */
@@ -108,7 +104,7 @@
     return intno;
 }
 
-static void pic_irq_request(void *opaque, int level)
+static void pic_irq_request(void *opaque, int irq, int level)
 {
     CPUState *env = opaque;
     if (level && apic_accept_pic_intr(env))
@@ -143,7 +139,7 @@
     return val;
 }
 
-static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd) 
+static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
 {
     RTCState *s = rtc_state;
     int cylinders, heads, sectors;
@@ -198,7 +194,7 @@
         val = 65535;
     rtc_set_memory(s, 0x34, val);
     rtc_set_memory(s, 0x35, val >> 8);
-    
+
     switch(boot_device) {
     case 'a':
     case 'b':
@@ -214,7 +210,7 @@
         rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */
         break;
     case 'n':
-        rtc_set_memory(s, 0x3d, 0x04); /* Expansion ROM boot */
+        rtc_set_memory(s, 0x3d, 0x04); /* Network boot */
         break;
     }
 
@@ -225,7 +221,7 @@
 
     val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
     rtc_set_memory(s, 0x10, val);
-    
+
     val = 0;
     nb = 0;
     if (fd0 < 3)
@@ -251,7 +247,7 @@
     rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
     if (hd_table[0])
         cmos_init_hd(0x19, 0x1b, hd_table[0]);
-    if (hd_table[1]) 
+    if (hd_table[1])
         cmos_init_hd(0x1a, 0x24, hd_table[1]);
 
     val = 0;
@@ -310,7 +306,7 @@
 {
     static const char shutdown_str[8] = "Shutdown";
     static int shutdown_index = 0;
-    
+
     switch(addr) {
         /* Bochs BIOS messages */
     case 0x400:
@@ -364,8 +360,63 @@
     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;
 
-int load_kernel(const char *filename, uint8_t *addr, 
+    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)
 {
     int fd, size;
@@ -381,10 +432,10 @@
     setup_sects = real_addr[0x1F1];
     if (!setup_sects)
         setup_sects = 4;
-    if (read(fd, real_addr + 512, setup_sects * 512) != 
+    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)
@@ -396,6 +447,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;
@@ -418,7 +632,7 @@
 static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
 
 #ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus)
+static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
 {
     struct soundhw *c;
     int audio_enabled = 0;
@@ -435,7 +649,7 @@
             for (c = soundhw; c->name; ++c) {
                 if (c->enabled) {
                     if (c->isa) {
-                        c->init.init_isa (s);
+                        c->init.init_isa (s, pic);
                     }
                     else {
                         if (pci_bus) {
@@ -449,13 +663,13 @@
 }
 #endif
 
-static void pc_init_ne2k_isa(NICInfo *nd)
+static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
 {
     static int nb_ne2k = 0;
 
     if (nb_ne2k == NE2000_NB_MAX)
         return;
-    isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd);
+    isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
     nb_ne2k++;
 }
 
@@ -472,15 +686,16 @@
                      int pci_enabled)
 {
     char buf[1024];
-    int ret, linux_boot, initrd_size, i;
-    ram_addr_t bios_offset, vga_bios_offset, option_rom_offset,
-    above_4g_mem_size = 0;
-    ram_addr_t initrd_offset;
-    int bios_size, isa_bios_size;
+    int ret, linux_boot, i;
+    ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset;
+    ram_addr_t above_4g_mem_size = 0;
+    int bios_size, isa_bios_size, vga_bios_size;
     PCIBus *pci_bus;
     int piix3_devfn = -1;
     CPUState *env;
     NICInfo *nd;
+    qemu_irq *cpu_irq;
+    qemu_irq *i8259;
 
     if (ram_size + (phys_ram_size - ram_size) >= 0xf0000000 ) {
         above_4g_mem_size = phys_ram_size - 0xf0000000;
@@ -503,28 +718,32 @@
         if (pci_enabled) {
             apic_init(env);
         }
+        vmport_init(env);
     }
 
     /* allocate RAM */
-    cpu_register_physical_memory(0, ram_size, 0);
-    if (above_4g_mem_size > 0)
-        cpu_register_physical_memory(0x100000000, above_4g_mem_size, 0);
+    ram_addr = qemu_ram_alloc(ram_size);
+    cpu_register_physical_memory(0, ram_size, ram_addr);
+    if (above_4g_mem_size > 0) {
+	ram_addr = qemu_ram_alloc(above_4g_mem_size);
+        cpu_register_physical_memory(0x100000000, above_4g_mem_size, ram_addr);
+    }
+
+    /* allocate VGA RAM */
+    vga_ram_addr = qemu_ram_alloc(vga_ram_size);
 
     /* BIOS load */
-    bios_offset = ram_size + vga_ram_size;
-    vga_bios_offset = bios_offset + 256 * 1024;
-
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
     bios_size = get_image_size(buf);
-    if (bios_size <= 0 || 
-        (bios_size % 65536) != 0 ||
-        bios_size > (256 * 1024)) {
+    if (bios_size <= 0 ||
+        (bios_size % 65536) != 0) {
         goto bios_error;
     }
+    bios_offset = qemu_ram_alloc(bios_size);
     ret = load_image(buf, phys_ram_base + bios_offset);
     if (ret != bios_size) {
     bios_error:
-        fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
+        fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", buf);
         exit(1);
     }
 
@@ -534,10 +753,20 @@
     } else {
         snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
     }
+    vga_bios_size = get_image_size(buf);
+    if (vga_bios_size <= 0 || vga_bios_size > 65536)
+        goto vga_bios_error;
+    vga_bios_offset = qemu_ram_alloc(65536);
+
     ret = load_image(buf, phys_ram_base + vga_bios_offset);
-    
+    if (ret != vga_bios_size) {
+    vga_bios_error:
+        fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf);
+        exit(1);
+    }
+
     /* setup basic memory access */
-    cpu_register_physical_memory(0xc0000, 0x10000, 
+    cpu_register_physical_memory(0xc0000, 0x10000,
                                  vga_bios_offset | IO_MEM_ROM);
 #ifdef USE_KVM
     if (kvm_allowed)
@@ -549,10 +778,10 @@
     isa_bios_size = bios_size;
     if (isa_bios_size > (128 * 1024))
         isa_bios_size = 128 * 1024;
-    cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size, 
+    cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size,
                                  IO_MEM_UNASSIGNED);
-    cpu_register_physical_memory(0x100000 - isa_bios_size, 
-                                 isa_bios_size, 
+    cpu_register_physical_memory(0x100000 - isa_bios_size,
+                                 isa_bios_size,
                                  (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
 
 #ifdef USE_KVM
@@ -574,112 +803,54 @@
 					 (phys_ram_size - KVM_EXTRA_PAGES * 4096) | IO_MEM_ROM);
     }
 #endif
-    
-    option_rom_offset = 0;
-    for (i = 0; i < nb_option_roms; i++) {
-	int offset = bios_offset + bios_size + option_rom_offset;
-	int size;
 
-	size = load_image(option_rom[i], phys_ram_base + offset);
-	if ((size + option_rom_offset) > 0x10000) {
-	    fprintf(stderr, "Too many option ROMS\n");
-	    exit(1);
-	}
-	cpu_register_physical_memory(0xd0000 + option_rom_offset,
-				     size, offset | IO_MEM_ROM);
+    {
+        ram_addr_t option_rom_offset;
+        int size, offset;
 
-	if (kvm_allowed)
+        offset = 0;
+        for (i = 0; i < nb_option_roms; i++) {
+            size = get_image_size(option_rom[i]);
+            if (size < 0) {
+                fprintf(stderr, "Could not load option rom '%s'\n",
+                        option_rom[i]);
+                exit(1);
+            }
+            if (size > (0x10000 - offset))
+                goto option_rom_error;
+            option_rom_offset = qemu_ram_alloc(size);
+            ret = load_image(option_rom[i], phys_ram_base + option_rom_offset);
+            if (ret != size) {
+            option_rom_error:
+                fprintf(stderr, "Too many option ROMS\n");
+                exit(1);
+            }
+            size = (size + 4095) & ~4095;
+            cpu_register_physical_memory(0xd0000 + offset,
+                                         size, option_rom_offset | IO_MEM_ROM);
+	    if (kvm_allowed)
 		memcpy(phys_ram_base + 0xd0000 + option_rom_offset,
 		       phys_ram_base + offset, size);
 
-	option_rom_offset += size + 2047;
-	option_rom_offset -= (option_rom_offset % 2048);
+            offset += size;
+        }
     }
 
     /* map all the bios at the top of memory */
-    cpu_register_physical_memory((uint32_t)(-bios_size), 
+    cpu_register_physical_memory((uint32_t)(-bios_size),
                                  bios_size, bios_offset | IO_MEM_ROM);
-    
+
     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];
 
     if (pci_enabled) {
-        pci_bus = i440fx_init(&i440fx_state);
+        pci_bus = i440fx_init(&i440fx_state, i8259);
         piix3_devfn = piix3_init(pci_bus, -1);
     } else {
         pci_bus = NULL;
@@ -692,24 +863,30 @@
 
     if (cirrus_vga_enabled) {
         if (pci_enabled) {
-            pci_cirrus_vga_init(pci_bus, 
-                                ds, phys_ram_base + ram_size, ram_size, 
-                                vga_ram_size);
+            pci_cirrus_vga_init(pci_bus,
+                                ds, phys_ram_base + vga_ram_addr,
+                                vga_ram_addr, vga_ram_size);
         } else {
-            isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size, 
-                                vga_ram_size);
+            isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr,
+                                vga_ram_addr, vga_ram_size);
         }
+    } else if (vmsvga_enabled) {
+        if (pci_enabled)
+            pci_vmsvga_init(pci_bus, ds, phys_ram_base + ram_size,
+                            ram_size, vga_ram_size);
+        else
+            fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
     } else {
         if (pci_enabled) {
-            pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, 
-                         vga_ram_size, 0, 0);
+            pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr,
+                         vga_ram_addr, vga_ram_size, 0, 0);
         } else {
-            isa_vga_init(ds, phys_ram_base + ram_size, ram_size, 
-                         vga_ram_size);
+            isa_vga_init(ds, phys_ram_base + vga_ram_addr,
+                         vga_ram_addr, vga_ram_size);
         }
     }
 
-    rtc_state = rtc_init(0x70, 8);
+    rtc_state = rtc_init(0x70, i8259[8]);
 
     register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
     register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
@@ -717,8 +894,7 @@
     if (pci_enabled) {
         ioapic = ioapic_init();
     }
-    isa_pic = pic_init(pic_irq_request, first_cpu);
-    pit = pit_init(0x40, 0);
+    pit = pit_init(0x40, i8259[0]);
     pcspk_init(pit);
     if (pci_enabled) {
         pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
@@ -726,14 +902,14 @@
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(&pic_set_irq_new, isa_pic,
-                        serial_io[i], serial_irq[i], serial_hds[i]);
+            serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]);
         }
     }
 
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
         if (parallel_hds[i]) {
-            parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
+            parallel_init(parallel_io[i], i8259[parallel_irq[i]],
+                          parallel_hds[i]);
         }
     }
 
@@ -747,9 +923,14 @@
             }
         }
         if (strcmp(nd->model, "ne2k_isa") == 0) {
-            pc_init_ne2k_isa(nd);
+            pc_init_ne2k_isa(nd, i8259);
         } else if (pci_enabled) {
+            if (strcmp(nd->model, "?") == 0)
+                fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n");
             pci_nic_init(pci_bus, nd, -1);
+        } else if (strcmp(nd->model, "?") == 0) {
+            fprintf(stderr, "qemu: Supported ISA NICs: ne2k_isa\n");
+            exit(1);
         } else {
             fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
             exit(1);
@@ -761,38 +942,39 @@
     pci_hypercall_init(pci_bus);
 #endif
     if (pci_enabled) {
-        pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
+        pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1, i8259);
     } else {
         for(i = 0; i < 2; i++) {
-            isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+            isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
                          bs_table[2 * i], bs_table[2 * i + 1]);
         }
     }
 
-    kbd_init();
+    i8042_init(i8259[1], i8259[12], 0x60);
     DMA_init(0);
 #ifdef HAS_AUDIO
-    audio_init(pci_enabled ? pci_bus : NULL);
+    audio_init(pci_enabled ? pci_bus : NULL, i8259);
 #endif
 
-    floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
+    floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table);
 
     cmos_init(ram_size, above_4g_mem_size, boot_device, bs_table, smp_cpus);
 
     if (pci_enabled && usb_enabled) {
-        usb_uhci_init(pci_bus, piix3_devfn + 2);
+        usb_uhci_piix3_init(pci_bus, piix3_devfn + 2);
     }
 
     if (pci_enabled && acpi_enabled) {
         uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
-        piix4_pm_init(pci_bus, piix3_devfn + 3);
+        i2c_bus *smbus;
+
+        /* TODO: Populate SPD eeprom data.  */
+        smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100);
         for (i = 0; i < 8; i++) {
-            SMBusDevice *eeprom = smbus_eeprom_device_init(0x50 + i,
-                eeprom_buf + (i * 256));
-            piix4_smbus_register_device(eeprom, 0x50 + i);
+            smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));
         }
     }
-    
+
     if (i440fx_state) {
         i440fx_init_memory_mappings(i440fx_state);
     }
@@ -816,11 +998,12 @@
 }
 
 static void pc_init_pci(ram_addr_t ram_size, int vga_ram_size, int boot_device,
-                        DisplayState *ds, const char **fd_filename, 
-                        int snapshot, 
-                        const char *kernel_filename, 
+                        DisplayState *ds, const char **fd_filename,
+                        int snapshot,
+                        const char *kernel_filename,
                         const char *kernel_cmdline,
-                        const char *initrd_filename)
+                        const char *initrd_filename,
+                        const char *cpu_model)
 {
     pc_init1(ram_size, vga_ram_size, boot_device,
              ds, fd_filename, snapshot,
@@ -829,11 +1012,12 @@
 }
 
 static void pc_init_isa(ram_addr_t ram_size, int vga_ram_size, int boot_device,
-                        DisplayState *ds, const char **fd_filename, 
-                        int snapshot, 
-                        const char *kernel_filename, 
+                        DisplayState *ds, const char **fd_filename,
+                        int snapshot,
+                        const char *kernel_filename,
                         const char *kernel_cmdline,
-                        const char *initrd_filename)
+                        const char *initrd_filename,
+                        const char *cpu_model)
 {
     pc_init1(ram_size, vga_ram_size, boot_device,
              ds, fd_filename, snapshot,
diff --git a/hw/pci.c b/hw/pci.c
index b895f98..7e8adc4 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -2,7 +2,7 @@
  * QEMU PCI bus manager
  *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -33,7 +33,7 @@
     uint32_t config_reg; /* XXX: suppress */
     /* low level pic */
     SetIRQFunc *low_set_irq;
-    void *irq_opaque;
+    qemu_irq *irq_opaque;
     PCIDevice *devices[256];
     PCIDevice *parent_dev;
     PCIBus *next;
@@ -43,13 +43,14 @@
 };
 
 static void pci_update_mappings(PCIDevice *d);
+static void pci_set_irq(void *opaque, int irq_num, int level);
 
 target_phys_addr_t pci_mem_base;
 static int pci_irq_index;
 static PCIBus *first_bus;
 
 PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
-                         void *pic, int devfn_min, int nirq)
+                         qemu_irq *pic, int devfn_min, int nirq)
 {
     PCIBus *bus;
     bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
@@ -95,16 +96,16 @@
 }
 
 /* -1 for devfn means auto assign */
-PCIDevice *pci_register_device(PCIBus *bus, const char *name, 
+PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
-                               PCIConfigReadFunc *config_read, 
+                               PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write)
 {
     PCIDevice *pci_dev;
 
     if (pci_irq_index >= PCI_DEVICES_MAX)
         return NULL;
-    
+
     if (devfn < 0) {
         for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) {
             if (!bus->devices[devfn])
@@ -129,11 +130,12 @@
     pci_dev->config_write = config_write;
     pci_dev->irq_index = pci_irq_index++;
     bus->devices[devfn] = pci_dev;
+    pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4);
     return pci_dev;
 }
 
-void pci_register_io_region(PCIDevice *pci_dev, int region_num, 
-                            uint32_t size, int type, 
+void pci_register_io_region(PCIDevice *pci_dev, int region_num,
+                            uint32_t size, int type,
                             PCIMapIORegionFunc *map_func)
 {
     PCIIORegion *r;
@@ -164,7 +166,7 @@
     PCIIORegion *r;
     int cmd, i;
     uint32_t last_addr, new_addr, config_ofs;
-    
+
     cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND));
     for(i = 0; i < PCI_NUM_REGIONS; i++) {
         r = &d->io_regions[i];
@@ -176,7 +178,7 @@
         if (r->size != 0) {
             if (r->type & PCI_ADDRESS_SPACE_IO) {
                 if (cmd & PCI_COMMAND_IO) {
-                    new_addr = le32_to_cpu(*(uint32_t *)(d->config + 
+                    new_addr = le32_to_cpu(*(uint32_t *)(d->config +
                                                          config_ofs));
                     new_addr = new_addr & ~(r->size - 1);
                     last_addr = new_addr + r->size - 1;
@@ -190,7 +192,7 @@
                 }
             } else {
                 if (cmd & PCI_COMMAND_MEMORY) {
-                    new_addr = le32_to_cpu(*(uint32_t *)(d->config + 
+                    new_addr = le32_to_cpu(*(uint32_t *)(d->config +
                                                          config_ofs));
                     /* the ROM slot has a specific enable bit */
                     if (i == PCI_ROM_SLOT && !(new_addr & 1))
@@ -225,7 +227,7 @@
                         }
                     } else {
                         cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
-                                                     r->size, 
+                                                     r->size,
                                                      IO_MEM_UNASSIGNED);
                     }
                 }
@@ -238,7 +240,7 @@
     }
 }
 
-uint32_t pci_default_read_config(PCIDevice *d, 
+uint32_t pci_default_read_config(PCIDevice *d,
                                  uint32_t address, int len)
 {
     uint32_t val;
@@ -264,13 +266,13 @@
     return val;
 }
 
-void pci_default_write_config(PCIDevice *d, 
+void pci_default_write_config(PCIDevice *d,
                               uint32_t address, uint32_t val, int len)
 {
     int can_write, i;
     uint32_t end, addr;
 
-    if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) || 
+    if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
                      (address >= 0x30 && address < 0x34))) {
         PCIIORegion *r;
         int reg;
@@ -365,7 +367,7 @@
     PCIBus *s = opaque;
     PCIDevice *pci_dev;
     int config_addr, bus_num;
-    
+
 #if defined(DEBUG_PCI) && 0
     printf("pci_data_write: addr=%08x val=%08x len=%d\n",
            addr, val, len);
@@ -433,11 +435,12 @@
 /* generic PCI irq support */
 
 /* 0 <= irq_num <= 3. level must be 0 or 1 */
-void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
+static void pci_set_irq(void *opaque, int irq_num, int level)
 {
+    PCIDevice *pci_dev = (PCIDevice *)opaque;
     PCIBus *bus;
     int change;
-    
+
     change = level - pci_dev->irq_state[irq_num];
     if (!change)
         return;
@@ -462,15 +465,42 @@
     const char *desc;
 } pci_class_desc;
 
-static pci_class_desc pci_class_descriptions[] = 
+static pci_class_desc pci_class_descriptions[] =
 {
     { 0x0100, "SCSI controller"},
     { 0x0101, "IDE controller"},
+    { 0x0102, "Floppy controller"},
+    { 0x0103, "IPI controller"},
+    { 0x0104, "RAID controller"},
+    { 0x0106, "SATA controller"},
+    { 0x0107, "SAS controller"},
+    { 0x0180, "Storage controller"},
     { 0x0200, "Ethernet controller"},
+    { 0x0201, "Token Ring controller"},
+    { 0x0202, "FDDI controller"},
+    { 0x0203, "ATM controller"},
+    { 0x0280, "Network controller"},
     { 0x0300, "VGA controller"},
+    { 0x0301, "XGA controller"},
+    { 0x0302, "3D controller"},
+    { 0x0380, "Display controller"},
+    { 0x0400, "Video controller"},
+    { 0x0401, "Audio controller"},
+    { 0x0402, "Phone"},
+    { 0x0480, "Multimedia controller"},
+    { 0x0500, "RAM controller"},
+    { 0x0501, "Flash controller"},
+    { 0x0580, "Memory controller"},
     { 0x0600, "Host bridge"},
     { 0x0601, "ISA bridge"},
+    { 0x0602, "EISA bridge"},
+    { 0x0603, "MC bridge"},
     { 0x0604, "PCI bridge"},
+    { 0x0605, "PCMCIA bridge"},
+    { 0x0606, "NUBUS bridge"},
+    { 0x0607, "CARDBUS bridge"},
+    { 0x0608, "RACEWAY bridge"},
+    { 0x0680, "Bridge"},
     { 0x0c03, "USB controller"},
     { 0, NULL}
 };
@@ -508,10 +538,10 @@
         if (r->size != 0) {
             term_printf("      BAR%d: ", i);
             if (r->type & PCI_ADDRESS_SPACE_IO) {
-                term_printf("I/O at 0x%04x [0x%04x].\n", 
+                term_printf("I/O at 0x%04x [0x%04x].\n",
                        r->addr, r->addr + r->size - 1);
             } else {
-                term_printf("32 bit memory at 0x%08x [0x%08x].\n", 
+                term_printf("32 bit memory at 0x%08x [0x%08x].\n",
                        r->addr, r->addr + r->size - 1);
             }
         }
@@ -526,7 +556,7 @@
     PCIBus *bus = first_bus;
     PCIDevice *d;
     int devfn;
-    
+
     while (bus && bus->bus_num != bus_num)
         bus = bus->next;
     if (bus) {
@@ -548,10 +578,20 @@
 {
     if (strcmp(nd->model, "ne2k_pci") == 0) {
         pci_ne2000_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "i82551") == 0) {
+        pci_i82551_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "i82557b") == 0) {
+        pci_i82557b_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "i82559er") == 0) {
+        pci_i82559er_init(bus, nd, devfn);
     } else if (strcmp(nd->model, "rtl8139") == 0) {
         pci_rtl8139_init(bus, nd, devfn);
     } else if (strcmp(nd->model, "pcnet") == 0) {
         pci_pcnet_init(bus, nd, devfn);
+    } else if (strcmp(nd->model, "?") == 0) {
+        fprintf(stderr, "qemu: Supported PCI NICs: i82551 i82557b i82559er"
+                        " ne2k_pci pcnet rtl8139\n");
+        exit (1);
     } else {
         fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
         exit (1);
@@ -563,7 +603,7 @@
     PCIBus *bus;
 } PCIBridge;
 
-void pci_bridge_write_config(PCIDevice *d, 
+void pci_bridge_write_config(PCIDevice *d,
                              uint32_t address, uint32_t val, int len)
 {
     PCIBridge *s = (PCIBridge *)d;
@@ -584,10 +624,10 @@
                         pci_map_irq_fn map_irq, const char *name)
 {
     PCIBridge *s;
-    s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge), 
+    s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
                                          devfn, NULL, pci_bridge_write_config);
     s->dev.config[0x00] = id >> 16;
-    s->dev.config[0x01] = id > 24;
+    s->dev.config[0x01] = id >> 24;
     s->dev.config[0x02] = id; // device_id
     s->dev.config[0x03] = id >> 8;
     s->dev.config[0x04] = 0x06; // command = bus master, pci mem
diff --git a/hw/pci_host.h b/hw/pci_host.h
index 708dae2..49a0c59 100644
--- a/hw/pci_host.h
+++ b/hw/pci_host.h
@@ -2,7 +2,7 @@
  * QEMU Common PCI Host bridge configuration data space access routines.
  *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
diff --git a/hw/pckbd.c b/hw/pckbd.c
index 3c41e5f..ff4916d 100644
--- a/hw/pckbd.c
+++ b/hw/pckbd.c
@@ -1,8 +1,8 @@
 /*
  * QEMU PC keyboard emulation
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -121,6 +121,11 @@
     uint8_t pending;
     void *kbd;
     void *mouse;
+
+    qemu_irq irq_kbd;
+    qemu_irq irq_mouse;
+    target_phys_addr_t base;
+    int it_shift;
 } KBDState;
 
 KBDState kbd_state;
@@ -130,26 +135,26 @@
    incorrect, but it avoids having to simulate exact delays */
 static void kbd_update_irq(KBDState *s)
 {
-    int irq12_level, irq1_level;
+    int irq_kbd_level, irq_mouse_level;
 
-    irq1_level = 0;    
-    irq12_level = 0;    
+    irq_kbd_level = 0;
+    irq_mouse_level = 0;
     s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
     if (s->pending) {
         s->status |= KBD_STAT_OBF;
-        /* kdb data takes priority over aux data.  */
+        /* kbd data takes priority over aux data.  */
         if (s->pending == KBD_PENDING_AUX) {
             s->status |= KBD_STAT_MOUSE_OBF;
             if (s->mode & KBD_MODE_MOUSE_INT)
-                irq12_level = 1;
+                irq_mouse_level = 1;
         } else {
-            if ((s->mode & KBD_MODE_KBD_INT) && 
+            if ((s->mode & KBD_MODE_KBD_INT) &&
                 !(s->mode & KBD_MODE_DISABLE_KBD))
-                irq1_level = 1;
+                irq_kbd_level = 1;
         }
     }
-    pic_set_irq(1, irq1_level);
-    pic_set_irq(12, irq12_level);
+    qemu_set_irq(s->irq_kbd, irq_kbd_level);
+    qemu_set_irq(s->irq_mouse, irq_mouse_level);
 }
 
 static void kbd_update_kbd_irq(void *opaque, int level)
@@ -333,7 +338,7 @@
 static void kbd_save(QEMUFile* f, void* opaque)
 {
     KBDState *s = (KBDState*)opaque;
-    
+
     qemu_put_8s(f, &s->write_cmd);
     qemu_put_8s(f, &s->status);
     qemu_put_8s(f, &s->mode);
@@ -343,7 +348,7 @@
 static int kbd_load(QEMUFile* f, void* opaque, int version_id)
 {
     KBDState *s = (KBDState*)opaque;
-    
+
     if (version_id != 3)
         return -EINVAL;
     qemu_get_8s(f, &s->write_cmd);
@@ -353,18 +358,89 @@
     return 0;
 }
 
-void kbd_init(void)
+void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base)
 {
     KBDState *s = &kbd_state;
-    
+
+    s->irq_kbd = kbd_irq;
+    s->irq_mouse = mouse_irq;
+
     kbd_reset(s);
     register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
-    register_ioport_read(0x60, 1, 1, kbd_read_data, s);
-    register_ioport_write(0x60, 1, 1, kbd_write_data, s);
-    register_ioport_read(0x64, 1, 1, kbd_read_status, s);
-    register_ioport_write(0x64, 1, 1, kbd_write_command, s);
+    register_ioport_read(io_base, 1, 1, kbd_read_data, s);
+    register_ioport_write(io_base, 1, 1, kbd_write_data, s);
+    register_ioport_read(io_base + 4, 1, 1, kbd_read_status, s);
+    register_ioport_write(io_base + 4, 1, 1, kbd_write_command, s);
 
     s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
     s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
+#ifdef TARGET_I386
+    vmmouse_init(s->mouse);
+#endif
+    qemu_register_reset(kbd_reset, s);
+}
+
+/* Memory mapped interface */
+uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    KBDState *s = opaque;
+
+    switch ((addr - s->base) >> s->it_shift) {
+    case 0:
+        return kbd_read_data(s, 0) & 0xff;
+    case 1:
+        return kbd_read_status(s, 0) & 0xff;
+    default:
+        return 0xff;
+    }
+}
+
+void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    KBDState *s = opaque;
+
+    switch ((addr - s->base) >> s->it_shift) {
+    case 0:
+        kbd_write_data(s, 0, value & 0xff);
+        break;
+    case 1:
+        kbd_write_command(s, 0, value & 0xff);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *kbd_mm_read[] = {
+    &kbd_mm_readb,
+    &kbd_mm_readb,
+    &kbd_mm_readb,
+};
+
+static CPUWriteMemoryFunc *kbd_mm_write[] = {
+    &kbd_mm_writeb,
+    &kbd_mm_writeb,
+    &kbd_mm_writeb,
+};
+
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
+                   target_phys_addr_t base, int it_shift)
+{
+    KBDState *s = &kbd_state;
+    int s_io_memory;
+
+    s->irq_kbd = kbd_irq;
+    s->irq_mouse = mouse_irq;
+    s->base = base;
+    s->it_shift = it_shift;
+
+    kbd_reset(s);
+    register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
+    s_io_memory = cpu_register_io_memory(0, kbd_mm_read, kbd_mm_write, s);
+    cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+
+    s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+    s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
+#ifdef TARGET_I386
+    vmmouse_init(s->mouse);
+#endif
     qemu_register_reset(kbd_reset, s);
 }
diff --git a/hw/pcnet.c b/hw/pcnet.c
index 3bdddeb..71a05da 100644
--- a/hw/pcnet.c
+++ b/hw/pcnet.c
@@ -1,8 +1,8 @@
 /*
  * QEMU AMD PC-Net II (Am79C970A) emulation
- * 
+ *
  * Copyright (c) 2004 Antony T Curtis
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -21,12 +21,12 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
- 
+
 /* This software was written to be compatible with the specification:
  * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
  * AMD Publication# 19436  Rev:E  Amendment/0  Issue Date: June 2000
  */
- 
+
 /*
  * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also
  * produced as NCR89C100. See
@@ -35,8 +35,6 @@
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
  */
 
-/* TODO: remove little endian host assumptions */
- 
 #include "vl.h"
 
 //#define PCNET_DEBUG
@@ -69,7 +67,7 @@
     int xmit_pos, recv_pos;
     uint8_t buffer[4096];
     int tx_busy;
-    void (*set_irq_cb)(void *s, int isr);
+    qemu_irq irq;
     void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr,
                          uint8_t *buf, int len, int do_bswap);
     void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr,
@@ -77,14 +75,6 @@
     void *dma_opaque;
 };
 
-/* XXX: using bitfields for target memory structures is almost surely
-   not portable, so it should be suppressed ASAP */
-#ifdef __GNUC__
-#define PACKED_FIELD(A) A __attribute__ ((packed))
-#else
-#error FixMe
-#endif
-
 struct qemu_ether_header {
     uint8_t ether_dhost[6];
     uint8_t ether_shost[6];
@@ -183,223 +173,291 @@
 };
 
 struct pcnet_TMD {
-    struct {
-        unsigned tbadr:32;
-    } tmd0;
-    struct {
-        unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1);
-        unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1);
-        unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1);
-    } tmd1;
-    struct {
-        unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12);
-        unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1);
-        unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1);
-    } tmd2;
-    struct {
-        unsigned res:32;
-    } tmd3;    
+    uint32_t tbadr;
+    int16_t length;
+    int16_t status;
+    uint32_t misc;
+    uint32_t res;
 };
 
+#define TMDL_BCNT_MASK  0x0fff
+#define TMDL_BCNT_SH    0
+#define TMDL_ONES_MASK  0xf000
+#define TMDL_ONES_SH    12
+
+#define TMDS_BPE_MASK   0x0080
+#define TMDS_BPE_SH     7
+#define TMDS_ENP_MASK   0x0100
+#define TMDS_ENP_SH     8
+#define TMDS_STP_MASK   0x0200
+#define TMDS_STP_SH     9
+#define TMDS_DEF_MASK   0x0400
+#define TMDS_DEF_SH     10
+#define TMDS_ONE_MASK   0x0800
+#define TMDS_ONE_SH     11
+#define TMDS_LTINT_MASK 0x1000
+#define TMDS_LTINT_SH   12
+#define TMDS_NOFCS_MASK 0x2000
+#define TMDS_NOFCS_SH   13
+#define TMDS_ERR_MASK   0x4000
+#define TMDS_ERR_SH     14
+#define TMDS_OWN_MASK   0x8000
+#define TMDS_OWN_SH     15
+
+#define TMDM_TRC_MASK   0x0000000f
+#define TMDM_TRC_SH     0
+#define TMDM_TDR_MASK   0x03ff0000
+#define TMDM_TDR_SH     16
+#define TMDM_RTRY_MASK  0x04000000
+#define TMDM_RTRY_SH    26
+#define TMDM_LCAR_MASK  0x08000000
+#define TMDM_LCAR_SH    27
+#define TMDM_LCOL_MASK  0x10000000
+#define TMDM_LCOL_SH    28
+#define TMDM_EXDEF_MASK 0x20000000
+#define TMDM_EXDEF_SH   29
+#define TMDM_UFLO_MASK  0x40000000
+#define TMDM_UFLO_SH    30
+#define TMDM_BUFF_MASK  0x80000000
+#define TMDM_BUFF_SH    31
+
 struct pcnet_RMD {
-    struct {
-        unsigned rbadr:32;
-    } rmd0;
-    struct {
-        unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4);
-        unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1);
-        unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1);
-        unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1);
-    } rmd1;
-    struct {
-        unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4);
-        unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8);
-    } rmd2;    
-    struct {
-        unsigned res:32;
-    } rmd3;    
+    uint32_t rbadr;
+    int16_t buf_length;
+    int16_t status;
+    uint32_t msg_length;
+    uint32_t res;
 };
 
+#define RMDL_BCNT_MASK  0x0fff
+#define RMDL_BCNT_SH    0
+#define RMDL_ONES_MASK  0xf000
+#define RMDL_ONES_SH    12
 
-#define PRINT_TMD(T) printf(    \
-        "TMD0 : TBADR=0x%08x\n" \
+#define RMDS_BAM_MASK   0x0010
+#define RMDS_BAM_SH     4
+#define RMDS_LFAM_MASK  0x0020
+#define RMDS_LFAM_SH    5
+#define RMDS_PAM_MASK   0x0040
+#define RMDS_PAM_SH     6
+#define RMDS_BPE_MASK   0x0080
+#define RMDS_BPE_SH     7
+#define RMDS_ENP_MASK   0x0100
+#define RMDS_ENP_SH     8
+#define RMDS_STP_MASK   0x0200
+#define RMDS_STP_SH     9
+#define RMDS_BUFF_MASK  0x0400
+#define RMDS_BUFF_SH    10
+#define RMDS_CRC_MASK   0x0800
+#define RMDS_CRC_SH     11
+#define RMDS_OFLO_MASK  0x1000
+#define RMDS_OFLO_SH    12
+#define RMDS_FRAM_MASK  0x2000
+#define RMDS_FRAM_SH    13
+#define RMDS_ERR_MASK   0x4000
+#define RMDS_ERR_SH     14
+#define RMDS_OWN_MASK   0x8000
+#define RMDS_OWN_SH     15
+
+#define RMDM_MCNT_MASK  0x00000fff
+#define RMDM_MCNT_SH    0
+#define RMDM_ZEROS_MASK 0x0000f000
+#define RMDM_ZEROS_SH   12
+#define RMDM_RPC_MASK   0x00ff0000
+#define RMDM_RPC_SH     16
+#define RMDM_RCC_MASK   0xff000000
+#define RMDM_RCC_SH     24
+
+#define SET_FIELD(regp, name, field, value)             \
+  (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
+             | ((value) << name ## _ ## field ## _SH))
+
+#define GET_FIELD(reg, name, field)                     \
+  (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
+
+#define PRINT_TMD(T) printf(                            \
+        "TMD0 : TBADR=0x%08x\n"                         \
         "TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, "       \
         "ONE=%d, DEF=%d, STP=%d, ENP=%d,\n"             \
         "       BPE=%d, BCNT=%d\n"                      \
         "TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, "       \
         "LCA=%d, RTR=%d,\n"                             \
         "       TDR=%d, TRC=%d\n",                      \
-        (T)->tmd0.tbadr,                                \
-        (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs,  \
-        (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def,  \
-        (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe,    \
-        4096-(T)->tmd1.bcnt,                            \
-        (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\
-        (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \
-        (T)->tmd2.tdr, (T)->tmd2.trc)
+        (T)->tbadr,                                     \
+        GET_FIELD((T)->status, TMDS, OWN),              \
+        GET_FIELD((T)->status, TMDS, ERR),              \
+        GET_FIELD((T)->status, TMDS, NOFCS),            \
+        GET_FIELD((T)->status, TMDS, LTINT),            \
+        GET_FIELD((T)->status, TMDS, ONE),              \
+        GET_FIELD((T)->status, TMDS, DEF),              \
+        GET_FIELD((T)->status, TMDS, STP),              \
+        GET_FIELD((T)->status, TMDS, ENP),              \
+        GET_FIELD((T)->status, TMDS, BPE),              \
+        4096-GET_FIELD((T)->length, TMDL, BCNT),        \
+        GET_FIELD((T)->misc, TMDM, BUFF),               \
+        GET_FIELD((T)->misc, TMDM, UFLO),               \
+        GET_FIELD((T)->misc, TMDM, EXDEF),              \
+        GET_FIELD((T)->misc, TMDM, LCOL),               \
+        GET_FIELD((T)->misc, TMDM, LCAR),               \
+        GET_FIELD((T)->misc, TMDM, RTRY),               \
+        GET_FIELD((T)->misc, TMDM, TDR),                \
+        GET_FIELD((T)->misc, TMDM, TRC))
 
-#define PRINT_RMD(R) printf(    \
-        "RMD0 : RBADR=0x%08x\n" \
+#define PRINT_RMD(R) printf(                            \
+        "RMD0 : RBADR=0x%08x\n"                         \
         "RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, "     \
         "CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n       "     \
-        "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n"    \
+        "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
         "RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n",   \
-        (R)->rmd0.rbadr,                                \
-        (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram,   \
-        (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff,  \
-        (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe,    \
-        (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam,   \
-        (R)->rmd1.ones, 4096-(R)->rmd1.bcnt,            \
-        (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt,   \
-        (R)->rmd2.zeros)
+        (R)->rbadr,                                     \
+        GET_FIELD((R)->status, RMDS, OWN),              \
+        GET_FIELD((R)->status, RMDS, ERR),              \
+        GET_FIELD((R)->status, RMDS, FRAM),             \
+        GET_FIELD((R)->status, RMDS, OFLO),             \
+        GET_FIELD((R)->status, RMDS, CRC),              \
+        GET_FIELD((R)->status, RMDS, BUFF),             \
+        GET_FIELD((R)->status, RMDS, STP),              \
+        GET_FIELD((R)->status, RMDS, ENP),              \
+        GET_FIELD((R)->status, RMDS, BPE),              \
+        GET_FIELD((R)->status, RMDS, PAM),              \
+        GET_FIELD((R)->status, RMDS, LFAM),             \
+        GET_FIELD((R)->status, RMDS, BAM),              \
+        GET_FIELD((R)->buf_length, RMDL, ONES),         \
+        4096-GET_FIELD((R)->buf_length, RMDL, BCNT),    \
+        GET_FIELD((R)->msg_length, RMDM, RCC),          \
+        GET_FIELD((R)->msg_length, RMDM, RPC),          \
+        GET_FIELD((R)->msg_length, RMDM, MCNT),         \
+        GET_FIELD((R)->msg_length, RMDM, ZEROS))
 
-static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd1, 
+static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
                                   target_phys_addr_t addr)
 {
-    uint32_t *tmd = (uint32_t *)tmd1;
-
-    if (!BCR_SWSTYLE(s)) {
-        uint16_t xda[4];
-        s->phys_mem_read(s->dma_opaque, addr,
-                (void *)&xda[0], sizeof(xda), 0);
-        le16_to_cpus(&xda[0]);
-        le16_to_cpus(&xda[1]);
-        le16_to_cpus(&xda[2]);
-        le16_to_cpus(&xda[3]);
-        tmd[0] = (xda[0]&0xffff) |
-            ((xda[1]&0x00ff) << 16);
-        tmd[1] = (xda[2]&0xffff)|
-            ((xda[1] & 0xff00) << 16);
-        tmd[2] =
-            (xda[3] & 0xffff) << 16;
-        tmd[3] = 0;
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+	} xda;
+        s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
+        tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
+        tmd->length = le16_to_cpu(xda.length);
+        tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
+        tmd->misc = le16_to_cpu(xda.status) << 16;
+        tmd->res = 0;
     } else {
-        uint32_t xda[4];
-        s->phys_mem_read(s->dma_opaque, addr,
-                (void *)&xda[0], sizeof(xda), 0);
-        le32_to_cpus(&xda[0]);
-        le32_to_cpus(&xda[1]);
-        le32_to_cpus(&xda[2]);
-        le32_to_cpus(&xda[3]);
-        if (BCR_SWSTYLE(s) != 3) {
-            memcpy(tmd, xda, sizeof(xda));
-        } else {
-            tmd[0] = xda[2];
-            tmd[1] = xda[1];
-            tmd[2] = xda[0];
-            tmd[3] = xda[3];
+        s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
+        le32_to_cpus(&tmd->tbadr);
+        le16_to_cpus(&tmd->length);
+        le16_to_cpus(&tmd->status);
+        le32_to_cpus(&tmd->misc);
+        le32_to_cpus(&tmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = tmd->tbadr;
+            tmd->tbadr = tmd->misc;
+            tmd->misc = tmp;
         }
     }
 }
 
-static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd1,
+static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
                                    target_phys_addr_t addr)
 {
-    const uint32_t *tmd = (const uint32_t *)tmd1;
-    if (!BCR_SWSTYLE(s)) {
-        uint16_t xda[4];
-        xda[0] = tmd[0] & 0xffff;
-        xda[1] = ((tmd[0]>>16)&0x00ff) |
-            ((tmd[1]>>16)&0xff00);
-        xda[2] = tmd[1] & 0xffff;
-        xda[3] = tmd[2] >> 16;
-        cpu_to_le16s(&xda[0]);
-        cpu_to_le16s(&xda[1]);
-        cpu_to_le16s(&xda[2]);
-        cpu_to_le16s(&xda[3]);
-        s->phys_mem_write(s->dma_opaque, addr,
-                (void *)&xda[0], sizeof(xda), 0);
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+        } xda;
+        xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
+                                ((tmd->status & 0xff00) << 16));
+        xda.length = cpu_to_le16(tmd->length);
+        xda.status = cpu_to_le16(tmd->misc >> 16);
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
     } else {
-        uint32_t xda[4];
-        if (BCR_SWSTYLE(s) != 3) {
-            memcpy(xda, tmd, sizeof(xda));
-        } else {
-            xda[0] = tmd[2];
-            xda[1] = tmd[1];
-            xda[2] = tmd[0];
-            xda[3] = tmd[3];
+        struct {
+            uint32_t tbadr;
+            int16_t length;
+            int16_t status;
+            uint32_t misc;
+            uint32_t res;
+        } xda;
+        xda.tbadr = cpu_to_le32(tmd->tbadr);
+        xda.length = cpu_to_le16(tmd->length);
+        xda.status = cpu_to_le16(tmd->status);
+        xda.misc = cpu_to_le32(tmd->misc);
+        xda.res = cpu_to_le32(tmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = xda.tbadr;
+            xda.tbadr = xda.misc;
+            xda.misc = tmp;
         }
-        cpu_to_le32s(&xda[0]);
-        cpu_to_le32s(&xda[1]);
-        cpu_to_le32s(&xda[2]);
-        cpu_to_le32s(&xda[3]);
-        s->phys_mem_write(s->dma_opaque, addr,
-                          (void *)&xda[0], sizeof(xda), 0);
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
     }
 }
 
-static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd1,
+static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
                                   target_phys_addr_t addr)
 {
-    uint32_t *rmd = (uint32_t *)rmd1;
-
-    if (!BCR_SWSTYLE(s)) {
-        uint16_t rda[4];
-        s->phys_mem_read(s->dma_opaque, addr, 
-                         (void *)&rda[0], sizeof(rda), 0);
-        le16_to_cpus(&rda[0]);
-        le16_to_cpus(&rda[1]);
-        le16_to_cpus(&rda[2]);
-        le16_to_cpus(&rda[3]);
-        rmd[0] = (rda[0]&0xffff)|
-            ((rda[1] & 0x00ff) << 16);
-        rmd[1] = (rda[2]&0xffff)|
-            ((rda[1] & 0xff00) << 16);
-        rmd[2] = rda[3] & 0xffff;
-        rmd[3] = 0;
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t msg_length;
+	} rda;
+        s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
+        rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
+        rmd->buf_length = le16_to_cpu(rda.buf_length);
+        rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
+        rmd->msg_length = le16_to_cpu(rda.msg_length);
+        rmd->res = 0;
     } else {
-        uint32_t rda[4];
-        s->phys_mem_read(s->dma_opaque, addr, 
-                         (void *)&rda[0], sizeof(rda), 0);
-        le32_to_cpus(&rda[0]);
-        le32_to_cpus(&rda[1]);
-        le32_to_cpus(&rda[2]);
-        le32_to_cpus(&rda[3]);
-        if (BCR_SWSTYLE(s) != 3) {
-            memcpy(rmd, rda, sizeof(rda));
-        } else {
-            rmd[0] = rda[2];
-            rmd[1] = rda[1];
-            rmd[2] = rda[0];
-            rmd[3] = rda[3];
+        s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
+        le32_to_cpus(&rmd->rbadr);
+        le16_to_cpus(&rmd->buf_length);
+        le16_to_cpus(&rmd->status);
+        le32_to_cpus(&rmd->msg_length);
+        le32_to_cpus(&rmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = rmd->rbadr;
+            rmd->rbadr = rmd->msg_length;
+            rmd->msg_length = tmp;
         }
     }
 }
 
-static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1, 
+static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
                                    target_phys_addr_t addr)
 {
-    const uint32_t *rmd = (const uint32_t *)rmd1;
-
-    if (!BCR_SWSTYLE(s)) {
-        uint16_t rda[4];
-        rda[0] = rmd[0] & 0xffff;
-        rda[1] = ((rmd[0]>>16)&0xff)|
-            ((rmd[1]>>16)&0xff00);
-        rda[2] = rmd[1] & 0xffff;
-        rda[3] = rmd[2] & 0xffff;
-        cpu_to_le16s(&rda[0]);
-        cpu_to_le16s(&rda[1]);
-        cpu_to_le16s(&rda[2]);
-        cpu_to_le16s(&rda[3]);
-        s->phys_mem_write(s->dma_opaque, addr,
-                (void *)&rda[0], sizeof(rda), 0);
+    if (!BCR_SSIZE32(s)) {
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t msg_length;
+        } rda;
+        rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
+                                ((rmd->status & 0xff00) << 16));
+        rda.buf_length = cpu_to_le16(rmd->buf_length);
+        rda.msg_length = cpu_to_le16(rmd->msg_length);
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
     } else {
-        uint32_t rda[4];
-        if (BCR_SWSTYLE(s) != 3) {
-            memcpy(rda, rmd, sizeof(rda));
-        } else {
-            rda[0] = rmd[2];
-            rda[1] = rmd[1];
-            rda[2] = rmd[0];
-            rda[3] = rmd[3];
+        struct {
+            uint32_t rbadr;
+            int16_t buf_length;
+            int16_t status;
+            uint32_t msg_length;
+            uint32_t res;
+        } rda;
+        rda.rbadr = cpu_to_le32(rmd->rbadr);
+        rda.buf_length = cpu_to_le16(rmd->buf_length);
+        rda.status = cpu_to_le16(rmd->status);
+        rda.msg_length = cpu_to_le32(rmd->msg_length);
+        rda.res = cpu_to_le32(rmd->res);
+        if (BCR_SWSTYLE(s) == 3) {
+            uint32_t tmp = rda.rbadr;
+            rda.rbadr = rda.msg_length;
+            rda.msg_length = tmp;
         }
-        cpu_to_le32s(&rda[0]);
-        cpu_to_le32s(&rda[1]);
-        cpu_to_le32s(&rda[2]);
-        cpu_to_le32s(&rda[3]);
-        s->phys_mem_write(s->dma_opaque, addr,
-                          (void *)&rda[0], sizeof(rda), 0);
+        s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
     }
 }
 
@@ -417,14 +475,14 @@
 #define CHECK_RMD(ADDR,RES) do {                \
     struct pcnet_RMD rmd;                       \
     RMDLOAD(&rmd,(ADDR));                       \
-    (RES) |= (rmd.rmd1.ones != 15)              \
-          || (rmd.rmd2.zeros != 0);             \
+    (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
+          || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
 } while (0)
 
 #define CHECK_TMD(ADDR,RES) do {                \
     struct pcnet_TMD tmd;                       \
     TMDLOAD(&tmd,(ADDR));                       \
-    (RES) |= (tmd.tmd1.ones != 15);             \
+    (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
 } while (0)
 
 #else
@@ -434,8 +492,8 @@
     case 0x00:                                  \
         do {                                    \
             uint16_t rda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR),    \
-                (void *)&rda[0], sizeof(rda), 0);  \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&rda[0], sizeof(rda), 0); \
             (RES) |= (rda[2] & 0xf000)!=0xf000; \
             (RES) |= (rda[3] & 0xf000)!=0x0000; \
         } while (0);                            \
@@ -444,7 +502,7 @@
     case 0x02:                                  \
         do {                                    \
             uint32_t rda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR),    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
                 (void *)&rda[0], sizeof(rda), 0); \
             (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
             (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
@@ -453,7 +511,7 @@
     case 0x03:                                  \
         do {                                    \
             uint32_t rda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR),    \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
                 (void *)&rda[0], sizeof(rda), 0); \
             (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
             (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
@@ -467,9 +525,9 @@
     case 0x00:                                  \
         do {                                    \
             uint16_t xda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR),    \
-                (void *)&xda[0], sizeof(xda), 0);  \
-            (RES) |= (xda[2] & 0xf000)!=0xf000;\
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&xda[0], sizeof(xda), 0); \
+            (RES) |= (xda[2] & 0xf000)!=0xf000; \
         } while (0);                            \
         break;                                  \
     case 0x01:                                  \
@@ -477,8 +535,8 @@
     case 0x03:                                  \
         do {                                    \
             uint32_t xda[4];                    \
-            s->phys_mem_read(s->dma_opaque, (ADDR),    \
-                (void *)&xda[0], sizeof(xda), 0);  \
+            s->phys_mem_read(s->dma_opaque, (ADDR), \
+                (void *)&xda[0], sizeof(xda), 0); \
             (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
         } while (0);                            \
         break;                                  \
@@ -488,15 +546,15 @@
 #endif
 
 #define PRINT_PKTHDR(BUF) do {                  \
-    struct qemu_ether_header *hdr = (void *)(BUF);   \
-    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "       \
-           "shost=%02x:%02x:%02x:%02x:%02x:%02x, "              \
-           "type=0x%04x\n",                          \
+    struct qemu_ether_header *hdr = (void *)(BUF); \
+    printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+           "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+           "type=0x%04x\n",                     \
            hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
            hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
            hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
            hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
-           be16_to_cpu(hdr->ether_type));                     \
+           be16_to_cpu(hdr->ether_type));       \
 } while (0)
 
 #define MULTICAST_FILTER_LEN 8
@@ -594,10 +652,10 @@
 static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
 {
     struct qemu_ether_header *hdr = (void *)buf;
-    uint8_t padr[6] = { 
+    uint8_t padr[6] = {
         s->csr[12] & 0xff, s->csr[12] >> 8,
         s->csr[13] & 0xff, s->csr[13] >> 8,
-        s->csr[14] & 0xff, s->csr[14] >> 8 
+        s->csr[14] & 0xff, s->csr[14] >> 8
     };
     int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
 #ifdef PCNET_DEBUG_MATCH
@@ -625,13 +683,13 @@
 static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
 {
     struct qemu_ether_header *hdr = (void *)buf;
-    if ((*(hdr->ether_dhost)&0x01) && 
+    if ((*(hdr->ether_dhost)&0x01) &&
         ((uint64_t *)&s->csr[8])[0] != 0LL) {
-        uint8_t ladr[8] = { 
+        uint8_t ladr[8] = {
             s->csr[8] & 0xff, s->csr[8] >> 8,
             s->csr[9] & 0xff, s->csr[9] >> 8,
-            s->csr[10] & 0xff, s->csr[10] >> 8, 
-            s->csr[11] & 0xff, s->csr[11] >> 8 
+            s->csr[10] & 0xff, s->csr[10] >> 8,
+            s->csr[11] & 0xff, s->csr[11] >> 8
         };
         int index = lnc_mchash(hdr->ether_dhost) >> 26;
         return !!(ladr[index >> 3] & (1 << (index & 7)));
@@ -639,7 +697,7 @@
     return 0;
 }
 
-static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) 
+static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx)
 {
     while (idx < 1) idx += CSR_RCVRL(s);
     return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
@@ -647,8 +705,8 @@
 
 static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
 {
-    int64_t next_time = current_time + 
-        muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), 
+    int64_t next_time = current_time +
+        muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
                  ticks_per_sec, 33000000L);
     if (next_time <= current_time)
         next_time = current_time + 1;
@@ -673,7 +731,7 @@
     s->rdra = 0;
     s->tdra = 0;
     s->rap = 0;
-    
+
     s->bcr[BCR_BSBC] &= ~0x0080;
 
     s->csr[0]   = 0x0004;
@@ -712,7 +770,7 @@
 {
     int isr = 0;
     s->csr[0] &= ~0x0080;
-    
+
 #if 1
     if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
         (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
@@ -732,11 +790,11 @@
         (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
 #endif
     {
-       
+
         isr = CSR_INEA(s);
         s->csr[0] |= 0x0080;
     }
-    
+
     if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
         s->csr[4] &= ~0x0080;
         s->csr[4] |= 0x0040;
@@ -748,7 +806,7 @@
     }
 
 #if 1
-    if (((s->csr[5]>>1) & s->csr[5]) & 0x0500) 
+    if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
 #else
     if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
         (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
@@ -763,40 +821,48 @@
         printf("pcnet: INTA=%d\n", isr);
 #endif
     }
-    s->set_irq_cb(s, isr);
+    qemu_set_irq(s->irq, isr);
     s->isr = isr;
 }
 
 static void pcnet_init(PCNetState *s)
 {
     int rlen, tlen;
-    uint16_t *padr, *ladrf, mode;
+    uint16_t padr[3], ladrf[4], mode;
     uint32_t rdra, tdra;
 
 #ifdef PCNET_DEBUG
     printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
 #endif
-    
+
     if (BCR_SSIZE32(s)) {
         struct pcnet_initblk32 initblk;
         s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
                 (uint8_t *)&initblk, sizeof(initblk), 0);
-        mode = initblk.mode;
+        mode = le16_to_cpu(initblk.mode);
         rlen = initblk.rlen >> 4;
         tlen = initblk.tlen >> 4;
-        ladrf = initblk.ladrf;
-        padr = initblk.padr;
+	ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
+	ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
+	ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
+	ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
+	padr[0] = le16_to_cpu(initblk.padr[0]);
+	padr[1] = le16_to_cpu(initblk.padr[1]);
+	padr[2] = le16_to_cpu(initblk.padr[2]);
         rdra = le32_to_cpu(initblk.rdra);
         tdra = le32_to_cpu(initblk.tdra);
-        s->rdra = PHYSADDR(s,initblk.rdra);
-        s->tdra = PHYSADDR(s,initblk.tdra);
     } else {
         struct pcnet_initblk16 initblk;
         s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
                 (uint8_t *)&initblk, sizeof(initblk), 0);
-        mode = initblk.mode;
-        ladrf = initblk.ladrf;
-        padr = initblk.padr;
+        mode = le16_to_cpu(initblk.mode);
+	ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
+	ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
+	ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
+	ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
+	padr[0] = le16_to_cpu(initblk.padr[0]);
+	padr[1] = le16_to_cpu(initblk.padr[1]);
+	padr[2] = le16_to_cpu(initblk.padr[2]);
         rdra = le32_to_cpu(initblk.rdra);
         tdra = le32_to_cpu(initblk.tdra);
         rlen = rdra >> 29;
@@ -804,22 +870,22 @@
         rdra &= 0x00ffffff;
         tdra &= 0x00ffffff;
     }
-    
+
 #if defined(PCNET_DEBUG)
-    printf("rlen=%d tlen=%d\n",
-           rlen, tlen);
+    printf("rlen=%d tlen=%d\n", rlen, tlen);
 #endif
+
     CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
     CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
     s->csr[ 6] = (tlen << 12) | (rlen << 8);
-    s->csr[15] = le16_to_cpu(mode);
-    s->csr[ 8] = le16_to_cpu(ladrf[0]);
-    s->csr[ 9] = le16_to_cpu(ladrf[1]);
-    s->csr[10] = le16_to_cpu(ladrf[2]);
-    s->csr[11] = le16_to_cpu(ladrf[3]);
-    s->csr[12] = le16_to_cpu(padr[0]);
-    s->csr[13] = le16_to_cpu(padr[1]);
-    s->csr[14] = le16_to_cpu(padr[2]);
+    s->csr[15] = mode;
+    s->csr[ 8] = ladrf[0];
+    s->csr[ 9] = ladrf[1];
+    s->csr[10] = ladrf[2];
+    s->csr[11] = ladrf[3];
+    s->csr[12] = padr[0];
+    s->csr[13] = padr[1];
+    s->csr[14] = padr[2];
     s->rdra = PHYSADDR(s, rdra);
     s->tdra = PHYSADDR(s, tdra);
 
@@ -827,12 +893,12 @@
     CSR_XMTRC(s) = CSR_XMTRL(s);
 
 #ifdef PCNET_DEBUG
-    printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n", 
+    printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
         BCR_SSIZE32(s),
         s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
 #endif
 
-    s->csr[0] |= 0x0101;    
+    s->csr[0] |= 0x0101;
     s->csr[0] &= ~0x0004;       /* clear STOP bit */
 }
 
@@ -844,7 +910,7 @@
 
     if (!CSR_DTX(s))
         s->csr[0] |= 0x0010;    /* set TXON */
-        
+
     if (!CSR_DRX(s))
         s->csr[0] |= 0x0020;    /* set RXON */
 
@@ -874,15 +940,15 @@
         target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
         target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
 #else
-        target_phys_addr_t crda = s->rdra + 
+        target_phys_addr_t crda = s->rdra +
             (CSR_RCVRL(s) - CSR_RCVRC(s)) *
             (BCR_SWSTYLE(s) ? 16 : 8 );
         int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
-        target_phys_addr_t nrda = s->rdra + 
+        target_phys_addr_t nrda = s->rdra +
             (CSR_RCVRL(s) - nrdc) *
             (BCR_SWSTYLE(s) ? 16 : 8 );
         int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
-        target_phys_addr_t nnrd = s->rdra + 
+        target_phys_addr_t nnrd = s->rdra +
             (CSR_RCVRL(s) - nnrc) *
             (BCR_SWSTYLE(s) ? 16 : 8 );
 #endif
@@ -910,27 +976,27 @@
 #endif
         }
     }
-    
+
     if (CSR_CRDA(s)) {
         struct pcnet_RMD rmd;
         RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
-        CSR_CRBC(s) = rmd.rmd1.bcnt;
-        CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16;
+        CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
+        CSR_CRST(s) = rmd.status;
 #ifdef PCNET_DEBUG_RMD_X
-        printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n",
+        printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n",
                 PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
-                ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]);
+                rmd.buf_length, rmd.status, rmd.msg_length);
         PRINT_RMD(&rmd);
 #endif
     } else {
         CSR_CRBC(s) = CSR_CRST(s) = 0;
     }
-    
+
     if (CSR_NRDA(s)) {
         struct pcnet_RMD rmd;
         RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
-        CSR_NRBC(s) = rmd.rmd1.bcnt;
-        CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16;
+        CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
+        CSR_NRST(s) = rmd.status;
     } else {
         CSR_NRBC(s) = CSR_NRST(s) = 0;
     }
@@ -941,9 +1007,9 @@
 {
     s->csr[34] = s->csr[35] = 0;
     if (s->tdra) {
-        target_phys_addr_t cxda = s->tdra + 
+        target_phys_addr_t cxda = s->tdra +
             (CSR_XMTRL(s) - CSR_XMTRC(s)) *
-            (BCR_SWSTYLE(s) ? 16 : 8 );
+            (BCR_SWSTYLE(s) ? 16 : 8);
         int bad = 0;
         CHECK_TMD(PHYSADDR(s, cxda),bad);
         if (!bad) {
@@ -955,8 +1021,7 @@
             }
             s->csr[34] = cxda & 0xffff;
             s->csr[35] = cxda >> 16;
-#ifdef PCNET_DEBUG
-        } else {
+#ifdef PCNET_DEBUG_X
             printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));
 #endif
         }
@@ -965,14 +1030,14 @@
     if (CSR_CXDA(s)) {
         struct pcnet_TMD tmd;
 
-        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));                
+        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
 
-        CSR_CXBC(s) = tmd.tmd1.bcnt;
-        CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16;
+        CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT);
+        CSR_CXST(s) = tmd.status;
     } else {
         CSR_CXBC(s) = CSR_CXST(s) = 0;
     }
-    
+
     return !!(CSR_CXST(s) & 0x8000);
 }
 
@@ -981,7 +1046,7 @@
     PCNetState *s = opaque;
     if (CSR_STOP(s) || CSR_SPND(s))
         return 0;
-        
+
     if (s->recv_pos > 0)
         return 0;
 
@@ -1011,8 +1076,8 @@
         size = MIN_BUF_SIZE;
     }
 
-    if (CSR_PROM(s) 
-        || (is_padr=padr_match(s, buf, size)) 
+    if (CSR_PROM(s)
+        || (is_padr=padr_match(s, buf, size))
         || (is_bcast=padr_bcast(s, buf, size))
         || (is_ladr=ladr_match(s, buf, size))) {
 
@@ -1028,10 +1093,10 @@
                 nrda = s->rdra +
                     (CSR_RCVRL(s) - rcvrc) *
                     (BCR_SWSTYLE(s) ? 16 : 8 );
-                RMDLOAD(&rmd, PHYSADDR(s,nrda));                  
-                if (rmd.rmd1.own) {                
+                RMDLOAD(&rmd, PHYSADDR(s,nrda));
+                if (GET_FIELD(rmd.status, RMDS, OWN)) {
 #ifdef PCNET_DEBUG_RMD
-                    printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n", 
+                    printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
                                 rcvrc, CSR_RCVRC(s));
 #endif
                     CSR_RCVRC(s) = rcvrc;
@@ -1054,7 +1119,7 @@
             int pktcount = 0;
 
             memcpy(src, buf, size);
-            
+
 #if 1
             /* no need to compute the CRC */
             src[size] = 0;
@@ -1071,7 +1136,7 @@
                 while (size < 46) {
                     src[size++] = 0;
                 }
-                
+
                 while (p != &src[size]) {
                     CRC(fcs, *p++);
                 }
@@ -1086,14 +1151,15 @@
 
             RMDLOAD(&rmd, PHYSADDR(s,crda));
             /*if (!CSR_LAPPEN(s))*/
-                rmd.rmd1.stp = 1;
+                SET_FIELD(&rmd.status, RMDS, STP, 1);
 
 #define PCNET_RECV_STORE() do {                                 \
-    int count = MIN(4096 - rmd.rmd1.bcnt,size);                 \
-    target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr);     \
-    s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s));  \
+    int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),size); \
+    target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr);          \
+    s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
     src += count; size -= count;                                \
-    rmd.rmd2.mcnt = count; rmd.rmd1.own = 0;                    \
+    SET_FIELD(&rmd.msg_length, RMDM, MCNT, count);              \
+    SET_FIELD(&rmd.status, RMDS, OWN, 0);                       \
     RMDSTORE(&rmd, PHYSADDR(s,crda));                           \
     pktcount++;                                                 \
 } while (0)
@@ -1102,57 +1168,57 @@
             if ((size > 0) && CSR_NRDA(s)) {
                 target_phys_addr_t nrda = CSR_NRDA(s);
                 RMDLOAD(&rmd, PHYSADDR(s,nrda));
-                if (rmd.rmd1.own) {
+                if (GET_FIELD(rmd.status, RMDS, OWN)) {
                     crda = nrda;
                     PCNET_RECV_STORE();
                     if ((size > 0) && (nrda=CSR_NNRD(s))) {
                         RMDLOAD(&rmd, PHYSADDR(s,nrda));
-                        if (rmd.rmd1.own) {
+                        if (GET_FIELD(rmd.status, RMDS, OWN)) {
                             crda = nrda;
                             PCNET_RECV_STORE();
                         }
                     }
-                }                
+                }
             }
 
 #undef PCNET_RECV_STORE
 
             RMDLOAD(&rmd, PHYSADDR(s,crda));
             if (size == 0) {
-                rmd.rmd1.enp = 1;
-                rmd.rmd1.pam = !CSR_PROM(s) && is_padr;
-                rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
-                rmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
+                SET_FIELD(&rmd.status, RMDS, ENP, 1);
+                SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
+                SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
+                SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
             } else {
-                rmd.rmd1.oflo = 1;
-                rmd.rmd1.buff = 1;
-                rmd.rmd1.err = 1;
+                SET_FIELD(&rmd.status, RMDS, OFLO, 1);
+                SET_FIELD(&rmd.status, RMDS, BUFF, 1);
+                SET_FIELD(&rmd.status, RMDS, ERR, 1);
             }
             RMDSTORE(&rmd, PHYSADDR(s,crda));
             s->csr[0] |= 0x0400;
 
 #ifdef PCNET_DEBUG
-            printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n", 
+            printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
                 CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
 #endif
 #ifdef PCNET_DEBUG_RMD
             PRINT_RMD(&rmd);
-#endif        
+#endif
 
             while (pktcount--) {
                 if (CSR_RCVRC(s) <= 1)
                     CSR_RCVRC(s) = CSR_RCVRL(s);
                 else
-                    CSR_RCVRC(s)--;            
+                    CSR_RCVRC(s)--;
             }
-            
+
             pcnet_rdte_poll(s);
 
-        }        
+        }
     }
 
     pcnet_poll(s);
-    pcnet_update_irq(s);    
+    pcnet_update_irq(s);
 }
 
 static void pcnet_transmit(PCNetState *s)
@@ -1160,7 +1226,7 @@
     target_phys_addr_t xmit_cxda = 0;
     int count = CSR_XMTRL(s)-1;
     s->xmit_pos = -1;
-    
+
     if (!CSR_TXON(s)) {
         s->csr[0] &= ~0x0008;
         return;
@@ -1172,43 +1238,44 @@
     if (pcnet_tdte_poll(s)) {
         struct pcnet_TMD tmd;
 
-        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));                
+        TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
 
 #ifdef PCNET_DEBUG_TMD
         printf("  TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
         PRINT_TMD(&tmd);
 #endif
-        if (tmd.tmd1.stp) {
-            s->xmit_pos = 0;                
-            if (!tmd.tmd1.enp) {
-                s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr),
-                                 s->buffer, 4096 - tmd.tmd1.bcnt, 
-                                 CSR_BSWP(s));
-                s->xmit_pos += 4096 - tmd.tmd1.bcnt;
-            } 
+        if (GET_FIELD(tmd.status, TMDS, STP)) {
+            s->xmit_pos = 0;
+            if (!GET_FIELD(tmd.status, TMDS, ENP)) {
+                int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
+                s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
+                                 s->buffer, bcnt, CSR_BSWP(s));
+                s->xmit_pos += bcnt;
+            }
             xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
         }
-        if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
-            s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr),
-                             s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt, 
-                             CSR_BSWP(s));
-            s->xmit_pos += 4096 - tmd.tmd1.bcnt;
+        if (GET_FIELD(tmd.status, TMDS, ENP) && (s->xmit_pos >= 0)) {
+            int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
+            s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
+                             s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
+            s->xmit_pos += bcnt;
 #ifdef PCNET_DEBUG
             printf("pcnet_transmit size=%d\n", s->xmit_pos);
-#endif            
+#endif
             if (CSR_LOOP(s))
                 pcnet_receive(s, s->buffer, s->xmit_pos);
             else
-                qemu_send_packet(s->vc, s->buffer, s->xmit_pos);
+                if (s->vc)
+                    qemu_send_packet(s->vc, s->buffer, s->xmit_pos);
 
             s->csr[0] &= ~0x0008;   /* clear TDMD */
             s->csr[4] |= 0x0004;    /* set TXSTRT */
             s->xmit_pos = -1;
         }
 
-        tmd.tmd1.own = 0;
+        SET_FIELD(&tmd.status, TMDS, OWN, 0);
         TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
-        if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
+        if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
             s->csr[0] |= 0x0200;    /* set TINT */
 
         if (CSR_XMTRC(s)<=1)
@@ -1218,12 +1285,14 @@
         if (count--)
             goto txagain;
 
-    } else 
+    } else
     if (s->xmit_pos >= 0) {
         struct pcnet_TMD tmd;
-        TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));                
-        tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
-        tmd.tmd1.own = 0;
+        TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
+        SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
+        SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
+        SET_FIELD(&tmd.status, TMDS, ERR, 1);
+        SET_FIELD(&tmd.status, TMDS, OWN, 0);
         TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
         s->csr[0] |= 0x0200;    /* set TINT */
         if (!CSR_DXSUFLO(s)) {
@@ -1242,7 +1311,7 @@
         pcnet_rdte_poll(s);
     }
 
-    if (CSR_TDMD(s) || 
+    if (CSR_TDMD(s) ||
         (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
     {
         /* prevent recursion */
@@ -1263,7 +1332,7 @@
         pcnet_transmit(s);
     }
 
-    pcnet_update_irq(s);    
+    pcnet_update_irq(s);
 
     if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
         uint64_t now = qemu_get_clock(vm_clock) * 33;
@@ -1277,7 +1346,7 @@
             } else
                 CSR_POLL(s) = t;
         }
-        qemu_mod_timer(s->poll_timer, 
+        qemu_mod_timer(s->poll_timer,
             pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock)));
     }
 }
@@ -1310,7 +1379,7 @@
         if (!CSR_STRT(s) && (val & 2))
             pcnet_start(s);
 
-        if (CSR_TDMD(s)) 
+        if (CSR_TDMD(s))
             pcnet_transmit(s);
 
         return;
@@ -1365,11 +1434,11 @@
     case 3:
         break;
     case 4:
-        s->csr[4] &= ~(val & 0x026a); 
+        s->csr[4] &= ~(val & 0x026a);
         val &= ~0x026a; val |= s->csr[4] & 0x026a;
         break;
     case 5:
-        s->csr[5] &= ~(val & 0x0a90); 
+        s->csr[5] &= ~(val & 0x0a90);
         val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
         break;
     case 16:
@@ -1484,7 +1553,7 @@
     return val;
 }
 
-void pcnet_h_reset(void *opaque)
+static void pcnet_h_reset(void *opaque)
 {
     PCNetState *s = opaque;
     int i;
@@ -1492,7 +1561,8 @@
 
     /* Initialize the PROM */
 
-    memcpy(s->prom, s->nd->macaddr, 6);
+    if (s->nd)
+        memcpy(s->prom, s->nd->macaddr, 6);
     s->prom[12] = s->prom[13] = 0x00;
     s->prom[14] = s->prom[15] = 0x57;
 
@@ -1522,11 +1592,11 @@
     PCNetState *s = opaque;
 #ifdef PCNET_DEBUG
     printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
-#endif    
+#endif
     /* Check APROMWE bit to enable write access */
     if (pcnet_bcr_readw(s,2) & 0x80)
         s->prom[addr & 15] = val;
-}       
+}
 
 static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
 {
@@ -1615,7 +1685,7 @@
         pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
 #ifdef PCNET_DEBUG_IO
         printf("device switched into dword i/o mode\n");
-#endif        
+#endif
     }
     pcnet_update_irq(s);
 }
@@ -1625,7 +1695,7 @@
     PCNetState *s = opaque;
     uint32_t val = -1;
     pcnet_poll_timer(s);
-    if (BCR_DWIO(s)) {  
+    if (BCR_DWIO(s)) {
         switch (addr & 0x0f) {
         case 0x00: /* RDP */
             val = pcnet_csr_readw(s, s->rap);
@@ -1649,7 +1719,7 @@
     return val;
 }
 
-static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, 
+static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
                              uint32_t addr, uint32_t size, int type)
 {
     PCNetState *d = (PCNetState *)pci_dev;
@@ -1660,7 +1730,7 @@
 
     register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
     register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
-    
+
     register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
     register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
     register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
@@ -1677,7 +1747,7 @@
         pcnet_aprom_writeb(d, addr & 0x0f, val);
 }
 
-static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) 
+static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
 {
     PCNetState *d = opaque;
     uint32_t val = -1;
@@ -1704,7 +1774,7 @@
     }
 }
 
-static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) 
+static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
 {
     PCNetState *d = opaque;
     uint32_t val = -1;
@@ -1739,7 +1809,7 @@
     }
 }
 
-static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) 
+static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
 {
     PCNetState *d = opaque;
     uint32_t val;
@@ -1828,18 +1898,21 @@
 
     d->nd = nd;
 
-    d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, 
-                                 pcnet_can_receive, d);
-    
-    snprintf(d->vc->info_str, sizeof(d->vc->info_str),
-             "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
-             d->nd->macaddr[0],
-             d->nd->macaddr[1],
-             d->nd->macaddr[2],
-             d->nd->macaddr[3],
-             d->nd->macaddr[4],
-             d->nd->macaddr[5]);
+    if (nd && nd->vlan) {
+        d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive,
+                                     pcnet_can_receive, d);
 
+        snprintf(d->vc->info_str, sizeof(d->vc->info_str),
+                 "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+                 d->nd->macaddr[0],
+                 d->nd->macaddr[1],
+                 d->nd->macaddr[2],
+                 d->nd->macaddr[3],
+                 d->nd->macaddr[4],
+                 d->nd->macaddr[5]);
+    } else {
+        d->vc = NULL;
+    }
     pcnet_h_reset(d);
     register_savevm("pcnet", 0, 2, pcnet_save, pcnet_load, d);
 }
@@ -1858,7 +1931,7 @@
     (CPUReadMemoryFunc *)&pcnet_mmio_readl
 };
 
-static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, 
+static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
                             uint32_t addr, uint32_t size, int type)
 {
     PCNetState *d = (PCNetState *)pci_dev;
@@ -1870,13 +1943,6 @@
     cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index);
 }
 
-static void pcnet_pci_set_irq_cb(void *opaque, int isr)
-{
-    PCNetState *s = opaque;
-
-    pci_set_irq(&s->dev, 0, isr);
-}
-
 static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
                                       uint8_t *buf, int len, int do_bswap)
 {
@@ -1895,28 +1961,28 @@
     uint8_t *pci_conf;
 
 #if 0
-    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", 
+    printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
         sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
 #endif
 
     d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
                                           devfn, NULL, NULL);
-                                          
+
     pci_conf = d->dev.config;
-    
+
     *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022);
-    *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000);    
-    *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); 
+    *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000);
+    *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007);
     *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280);
     pci_conf[0x08] = 0x10;
     pci_conf[0x09] = 0x00;
-    pci_conf[0x0a] = 0x00; // ethernet network controller 
+    pci_conf[0x0a] = 0x00; // ethernet network controller
     pci_conf[0x0b] = 0x02;
     pci_conf[0x0e] = 0x00; // header_type
-    
+
     *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001);
     *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000);
-    
+
     pci_conf[0x3d] = 1; // interrupt pin 0
     pci_conf[0x3e] = 0x06;
     pci_conf[0x3f] = 0xff;
@@ -1925,13 +1991,13 @@
     d->mmio_index =
       cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d);
 
-    pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, 
+    pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
                            PCI_ADDRESS_SPACE_IO, pcnet_ioport_map);
-                           
-    pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, 
+
+    pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
                            PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
-                           
-    d->set_irq_cb = pcnet_pci_set_irq_cb;
+
+    d->irq = d->dev.irq[0];
     d->phys_mem_read = pci_physical_memory_read;
     d->phys_mem_write = pci_physical_memory_write;
     d->pci_dev = &d->dev;
@@ -1943,46 +2009,70 @@
 
 #if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure
 
+static void parent_lance_reset(void *opaque, int irq, int level)
+{
+    if (level)
+        pcnet_h_reset(opaque);
+}
+
+static void lance_mem_writew(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+#ifdef PCNET_DEBUG_IO
+    printf("lance_mem_writew addr=" TARGET_FMT_plx " val=0x%04x\n", addr,
+           val & 0xffff);
+#endif
+    pcnet_ioport_writew(opaque, addr & 7, val & 0xffff);
+}
+
+static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+    uint32_t val;
+
+    val = pcnet_ioport_readw(opaque, addr & 7);
+#ifdef PCNET_DEBUG_IO
+    printf("pcnet_mmio_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr,
+           val & 0xffff);
+#endif
+
+    return val & 0xffff;
+}
+
 static CPUReadMemoryFunc *lance_mem_read[3] = {
-    (CPUReadMemoryFunc *)&pcnet_ioport_readw,
-    (CPUReadMemoryFunc *)&pcnet_ioport_readw,
-    (CPUReadMemoryFunc *)&pcnet_ioport_readw,
+    lance_mem_readw,
+    lance_mem_readw,
+    lance_mem_readw,
 };
 
 static CPUWriteMemoryFunc *lance_mem_write[3] = {
-    (CPUWriteMemoryFunc *)&pcnet_ioport_writew,
-    (CPUWriteMemoryFunc *)&pcnet_ioport_writew,
-    (CPUWriteMemoryFunc *)&pcnet_ioport_writew,
+    lance_mem_writew,
+    lance_mem_writew,
+    lance_mem_writew,
 };
 
-static void pcnet_sparc_set_irq_cb(void *opaque, int isr)
-{
-    PCNetState *s = opaque;
-
-    ledma_set_irq(s->dma_opaque, isr);
-}
-
-void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque)
+void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,
+                qemu_irq irq, qemu_irq *reset)
 {
     PCNetState *d;
     int lance_io_memory;
 
     d = qemu_mallocz(sizeof(PCNetState));
     if (!d)
-        return NULL;
+        return;
 
     lance_io_memory =
         cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d);
 
     d->dma_opaque = dma_opaque;
+
+    *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1);
+
     cpu_register_physical_memory(leaddr, 4, lance_io_memory);
 
-    d->set_irq_cb = pcnet_sparc_set_irq_cb;
+    d->irq = irq;
     d->phys_mem_read = ledma_memory_read;
     d->phys_mem_write = ledma_memory_write;
 
     pcnet_common_init(d, nd, "lance");
-
-    return d;
 }
 #endif /* TARGET_SPARC */
diff --git a/hw/pcspk.c b/hw/pcspk.c
index 0d52b31..2cbeff3 100644
--- a/hw/pcspk.c
+++ b/hw/pcspk.c
@@ -92,7 +92,7 @@
     }
 }
 
-int pcspk_audio_init(AudioState *audio)
+int pcspk_audio_init(AudioState *audio, qemu_irq *pic)
 {
     PCSpkState *s = &pcspk_state;
     audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
index 0db8b56..08f8890 100644
--- a/hw/pflash_cfi02.c
+++ b/hw/pflash_cfi02.c
@@ -1,6 +1,6 @@
 /*
  *  CFI parallel flash with AMD command set emulation
- * 
+ *
  *  Copyright (c) 2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
@@ -50,9 +50,9 @@
 
 struct pflash_t {
     BlockDriverState *bs;
-    target_ulong base;
-    target_ulong sector_len;
-    target_ulong total_len;
+    target_phys_addr_t base;
+    uint32_t sector_len;
+    uint32_t total_len;
     int width;
     int wcycle; /* if 0, the flash is read normally */
     int bypass;
@@ -85,13 +85,13 @@
     pfl->cmd = 0;
 }
 
-static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
+static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width)
 {
-    target_ulong boff;
+    uint32_t boff;
     uint32_t ret;
     uint8_t *p;
 
-    DPRINTF("%s: offset %08x\n", __func__, offset);
+    DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset);
     ret = -1;
     offset -= pfl->base;
     boff = offset & 0xFF;
@@ -161,7 +161,7 @@
         default:
             goto flash_read;
         }
-        DPRINTF("%s: ID %d %x\n", __func__, boff, ret);
+        DPRINTF("%s: ID " TARGET_FMT_ld " %x\n", __func__, boff, ret);
         break;
     case 0xA0:
     case 0x10:
@@ -185,7 +185,7 @@
 }
 
 /* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset, 
+static void pflash_update(pflash_t *pfl, int offset,
                           int size)
 {
     int offset_end;
@@ -194,32 +194,37 @@
         /* round to sectors */
         offset = offset >> 9;
         offset_end = (offset_end + 511) >> 9;
-        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9), 
+        bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
                    offset_end - offset);
     }
 }
 
-static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value,
+static void pflash_write (pflash_t *pfl, uint32_t offset, uint32_t value,
                           int width)
 {
-    target_ulong boff;
+    uint32_t boff;
     uint8_t *p;
     uint8_t cmd;
 
     /* WARNING: when the memory area is in ROMD mode, the offset is a
        ram offset, not a physical address */
-    if (pfl->wcycle == 0)
-        offset -= (target_ulong)(long)pfl->storage;
-    else
-        offset -= pfl->base;
-        
     cmd = value;
-    DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width);
     if (pfl->cmd != 0xA0 && cmd == 0xF0) {
+#if 0
         DPRINTF("%s: flash reset asked (%02x %02x)\n",
                 __func__, pfl->cmd, cmd);
+#endif
         goto reset_flash;
     }
+    DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__,
+            offset, value, width, pfl->wcycle);
+    if (pfl->wcycle == 0)
+        offset -= (uint32_t)(long)pfl->storage;
+    else
+        offset -= pfl->base;
+
+    DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__,
+            offset, value, width);
     /* Set the device in I/O access mode */
     cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
     boff = offset & (pfl->sector_len - 1);
@@ -239,7 +244,7 @@
             return;
         }
         if (boff != 0x555 || cmd != 0xAA) {
-            DPRINTF("%s: unlock0 failed %04x %02x %04x\n",
+            DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n",
                     __func__, boff, cmd, 0x555);
             goto reset_flash;
         }
@@ -249,7 +254,8 @@
         /* We started an unlock sequence */
     check_unlock1:
         if (boff != 0x2AA || cmd != 0x55) {
-            DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd);
+            DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__,
+                    boff, cmd);
             goto reset_flash;
         }
         DPRINTF("%s: unlock sequence done\n", __func__);
@@ -257,7 +263,8 @@
     case 2:
         /* We finished an unlock sequence */
         if (!pfl->bypass && boff != 0x555) {
-            DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd);
+            DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__,
+                    boff, cmd);
             goto reset_flash;
         }
         switch (cmd) {
@@ -281,7 +288,7 @@
             /* We need another unlock sequence */
             goto check_unlock0;
         case 0xA0:
-            DPRINTF("%s: write data offset %08x %08x %d\n",
+            DPRINTF("%s: write data offset " TARGET_FMT_lx " %08x %d\n",
                     __func__, offset, value, width);
             p = pfl->storage;
             switch (width) {
@@ -352,7 +359,7 @@
         switch (cmd) {
         case 0x10:
             if (boff != 0x555) {
-                DPRINTF("%s: chip erase: invalid address %04x\n",
+                DPRINTF("%s: chip erase: invalid address " TARGET_FMT_lx "\n",
                         __func__, offset);
                 goto reset_flash;
             }
@@ -362,19 +369,20 @@
             pfl->status = 0x00;
             pflash_update(pfl, 0, pfl->total_len);
             /* Let's wait 5 seconds before chip erase is done */
-            qemu_mod_timer(pfl->timer, 
+            qemu_mod_timer(pfl->timer,
                            qemu_get_clock(vm_clock) + (ticks_per_sec * 5));
             break;
         case 0x30:
             /* Sector erase */
             p = pfl->storage;
             offset &= ~(pfl->sector_len - 1);
-            DPRINTF("%s: start sector erase at %08x\n", __func__, offset);
+            DPRINTF("%s: start sector erase at " TARGET_FMT_lx "\n", __func__,
+                    offset);
             memset(p + offset, 0xFF, pfl->sector_len);
             pflash_update(pfl, offset, pfl->sector_len);
             pfl->status = 0x00;
             /* Let's wait 1/2 second before sector erase is done */
-            qemu_mod_timer(pfl->timer, 
+            qemu_mod_timer(pfl->timer,
                            qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
             break;
         default:
@@ -412,10 +420,8 @@
 
     /* Reset flash */
  reset_flash:
-    if (pfl->wcycle != 0) {
-        cpu_register_physical_memory(pfl->base, pfl->total_len,
-                                     pfl->off | IO_MEM_ROMD | pfl->fl_mem);
-    }
+    cpu_register_physical_memory(pfl->base, pfl->total_len,
+                                 pfl->off | IO_MEM_ROMD | pfl->fl_mem);
     pfl->bypass = 0;
     pfl->wcycle = 0;
     pfl->cmd = 0;
@@ -515,25 +521,28 @@
     return ret;
 }
 
-pflash_t *pflash_register (target_ulong base, ram_addr_t off,
+pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off,
                            BlockDriverState *bs,
-                           target_ulong sector_len, int nb_blocs, int width,
-                           uint16_t id0, uint16_t id1, 
+                           uint32_t sector_len, int nb_blocs, int width,
+                           uint16_t id0, uint16_t id1,
                            uint16_t id2, uint16_t id3)
 {
     pflash_t *pfl;
-    target_long total_len;
+    int32_t total_len;
 
     total_len = sector_len * nb_blocs;
     /* XXX: to be fixed */
+#if 0
     if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
         total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
         return NULL;
+#endif
     pfl = qemu_mallocz(sizeof(pflash_t));
     if (pfl == NULL)
         return NULL;
     pfl->storage = phys_ram_base + off;
-    pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl);
+    pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops,
+                                         pfl);
     pfl->off = off;
     cpu_register_physical_memory(base, total_len,
                                  off | pfl->fl_mem | IO_MEM_ROMD);
@@ -609,7 +618,9 @@
     pfl->cfi_table[0x28] = 0x02;
     pfl->cfi_table[0x29] = 0x00;
     /* Max number of bytes in multi-bytes write */
-    pfl->cfi_table[0x2A] = 0x05;
+    /* XXX: disable buffered write as it's not supported */
+    //    pfl->cfi_table[0x2A] = 0x05;
+    pfl->cfi_table[0x2A] = 0x00;
     pfl->cfi_table[0x2B] = 0x00;
     /* Number of erase block regions (uniform) */
     pfl->cfi_table[0x2C] = 0x01;
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 1b16652..8c00f0d 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -2,7 +2,7 @@
  * QEMU i440FX/PIIX3 PCI Bridge Emulation
  *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -40,7 +40,7 @@
     return s->config_reg;
 }
 
-static void piix3_set_irq(void *pic, int irq_num, int level);
+static void piix3_set_irq(qemu_irq *pic, int irq_num, int level);
 
 /* return the global irq number corresponding to a given device irq
    pin. We could also use the bus number to have a more precise
@@ -63,19 +63,19 @@
     switch(r) {
     case 3:
         /* RAM */
-        cpu_register_physical_memory(start, end - start, 
+        cpu_register_physical_memory(start, end - start,
                                      start);
         break;
     case 1:
         /* ROM (XXX: not quite correct) */
-        cpu_register_physical_memory(start, end - start, 
+        cpu_register_physical_memory(start, end - start,
                                      start | IO_MEM_ROM);
         break;
     case 2:
     case 0:
         /* XXX: should distinguish read/write cases */
         for(addr = start; addr < end; addr += 4096) {
-            cpu_register_physical_memory(addr, 4096, 
+            cpu_register_physical_memory(addr, 4096,
                                          isa_page_descs[(addr - 0xa0000) >> 12]);
         }
         break;
@@ -97,7 +97,7 @@
         cpu_register_physical_memory(0xa0000, 0x20000, 0xa0000);
     } else {
         for(addr = 0xa0000; addr < 0xc0000; addr += 4096) {
-            cpu_register_physical_memory(addr, 4096, 
+            cpu_register_physical_memory(addr, 4096,
                                          isa_page_descs[(addr - 0xa0000) >> 12]);
         }
     }
@@ -124,7 +124,7 @@
     }
 }
 
-static void i440fx_write_config(PCIDevice *d, 
+static void i440fx_write_config(PCIDevice *d,
                                 uint32_t address, uint32_t val, int len)
 {
     /* XXX: implement SMRAM.D_LOCK */
@@ -155,14 +155,14 @@
     return 0;
 }
 
-PCIBus *i440fx_init(PCIDevice **pi440fx_state)
+PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
 {
     PCIBus *b;
     PCIDevice *d;
     I440FXState *s;
 
     s = qemu_mallocz(sizeof(I440FXState));
-    b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0, 4);
+    b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, pic, 0, 4);
     s->bus = b;
 
     register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
@@ -175,7 +175,7 @@
     register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
     register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
 
-    d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0, 
+    d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
                             NULL, i440fx_write_config);
 
     d->config[0x00] = 0x86; // vendor_id
@@ -204,7 +204,7 @@
 
 static int pci_irq_levels[4];
 
-static void piix3_set_irq(void *pic, int irq_num, int level)
+static void piix3_set_irq(qemu_irq *pic, int irq_num, int level)
 {
     int i, pic_irq, pic_level;
 
@@ -221,7 +221,7 @@
             if (pic_irq == piix3_dev->config[0x60 + i])
                 pic_level |= pci_irq_levels[i];
         }
-        pic_set_irq(pic_irq, pic_level);
+        qemu_set_irq(pic[pic_irq], pic_level);
     }
 }
 
diff --git a/hw/pixel_ops.h b/hw/pixel_ops.h
new file mode 100644
index 0000000..d390adf
--- /dev/null
+++ b/hw/pixel_ops.h
@@ -0,0 +1,53 @@
+static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g,
+                                         unsigned int b)
+{
+    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
+}
+
+static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
+}
+
+static inline unsigned int rgb_to_pixel15bgr(unsigned int r, unsigned int g,
+                                             unsigned int b)
+{
+    return ((b >> 3) << 10) | ((g >> 3) << 5) | (r >> 3);
+}
+
+static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
+}
+
+static inline unsigned int rgb_to_pixel16bgr(unsigned int r, unsigned int g,
+                                             unsigned int b)
+{
+    return ((b >> 3) << 11) | ((g >> 2) << 5) | (r >> 3);
+}
+
+static inline unsigned int rgb_to_pixel24(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    return (r << 16) | (g << 8) | b;
+}
+
+static inline unsigned int rgb_to_pixel24bgr(unsigned int r, unsigned int g,
+                                             unsigned int b)
+{
+    return (b << 16) | (g << 8) | r;
+}
+
+static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    return (r << 16) | (g << 8) | b;
+}
+
+static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g,
+                                             unsigned int b)
+{
+    return (b << 16) | (g << 8) | r;
+}
diff --git a/hw/pl011.c b/hw/pl011.c
index fb7ab7b..94ed699 100644
--- a/hw/pl011.c
+++ b/hw/pl011.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Arm PrimeCell PL011 UART
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -27,8 +27,7 @@
     int read_count;
     int read_trigger;
     CharDriverState *chr;
-    void *pic;
-    int irq;
+    qemu_irq irq;
 } pl011_state;
 
 #define PL011_INT_TX 0x20
@@ -45,9 +44,9 @@
 static void pl011_update(pl011_state *s)
 {
     uint32_t flags;
-    
+
     flags = s->int_level & s->int_enabled;
-    pic_set_irq_new(s->pic, s->irq, flags != 0);
+    qemu_set_irq(s->irq, flags != 0);
 }
 
 static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
@@ -177,7 +176,7 @@
     }
 }
 
-static int pl011_can_recieve(void *opaque)
+static int pl011_can_receive(void *opaque)
 {
     pl011_state *s = (pl011_state *)opaque;
 
@@ -187,7 +186,7 @@
         return s->read_count < 1;
 }
 
-static void pl011_recieve(void *opaque, const uint8_t *buf, int size)
+static void pl011_receive(void *opaque, const uint8_t *buf, int size)
 {
     pl011_state *s = (pl011_state *)opaque;
     int slot;
@@ -224,7 +223,7 @@
    pl011_write
 };
 
-void pl011_init(uint32_t base, void *pic, int irq,
+void pl011_init(uint32_t base, qemu_irq irq,
                 CharDriverState *chr)
 {
     int iomemtype;
@@ -233,17 +232,16 @@
     s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
     iomemtype = cpu_register_io_memory(0, pl011_readfn,
                                        pl011_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     s->chr = chr;
     s->read_trigger = 1;
     s->ifl = 0x12;
     s->cr = 0x300;
     s->flags = 0x90;
-    if (chr){ 
-        qemu_chr_add_handlers(chr, pl011_can_recieve, pl011_recieve,
+    if (chr){
+        qemu_chr_add_handlers(chr, pl011_can_receive, pl011_receive,
                               pl011_event, s);
     }
     /* ??? Save/restore.  */
diff --git a/hw/pl031.c b/hw/pl031.c
new file mode 100644
index 0000000..7e8098b
--- /dev/null
+++ b/hw/pl031.c
@@ -0,0 +1,219 @@
+/*
+ * ARM AMBA PrimeCell PL031 RTC
+ *
+ * Copyright (c) 2007 CodeSourcery
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include"vl.h"
+
+//#define DEBUG_PL031
+
+#ifdef DEBUG_PL031
+#define DPRINTF(fmt, args...) \
+do { printf("pl031: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+#define RTC_DR      0x00    /* Data read register */
+#define RTC_MR      0x04    /* Match register */
+#define RTC_LR      0x08    /* Data load register */
+#define RTC_CR      0x0c    /* Control register */
+#define RTC_IMSC    0x10    /* Interrupt mask and set register */
+#define RTC_RIS     0x14    /* Raw interrupt status register */
+#define RTC_MIS     0x18    /* Masked interrupt status register */
+#define RTC_ICR     0x1c    /* Interrupt clear register */
+
+typedef struct {
+    QEMUTimer *timer;
+    qemu_irq irq;
+    uint32_t base;
+
+    uint64_t start_time;
+    uint32_t tick_offset;
+
+    uint32_t mr;
+    uint32_t lr;
+    uint32_t cr;
+    uint32_t im;
+    uint32_t is;
+} pl031_state;
+
+static const unsigned char pl031_id[] = {
+    0x31, 0x10, 0x14, 0x00,         /* Device ID        */
+    0x0d, 0xf0, 0x05, 0xb1          /* Cell ID      */
+};
+
+static void pl031_update(pl031_state *s)
+{
+    qemu_set_irq(s->irq, s->is & s->im);
+}
+
+static void pl031_interrupt(void * opaque)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+    s->im = 1;
+    DPRINTF("Alarm raised\n");
+    pl031_update(s);
+}
+
+static uint32_t pl031_get_count(pl031_state *s)
+{
+    /* This assumes qemu_get_clock returns the time since the machine was
+       created.  */
+    return s->tick_offset + qemu_get_clock(vm_clock) / ticks_per_sec;
+}
+
+static void pl031_set_alarm(pl031_state *s)
+{
+    int64_t now;
+    uint32_t ticks;
+
+    now = qemu_get_clock(vm_clock);
+    ticks = s->tick_offset + now / ticks_per_sec;
+
+    /* The timer wraps around.  This subtraction also wraps in the same way,
+       and gives correct results when alarm < now_ticks.  */
+    ticks = s->mr - ticks;
+    DPRINTF("Alarm set in %ud ticks\n", ticks);
+    if (ticks == 0) {
+        qemu_del_timer(s->timer);
+        pl031_interrupt(s);
+    } else {
+        qemu_mod_timer(s->timer, now + (int64_t)ticks * ticks_per_sec);
+    }
+}
+
+static uint32_t pl031_read(void *opaque, target_phys_addr_t offset)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+    offset -= s->base;
+
+    if (offset >= 0xfe0  &&  offset < 0x1000)
+        return pl031_id[(offset - 0xfe0) >> 2];
+
+    switch (offset) {
+    case RTC_DR:
+        return pl031_get_count(s);
+    case RTC_MR:
+        return s->mr;
+    case RTC_IMSC:
+        return s->im;
+    case RTC_RIS:
+        return s->is;
+    case RTC_LR:
+        return s->lr;
+    case RTC_CR:
+        /* RTC is permanently enabled.  */
+        return 1;
+    case RTC_MIS:
+        return s->is & s->im;
+    case RTC_ICR:
+        fprintf(stderr, "qemu: pl031_read: Unexpected offset 0x%x\n",
+                (int)offset);
+        break;
+    default:
+        cpu_abort(cpu_single_env, "pl031_read: Bad offset 0x%x\n",
+                  (int)offset);
+        break;
+    }
+
+    return 0;
+}
+
+static void pl031_write(void * opaque, target_phys_addr_t offset,
+                        uint32_t value)
+{
+    pl031_state *s = (pl031_state *)opaque;
+
+    offset -= s->base;
+
+    switch (offset) {
+    case RTC_LR:
+        s->tick_offset += value - pl031_get_count(s);
+        pl031_set_alarm(s);
+        break;
+    case RTC_MR:
+        s->mr = value;
+        pl031_set_alarm(s);
+        break;
+    case RTC_IMSC:
+        s->im = value & 1;
+        DPRINTF("Interrupt mask %d\n", s->im);
+        pl031_update(s);
+        break;
+    case RTC_ICR:
+        /* The PL031 documentation (DDI0224B) states that the interupt is
+           cleared when bit 0 of the written value is set.  However the
+           arm926e documentation (DDI0287B) states that the interrupt is
+           cleared when any value is written.  */
+        DPRINTF("Interrupt cleared");
+        s->is = 0;
+        pl031_update(s);
+        break;
+    case RTC_CR:
+        /* Written value is ignored.  */
+        break;
+
+    case RTC_DR:
+    case RTC_MIS:
+    case RTC_RIS:
+        fprintf(stderr, "qemu: pl031_write: Unexpected offset 0x%x\n",
+                (int)offset);
+        break;
+
+    default:
+        cpu_abort(cpu_single_env, "pl031_write: Bad offset 0x%x\n",
+                  (int)offset);
+        break;
+    }
+}
+
+static CPUWriteMemoryFunc * pl031_writefn[] = {
+    pl031_write,
+    pl031_write,
+    pl031_write
+};
+
+static CPUReadMemoryFunc * pl031_readfn[] = {
+    pl031_read,
+    pl031_read,
+    pl031_read
+};
+
+void pl031_init(uint32_t base, qemu_irq irq)
+{
+    int iomemtype;
+    pl031_state *s;
+    time_t ti;
+    struct tm *tm;
+
+    s = qemu_mallocz(sizeof(pl031_state));
+    if (!s)
+        cpu_abort(cpu_single_env, "pl031_init: Out of memory\n");
+
+    iomemtype = cpu_register_io_memory(0, pl031_readfn, pl031_writefn, s);
+    if (iomemtype == -1)
+        cpu_abort(cpu_single_env, "pl031_init: Can't register I/O memory\n");
+
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+
+    s->base = base;
+    s->irq  = irq;
+    /* ??? We assume vm_clock is zero at this point.  */
+    time(&ti);
+    if (rtc_utc)
+        tm = gmtime(&ti);
+    else
+        tm = localtime(&ti);
+    s->tick_offset = mktime(tm);
+
+    s->timer = qemu_new_timer(vm_clock, pl031_interrupt, s);
+}
diff --git a/hw/pl050.c b/hw/pl050.c
index 20451e5..b3a2797 100644
--- a/hw/pl050.c
+++ b/hw/pl050.c
@@ -1,7 +1,7 @@
-/* 
+/*
  * Arm PrimeCell PL050 Keyboard / Mouse Interface
  *
- * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
  * This code is licenced under the GPL.
@@ -15,12 +15,19 @@
     uint32_t cr;
     uint32_t clk;
     uint32_t last;
-    void *pic;
     int pending;
-    int irq;
+    qemu_irq irq;
     int is_mouse;
 } pl050_state;
 
+#define PL050_TXEMPTY         (1 << 6)
+#define PL050_TXBUSY          (1 << 5)
+#define PL050_RXFULL          (1 << 4)
+#define PL050_RXBUSY          (1 << 3)
+#define PL050_RXPARITY        (1 << 2)
+#define PL050_KMIC            (1 << 1)
+#define PL050_KMID            (1 << 0)
+
 static const unsigned char pl050_id[] =
 { 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
 
@@ -32,7 +39,7 @@
     s->pending = level;
     raise = (s->pending && (s->cr & 0x10) != 0)
             || (s->cr & 0x08) != 0;
-    pic_set_irq_new(s->pic, s->irq, raise);
+    qemu_set_irq(s->irq, raise);
 }
 
 static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
@@ -46,11 +53,22 @@
     case 0: /* KMICR */
         return s->cr;
     case 1: /* KMISTAT */
-        /* KMIC and KMID bits not implemented.  */
-        if (s->pending) {
-            return 0x10;
-        } else {
-            return 0;
+        {
+            uint8_t val;
+            uint32_t stat;
+
+            val = s->last;
+            val = val ^ (val >> 4);
+            val = val ^ (val >> 2);
+            val = (val ^ (val >> 1)) & 1;
+
+            stat = PL050_TXEMPTY;
+            if (val)
+                stat |= PL050_RXPARITY;
+            if (s->pending)
+                stat |= PL050_RXFULL;
+
+            return stat;
         }
     case 2: /* KMIDATA */
         if (s->pending)
@@ -105,7 +123,7 @@
    pl050_write
 };
 
-void pl050_init(uint32_t base, void *pic, int irq, int is_mouse)
+void pl050_init(uint32_t base, qemu_irq irq, int is_mouse)
 {
     int iomemtype;
     pl050_state *s;
@@ -113,9 +131,8 @@
     s = (pl050_state *)qemu_mallocz(sizeof(pl050_state));
     iomemtype = cpu_register_io_memory(0, pl050_readfn,
                                        pl050_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     s->is_mouse = is_mouse;
     if (is_mouse)
diff --git a/hw/pl080.c b/hw/pl080.c
index 549b3bf..b24cfba 100644
--- a/hw/pl080.c
+++ b/hw/pl080.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Arm PrimeCell PL080/PL081 DMA controller
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -49,8 +49,7 @@
     int nchannels;
     /* Flag to avoid recursive DMA invocations.  */
     int running;
-    void *pic;
-    int irq;
+    qemu_irq irq;
 } pl080_state;
 
 static const unsigned char pl080_id[] =
@@ -63,9 +62,9 @@
 {
     if ((s->tc_int & s->tc_mask)
             || (s->err_int & s->err_mask))
-        pic_set_irq_new(s->pic, s->irq, 1);
+        qemu_irq_raise(s->irq);
     else
-        pic_set_irq_new(s->pic, s->irq, 1);
+        qemu_irq_lower(s->irq);
 }
 
 static void pl080_run(pl080_state *s)
@@ -112,7 +111,7 @@
                 continue;
             flow = (ch->conf >> 11) & 7;
             if (flow >= 4) {
-                cpu_abort(cpu_single_env, 
+                cpu_abort(cpu_single_env,
                     "pl080_run: Peripheral flow control not implemented\n");
             }
             src_id = (ch->conf >> 1) & 0x1f;
@@ -325,7 +324,7 @@
 
 /* The PL080 and PL081 are the same except for the number of channels
    they implement (8 and 2 respectively).  */
-void *pl080_init(uint32_t base, void *pic, int irq, int nchannels)
+void *pl080_init(uint32_t base, qemu_irq irq, int nchannels)
 {
     int iomemtype;
     pl080_state *s;
@@ -333,9 +332,8 @@
     s = (pl080_state *)qemu_mallocz(sizeof(pl080_state));
     iomemtype = cpu_register_io_memory(0, pl080_readfn,
                                        pl080_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     s->nchannels = nchannels;
     /* ??? Save/restore.  */
diff --git a/hw/pl110.c b/hw/pl110.c
index 16de16c..061ec7a 100644
--- a/hw/pl110.c
+++ b/hw/pl110.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Arm PrimeCell PL110 Color LCD Controller
  *
  * Copyright (c) 2005-2006 CodeSourcery.
@@ -29,7 +29,6 @@
     DisplayState *ds;
     /* The Versatile/PB uses a slightly modified PL110 controller.  */
     int versatile;
-    void *pic;
     uint32_t timing[4];
     uint32_t cr;
     uint32_t upbase;
@@ -42,7 +41,7 @@
     int invalidate;
     uint32_t pallette[256];
     uint32_t raw_pallette[128];
-    int irq;
+    qemu_irq irq;
 } pl110_state;
 
 static const unsigned char pl110_id[] =
@@ -118,7 +117,7 @@
 
     if (!pl110_enabled(s))
         return;
-    
+
     switch (s->ds->depth) {
     case 0:
         return;
@@ -152,7 +151,7 @@
       fn = fntable[s->bpp + 12];
     else
       fn = fntable[s->bpp];
-    
+
     src_width = s->cols;
     switch (s->bpp) {
     case BPP_1:
@@ -303,8 +302,12 @@
     case 5: /* LCDLPBASE */
         return s->lpbase;
     case 6: /* LCDIMSC */
+	if (s->versatile)
+	  return s->cr;
         return s->int_mask;
     case 7: /* LCDControl */
+	if (s->versatile)
+	  return s->int_mask;
         return s->cr;
     case 8: /* LCDRIS */
         return s->int_status;
@@ -399,7 +402,7 @@
    pl110_write
 };
 
-void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq,
+void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq,
                  int versatile)
 {
     pl110_state *s;
@@ -408,11 +411,10 @@
     s = (pl110_state *)qemu_mallocz(sizeof(pl110_state));
     iomemtype = cpu_register_io_memory(0, pl110_readfn,
                                        pl110_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
     s->base = base;
     s->ds = ds;
     s->versatile = versatile;
-    s->pic = pic;
     s->irq = irq;
     graphic_console_init(ds, pl110_update_display, pl110_invalidate_display,
                          NULL, s);
diff --git a/hw/pl110_template.h b/hw/pl110_template.h
index ed533ac..f7cb1f4 100644
--- a/hw/pl110_template.h
+++ b/hw/pl110_template.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * Arm PrimeCell PL110 Color LCD Controller
  *
  * Copyright (c) 2005 CodeSourcery, LLC.
@@ -15,7 +15,7 @@
 #define COPY_PIXEL(to, from) *(to++) = from
 #elif BITS == 15 || BITS == 16
 #define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2;
-#elif BITS == 24 
+#elif BITS == 24
 #define COPY_PIXEL(to, from) \
   *(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16
 #elif BITS == 32
diff --git a/hw/pl181.c b/hw/pl181.c
new file mode 100644
index 0000000..a905cbb
--- /dev/null
+++ b/hw/pl181.c
@@ -0,0 +1,466 @@
+/*
+ * Arm PrimeCell PL181 MultiMedia Card Interface
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+#include "sd.h"
+
+//#define DEBUG_PL181 1
+
+#ifdef DEBUG_PL181
+#define DPRINTF(fmt, args...) \
+do { printf("pl181: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+#define PL181_FIFO_LEN 16
+
+typedef struct {
+    SDState *card;
+    uint32_t base;
+    uint32_t clock;
+    uint32_t power;
+    uint32_t cmdarg;
+    uint32_t cmd;
+    uint32_t datatimer;
+    uint32_t datalength;
+    uint32_t respcmd;
+    uint32_t response[4];
+    uint32_t datactrl;
+    uint32_t datacnt;
+    uint32_t status;
+    uint32_t mask[2];
+    int fifo_pos;
+    int fifo_len;
+    /* The linux 2.6.21 driver is buggy, and misbehaves if new data arrives
+       while it is reading the FIFO.  We hack around this be defering
+       subsequent transfers until after the driver polls the status word.
+       http://www.arm.linux.org.uk/developer/patches/viewpatch.php?id=4446/1
+     */
+    int linux_hack;
+    uint32_t fifo[PL181_FIFO_LEN];
+    qemu_irq irq[2];
+} pl181_state;
+
+#define PL181_CMD_INDEX     0x3f
+#define PL181_CMD_RESPONSE  (1 << 6)
+#define PL181_CMD_LONGRESP  (1 << 7)
+#define PL181_CMD_INTERRUPT (1 << 8)
+#define PL181_CMD_PENDING   (1 << 9)
+#define PL181_CMD_ENABLE    (1 << 10)
+
+#define PL181_DATA_ENABLE             (1 << 0)
+#define PL181_DATA_DIRECTION          (1 << 1)
+#define PL181_DATA_MODE               (1 << 2)
+#define PL181_DATA_DMAENABLE          (1 << 3)
+
+#define PL181_STATUS_CMDCRCFAIL       (1 << 0)
+#define PL181_STATUS_DATACRCFAIL      (1 << 1)
+#define PL181_STATUS_CMDTIMEOUT       (1 << 2)
+#define PL181_STATUS_DATATIMEOUT      (1 << 3)
+#define PL181_STATUS_TXUNDERRUN       (1 << 4)
+#define PL181_STATUS_RXOVERRUN        (1 << 5)
+#define PL181_STATUS_CMDRESPEND       (1 << 6)
+#define PL181_STATUS_CMDSENT          (1 << 7)
+#define PL181_STATUS_DATAEND          (1 << 8)
+#define PL181_STATUS_DATABLOCKEND     (1 << 10)
+#define PL181_STATUS_CMDACTIVE        (1 << 11)
+#define PL181_STATUS_TXACTIVE         (1 << 12)
+#define PL181_STATUS_RXACTIVE         (1 << 13)
+#define PL181_STATUS_TXFIFOHALFEMPTY  (1 << 14)
+#define PL181_STATUS_RXFIFOHALFFULL   (1 << 15)
+#define PL181_STATUS_TXFIFOFULL       (1 << 16)
+#define PL181_STATUS_RXFIFOFULL       (1 << 17)
+#define PL181_STATUS_TXFIFOEMPTY      (1 << 18)
+#define PL181_STATUS_RXFIFOEMPTY      (1 << 19)
+#define PL181_STATUS_TXDATAAVLBL      (1 << 20)
+#define PL181_STATUS_RXDATAAVLBL      (1 << 21)
+
+#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
+                             |PL181_STATUS_TXFIFOHALFEMPTY \
+                             |PL181_STATUS_TXFIFOFULL \
+                             |PL181_STATUS_TXFIFOEMPTY \
+                             |PL181_STATUS_TXDATAAVLBL)
+#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
+                             |PL181_STATUS_RXFIFOHALFFULL \
+                             |PL181_STATUS_RXFIFOFULL \
+                             |PL181_STATUS_RXFIFOEMPTY \
+                             |PL181_STATUS_RXDATAAVLBL)
+
+static const unsigned char pl181_id[] =
+{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl181_update(pl181_state *s)
+{
+    int i;
+    for (i = 0; i < 2; i++) {
+        qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
+    }
+}
+
+static void pl181_fifo_push(pl181_state *s, uint32_t value)
+{
+    int n;
+
+    if (s->fifo_len == PL181_FIFO_LEN) {
+        fprintf(stderr, "pl181: FIFO overflow\n");
+        return;
+    }
+    n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
+    s->fifo_len++;
+    s->fifo[n] = value;
+    DPRINTF("FIFO push %08x\n", (int)value);
+}
+
+static uint32_t pl181_fifo_pop(pl181_state *s)
+{
+    uint32_t value;
+
+    if (s->fifo_len == 0) {
+        fprintf(stderr, "pl181: FIFO underflow\n");
+        return 0;
+    }
+    value = s->fifo[s->fifo_pos];
+    s->fifo_len--;
+    s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
+    DPRINTF("FIFO pop %08x\n", (int)value);
+    return value;
+}
+
+static void pl181_send_command(pl181_state *s)
+{
+    struct sd_request_s request;
+    uint8_t response[16];
+    int rlen;
+
+    request.cmd = s->cmd & PL181_CMD_INDEX;
+    request.arg = s->cmdarg;
+    DPRINTF("Command %d %08x\n", request.cmd, request.arg);
+    rlen = sd_do_command(s->card, &request, response);
+    if (rlen < 0)
+        goto error;
+    if (s->cmd & PL181_CMD_RESPONSE) {
+#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
+                  | (response[n + 2] << 8) | response[n + 3])
+        if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
+            goto error;
+        if (rlen != 4 && rlen != 16)
+            goto error;
+        s->response[0] = RWORD(0);
+        if (rlen == 4) {
+            s->response[1] = s->response[2] = s->response[3] = 0;
+        } else {
+            s->response[1] = RWORD(4);
+            s->response[2] = RWORD(8);
+            s->response[3] = RWORD(12) & ~1;
+        }
+        DPRINTF("Response received\n");
+        s->status |= PL181_STATUS_CMDRESPEND;
+#undef RWORD
+    } else {
+        DPRINTF("Command sent\n");
+        s->status |= PL181_STATUS_CMDSENT;
+    }
+    return;
+
+error:
+    DPRINTF("Timeout\n");
+    s->status |= PL181_STATUS_CMDTIMEOUT;
+}
+
+/* Transfer data between the card and the FIFO.  This is complicated by
+   the FIFO holding 32-bit words and the card taking data in single byte
+   chunks.  FIFO bytes are transferred in little-endian order.  */
+
+static void pl181_fifo_run(pl181_state *s)
+{
+    uint32_t bits;
+    uint32_t value;
+    int n;
+    int limit;
+    int is_read;
+
+    is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
+    if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))
+            && !s->linux_hack) {
+        limit = is_read ? PL181_FIFO_LEN : 0;
+        n = 0;
+        value = 0;
+        while (s->datacnt && s->fifo_len != limit) {
+            if (is_read) {
+                value |= (uint32_t)sd_read_data(s->card) << (n * 8);
+                n++;
+                if (n == 4) {
+                    pl181_fifo_push(s, value);
+                    value = 0;
+                    n = 0;
+                }
+            } else {
+                if (n == 0) {
+                    value = pl181_fifo_pop(s);
+                    n = 4;
+                }
+                sd_write_data(s->card, value & 0xff);
+                value >>= 8;
+                n--;
+            }
+            s->datacnt--;
+        }
+        if (n && is_read) {
+            pl181_fifo_push(s, value);
+        }
+    }
+    s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
+    if (s->datacnt == 0) {
+        s->status |= PL181_STATUS_DATAEND;
+        /* HACK: */
+        s->status |= PL181_STATUS_DATABLOCKEND;
+        DPRINTF("Transfer Complete\n");
+    }
+    if (s->datacnt == 0 && s->fifo_len == 0) {
+        s->datactrl &= ~PL181_DATA_ENABLE;
+        DPRINTF("Data engine idle\n");
+    } else {
+        /* Update FIFO bits.  */
+        bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
+        if (s->fifo_len == 0) {
+            bits |= PL181_STATUS_TXFIFOEMPTY;
+            bits |= PL181_STATUS_RXFIFOEMPTY;
+        } else {
+            bits |= PL181_STATUS_TXDATAAVLBL;
+            bits |= PL181_STATUS_RXDATAAVLBL;
+        }
+        if (s->fifo_len == 16) {
+            bits |= PL181_STATUS_TXFIFOFULL;
+            bits |= PL181_STATUS_RXFIFOFULL;
+        }
+        if (s->fifo_len <= 8) {
+            bits |= PL181_STATUS_TXFIFOHALFEMPTY;
+        }
+        if (s->fifo_len >= 8) {
+            bits |= PL181_STATUS_RXFIFOHALFFULL;
+        }
+        if (s->datactrl & PL181_DATA_DIRECTION) {
+            bits &= PL181_STATUS_RX_FIFO;
+        } else {
+            bits &= PL181_STATUS_TX_FIFO;
+        }
+        s->status |= bits;
+    }
+}
+
+static uint32_t pl181_read(void *opaque, target_phys_addr_t offset)
+{
+    pl181_state *s = (pl181_state *)opaque;
+    uint32_t tmp;
+
+    offset -= s->base;
+    if (offset >= 0xfe0 && offset < 0x1000) {
+        return pl181_id[(offset - 0xfe0) >> 2];
+    }
+    switch (offset) {
+    case 0x00: /* Power */
+        return s->power;
+    case 0x04: /* Clock */
+        return s->clock;
+    case 0x08: /* Argument */
+        return s->cmdarg;
+    case 0x0c: /* Command */
+        return s->cmd;
+    case 0x10: /* RespCmd */
+        return s->respcmd;
+    case 0x14: /* Response0 */
+        return s->response[0];
+    case 0x18: /* Response1 */
+        return s->response[1];
+    case 0x1c: /* Response2 */
+        return s->response[2];
+    case 0x20: /* Response3 */
+        return s->response[3];
+    case 0x24: /* DataTimer */
+        return s->datatimer;
+    case 0x28: /* DataLength */
+        return s->datalength;
+    case 0x2c: /* DataCtrl */
+        return s->datactrl;
+    case 0x30: /* DataCnt */
+        return s->datacnt;
+    case 0x34: /* Status */
+        tmp = s->status;
+        if (s->linux_hack) {
+            s->linux_hack = 0;
+            pl181_fifo_run(s);
+            pl181_update(s);
+        }
+        return tmp;
+    case 0x3c: /* Mask0 */
+        return s->mask[0];
+    case 0x40: /* Mask1 */
+        return s->mask[1];
+    case 0x48: /* FifoCnt */
+        /* The documentation is somewhat vague about exactly what FifoCnt
+           does.  On real hardware it appears to be when decrememnted
+           when a word is transfered between the FIFO and the serial
+           data engine.  DataCnt is decremented after each byte is
+           transfered between the serial engine and the card.
+           We don't emulate this level of detail, so both can be the same.  */
+        tmp = (s->datacnt + 3) >> 2;
+        if (s->linux_hack) {
+            s->linux_hack = 0;
+            pl181_fifo_run(s);
+            pl181_update(s);
+        }
+        return tmp;
+    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
+    case 0x90: case 0x94: case 0x98: case 0x9c:
+    case 0xa0: case 0xa4: case 0xa8: case 0xac:
+    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
+        if (s->fifo_len == 0) {
+            fprintf(stderr, "pl181: Unexpected FIFO read\n");
+            return 0;
+        } else {
+            uint32_t value;
+            value = pl181_fifo_pop(s);
+            s->linux_hack = 1;
+            pl181_fifo_run(s);
+            pl181_update(s);
+            return value;
+        }
+    default:
+        cpu_abort (cpu_single_env, "pl181_read: Bad offset %x\n", offset);
+        return 0;
+    }
+}
+
+static void pl181_write(void *opaque, target_phys_addr_t offset,
+                          uint32_t value)
+{
+    pl181_state *s = (pl181_state *)opaque;
+
+    offset -= s->base;
+    switch (offset) {
+    case 0x00: /* Power */
+        s->power = value & 0xff;
+        break;
+    case 0x04: /* Clock */
+        s->clock = value & 0xff;
+        break;
+    case 0x08: /* Argument */
+        s->cmdarg = value;
+        break;
+    case 0x0c: /* Command */
+        s->cmd = value;
+        if (s->cmd & PL181_CMD_ENABLE) {
+            if (s->cmd & PL181_CMD_INTERRUPT) {
+                fprintf(stderr, "pl181: Interrupt mode not implemented\n");
+                abort();
+            } if (s->cmd & PL181_CMD_PENDING) {
+                fprintf(stderr, "pl181: Pending commands not implemented\n");
+                abort();
+            } else {
+                pl181_send_command(s);
+                pl181_fifo_run(s);
+            }
+            /* The command has completed one way or the other.  */
+            s->cmd &= ~PL181_CMD_ENABLE;
+        }
+        break;
+    case 0x24: /* DataTimer */
+        s->datatimer = value;
+        break;
+    case 0x28: /* DataLength */
+        s->datalength = value & 0xffff;
+        break;
+    case 0x2c: /* DataCtrl */
+        s->datactrl = value & 0xff;
+        if (value & PL181_DATA_ENABLE) {
+            s->datacnt = s->datalength;
+            pl181_fifo_run(s);
+        }
+        break;
+    case 0x38: /* Clear */
+        s->status &= ~(value & 0x7ff);
+        break;
+    case 0x3c: /* Mask0 */
+        s->mask[0] = value;
+        break;
+    case 0x40: /* Mask1 */
+        s->mask[1] = value;
+        break;
+    case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
+    case 0x90: case 0x94: case 0x98: case 0x9c:
+    case 0xa0: case 0xa4: case 0xa8: case 0xac:
+    case 0xb0: case 0xb4: case 0xb8: case 0xbc:
+        if (s->datacnt == 0) {
+            fprintf(stderr, "pl181: Unexpected FIFO write\n");
+        } else {
+            pl181_fifo_push(s, value);
+            pl181_fifo_run(s);
+        }
+        break;
+    default:
+        cpu_abort (cpu_single_env, "pl181_write: Bad offset %x\n", offset);
+    }
+    pl181_update(s);
+}
+
+static CPUReadMemoryFunc *pl181_readfn[] = {
+   pl181_read,
+   pl181_read,
+   pl181_read
+};
+
+static CPUWriteMemoryFunc *pl181_writefn[] = {
+   pl181_write,
+   pl181_write,
+   pl181_write
+};
+
+static void pl181_reset(void *opaque)
+{
+    pl181_state *s = (pl181_state *)opaque;
+
+    s->power = 0;
+    s->cmdarg = 0;
+    s->cmd = 0;
+    s->datatimer = 0;
+    s->datalength = 0;
+    s->respcmd = 0;
+    s->response[0] = 0;
+    s->response[1] = 0;
+    s->response[2] = 0;
+    s->response[3] = 0;
+    s->datatimer = 0;
+    s->datalength = 0;
+    s->datactrl = 0;
+    s->datacnt = 0;
+    s->status = 0;
+    s->linux_hack = 0;
+    s->mask[0] = 0;
+    s->mask[1] = 0;
+}
+
+void pl181_init(uint32_t base, BlockDriverState *bd,
+                qemu_irq irq0, qemu_irq irq1)
+{
+    int iomemtype;
+    pl181_state *s;
+
+    s = (pl181_state *)qemu_mallocz(sizeof(pl181_state));
+    iomemtype = cpu_register_io_memory(0, pl181_readfn,
+                                       pl181_writefn, s);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+    s->base = base;
+    s->card = sd_init(bd);
+    s->irq[0] = irq0;
+    s->irq[1] = irq1;
+    qemu_register_reset(pl181_reset, s);
+    pl181_reset(s);
+    /* ??? Save/restore.  */
+}
diff --git a/hw/pl190.c b/hw/pl190.c
index 55c7180..23494d8 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * Arm PrimeCell PL190 Vector Interrupt Controller
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -17,7 +17,6 @@
 #define PL190_NUM_PRIO 17
 
 typedef struct {
-    arm_pic_handler handler;
     uint32_t base;
     DisplayState *ds;
     uint32_t level;
@@ -33,9 +32,8 @@
     /* Current priority level.  */
     int priority;
     int prev_prio[PL190_NUM_PRIO];
-    void *parent;
-    int irq;
-    int fiq;
+    qemu_irq irq;
+    qemu_irq fiq;
 } pl190_state;
 
 static const unsigned char pl190_id[] =
@@ -53,9 +51,9 @@
     int set;
 
     set = (level & s->prio_mask[s->priority]) != 0;
-    pic_set_irq_new(s->parent, s->irq, set);
+    qemu_set_irq(s->irq, set);
     set = ((s->level | s->soft_level) & s->fiq_select) != 0;
-    pic_set_irq_new(s->parent, s->fiq, set);
+    qemu_set_irq(s->fiq, set);
 }
 
 static void pl190_set_irq(void *opaque, int irq, int level)
@@ -232,21 +230,21 @@
   pl190_update_vectors(s);
 }
 
-void *pl190_init(uint32_t base, void *parent, int irq, int fiq)
+qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq)
 {
     pl190_state *s;
+    qemu_irq *qi;
     int iomemtype;
 
     s = (pl190_state *)qemu_mallocz(sizeof(pl190_state));
     iomemtype = cpu_register_io_memory(0, pl190_readfn,
                                        pl190_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
-    s->handler = pl190_set_irq;
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+    qi = qemu_allocate_irqs(pl190_set_irq, s, 32);
     s->base = base;
-    s->parent = parent;
     s->irq = irq;
     s->fiq = fiq;
     pl190_reset(s);
     /* ??? Save/restore.  */
-    return s;
+    return qi;
 }
diff --git a/hw/ppc.c b/hw/ppc.c
index b0865c1..8e7912e 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -1,8 +1,8 @@
 /*
- * QEMU generic PPC hardware System Emulator
- * 
- * Copyright (c) 2003-2004 Jocelyn Mayer
- * 
+ * QEMU generic PowerPC hardware System Emulator
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -24,24 +24,409 @@
 #include "vl.h"
 #include "m48t59.h"
 
-/*****************************************************************************/
-/* PPC time base and decrementer emulation */
-//#define DEBUG_TB
+//#define PPC_DEBUG_IRQ
+//#define PPC_DEBUG_TB
 
+extern FILE *logfile;
+extern int loglevel;
+
+void ppc_set_irq (CPUState *env, int n_IRQ, int level)
+{
+    if (level) {
+        env->pending_interrupts |= 1 << n_IRQ;
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        env->pending_interrupts &= ~(1 << n_IRQ);
+        if (env->pending_interrupts == 0)
+            cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+#if defined(PPC_DEBUG_IRQ)
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08x req %08x\n",
+                __func__, env, n_IRQ, level,
+                env->pending_interrupts, env->interrupt_request);
+    }
+#endif
+}
+
+/* PowerPC 6xx / 7xx internal IRQ controller */
+static void ppc6xx_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+    int cur_level;
+
+#if defined(PPC_DEBUG_IRQ)
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    }
+#endif
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC6xx_INPUT_INT:
+            /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC6xx_INPUT_SMI:
+            /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the SMI IRQ state to %d\n",
+                        __func__, level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
+            break;
+        case PPC6xx_INPUT_MCP:
+            /* Negative edge sensitive */
+            /* XXX: TODO: actual reaction may depends on HID0 status
+             *            603/604/740/750: check HID0[EMCP]
+             */
+            if (cur_level == 1 && level == 0) {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: raise machine check state\n",
+                            __func__);
+                }
+#endif
+                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
+            }
+            break;
+        case PPC6xx_INPUT_CKSTP_IN:
+            /* Level sensitive - active low */
+            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+            if (level) {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: stop the CPU\n", __func__);
+                }
+#endif
+                env->halted = 1;
+            } else {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: restart the CPU\n", __func__);
+                }
+#endif
+                env->halted = 0;
+            }
+            break;
+        case PPC6xx_INPUT_HRESET:
+            /* Level sensitive - active low */
+            if (level) {
+#if 0 // XXX: TOFIX
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: reset the CPU\n", __func__);
+                }
+#endif
+                cpu_reset(env);
+#endif
+            }
+            break;
+        case PPC6xx_INPUT_SRESET:
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
+                        __func__, level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
+            }
+#endif
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc6xx_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6);
+}
+
+/* PowerPC 970 internal IRQ controller */
+static void ppc970_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+    int cur_level;
+
+#if defined(PPC_DEBUG_IRQ)
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    }
+#endif
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC970_INPUT_INT:
+            /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC970_INPUT_THINT:
+            /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__,
+                        level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
+            break;
+        case PPC970_INPUT_MCP:
+            /* Negative edge sensitive */
+            /* XXX: TODO: actual reaction may depends on HID0 status
+             *            603/604/740/750: check HID0[EMCP]
+             */
+            if (cur_level == 1 && level == 0) {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: raise machine check state\n",
+                            __func__);
+                }
+#endif
+                ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
+            }
+            break;
+        case PPC970_INPUT_CKSTP:
+            /* Level sensitive - active low */
+            /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+            if (level) {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: stop the CPU\n", __func__);
+                }
+#endif
+                env->halted = 1;
+            } else {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: restart the CPU\n", __func__);
+                }
+#endif
+                env->halted = 0;
+            }
+            break;
+        case PPC970_INPUT_HRESET:
+            /* Level sensitive - active low */
+            if (level) {
+#if 0 // XXX: TOFIX
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: reset the CPU\n", __func__);
+                }
+#endif
+                cpu_reset(env);
+#endif
+            }
+            break;
+        case PPC970_INPUT_SRESET:
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
+                        __func__, level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
+            break;
+        case PPC970_INPUT_TBEN:
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the TBEN state to %d\n", __func__,
+                        level);
+            }
+#endif
+            /* XXX: TODO */
+            break;
+        default:
+            /* Unknown pin - do nothing */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
+            }
+#endif
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc970_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7);
+}
+
+/* PowerPC 40x internal IRQ controller */
+static void ppc40x_set_irq (void *opaque, int pin, int level)
+{
+    CPUState *env = opaque;
+    int cur_level;
+
+#if defined(PPC_DEBUG_IRQ)
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
+                env, pin, level);
+    }
+#endif
+    cur_level = (env->irq_input_state >> pin) & 1;
+    /* Don't generate spurious events */
+    if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+        switch (pin) {
+        case PPC40x_INPUT_RESET_SYS:
+            if (level) {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: reset the PowerPC system\n",
+                            __func__);
+                }
+#endif
+                ppc40x_system_reset(env);
+            }
+            break;
+        case PPC40x_INPUT_RESET_CHIP:
+            if (level) {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: reset the PowerPC chip\n", __func__);
+                }
+#endif
+                ppc40x_chip_reset(env);
+            }
+            break;
+        case PPC40x_INPUT_RESET_CORE:
+            /* XXX: TODO: update DBSR[MRR] */
+            if (level) {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: reset the PowerPC core\n", __func__);
+                }
+#endif
+                ppc40x_core_reset(env);
+            }
+            break;
+        case PPC40x_INPUT_CINT:
+            /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the critical IRQ state to %d\n",
+                        __func__, level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_CEXT, level);
+            break;
+        case PPC40x_INPUT_INT:
+            /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the external IRQ state to %d\n",
+                        __func__, level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+            break;
+        case PPC40x_INPUT_HALT:
+            /* Level sensitive - active low */
+            if (level) {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: stop the CPU\n", __func__);
+                }
+#endif
+                env->halted = 1;
+            } else {
+#if defined(PPC_DEBUG_IRQ)
+                if (loglevel & CPU_LOG_INT) {
+                    fprintf(logfile, "%s: restart the CPU\n", __func__);
+                }
+#endif
+                env->halted = 0;
+            }
+            break;
+        case PPC40x_INPUT_DEBUG:
+            /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: set the debug pin state to %d\n",
+                        __func__, level);
+            }
+#endif
+            ppc_set_irq(env, PPC_INTERRUPT_DEBUG, level);
+            break;
+        default:
+            /* Unknown pin - do nothing */
+#if defined(PPC_DEBUG_IRQ)
+            if (loglevel & CPU_LOG_INT) {
+                fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
+            }
+#endif
+            return;
+        }
+        if (level)
+            env->irq_input_state |= 1 << pin;
+        else
+            env->irq_input_state &= ~(1 << pin);
+    }
+}
+
+void ppc40x_irq_init (CPUState *env)
+{
+    env->irq_inputs = (void **)qemu_allocate_irqs(&ppc40x_set_irq,
+                                                  env, PPC40x_INPUT_NB);
+}
+
+/*****************************************************************************/
+/* PowerPC time base and decrementer emulation */
 struct ppc_tb_t {
     /* Time base management */
     int64_t  tb_offset;    /* Compensation               */
+    int64_t  atb_offset;   /* Compensation               */
     uint32_t tb_freq;      /* TB frequency               */
     /* Decrementer management */
     uint64_t decr_next;    /* Tick for next decr interrupt  */
     struct QEMUTimer *decr_timer;
+#if defined(TARGET_PPC64H)
+    /* Hypervisor decrementer management */
+    uint64_t hdecr_next;    /* Tick for next hdecr interrupt  */
+    struct QEMUTimer *hdecr_timer;
+    uint64_t purr_load;
+    uint64_t purr_start;
+#endif
+    void *opaque;
 };
 
-static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
+static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env, int64_t tb_offset)
 {
     /* TB time in tb periods */
     return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
-		    tb_env->tb_freq, ticks_per_sec);
+                    tb_env->tb_freq, ticks_per_sec);
 }
 
 uint32_t cpu_ppc_load_tbl (CPUState *env)
@@ -49,61 +434,127 @@
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env);
-#ifdef DEBUG_TB
-    {
-         static int last_time;
-	 int now;
-	 now = time(NULL);
-	 if (last_time != now) {
-	     last_time = now;
-	     printf("%s: tb=0x%016lx %d %08lx\n",
-                    __func__, tb, now, tb_env->tb_offset);
-	 }
+    tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset);
+#if defined(PPC_DEBUG_TB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
     }
 #endif
 
     return tb & 0xFFFFFFFF;
 }
 
-uint32_t cpu_ppc_load_tbu (CPUState *env)
+static inline uint32_t _cpu_ppc_load_tbu (CPUState *env)
 {
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t tb;
 
-    tb = cpu_ppc_get_tb(tb_env);
-#ifdef DEBUG_TB
-    printf("%s: tb=0x%016lx\n", __func__, tb);
+    tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset);
+#if defined(PPC_DEBUG_TB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
+    }
 #endif
+
     return tb >> 32;
 }
 
-static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
+uint32_t cpu_ppc_load_tbu (CPUState *env)
 {
-    tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
-        - qemu_get_clock(vm_clock);
-#ifdef DEBUG_TB
-    printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
-#endif
+    return _cpu_ppc_load_tbu(env);
 }
 
-void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+static inline void cpu_ppc_store_tb (ppc_tb_t *tb_env, int64_t *tb_offsetp,
+                                     uint64_t value)
 {
-    ppc_tb_t *tb_env = env->tb_env;
-
-    cpu_ppc_store_tb(tb_env,
-                     ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
+    *tb_offsetp = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
+        - qemu_get_clock(vm_clock);
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value,
+                *tb_offsetp);
+    }
+#endif
 }
 
 void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
 {
     ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
 
-    cpu_ppc_store_tb(tb_env,
-                     ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
+    tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset);
+    tb &= 0xFFFFFFFF00000000ULL;
+    cpu_ppc_store_tb(tb_env, &tb_env->tb_offset, tb | (uint64_t)value);
 }
 
-uint32_t cpu_ppc_load_decr (CPUState *env)
+static inline void _cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, tb_env->tb_offset);
+    tb &= 0x00000000FFFFFFFFULL;
+    cpu_ppc_store_tb(tb_env, &tb_env->tb_offset,
+                     ((uint64_t)value << 32) | tb);
+}
+
+void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+{
+    _cpu_ppc_store_tbu(env, value);
+}
+
+uint32_t cpu_ppc_load_atbl (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset);
+#if defined(PPC_DEBUG_TB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
+    }
+#endif
+
+    return tb & 0xFFFFFFFF;
+}
+
+uint32_t cpu_ppc_load_atbu (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset);
+#if defined(PPC_DEBUG_TB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
+    }
+#endif
+
+    return tb >> 32;
+}
+
+void cpu_ppc_store_atbl (CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset);
+    tb &= 0xFFFFFFFF00000000ULL;
+    cpu_ppc_store_tb(tb_env, &tb_env->atb_offset, tb | (uint64_t)value);
+}
+
+void cpu_ppc_store_atbu (CPUState *env, uint32_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t tb;
+
+    tb = cpu_ppc_get_tb(tb_env, tb_env->atb_offset);
+    tb &= 0x00000000FFFFFFFFULL;
+    cpu_ppc_store_tb(tb_env, &tb_env->atb_offset,
+                     ((uint64_t)value << 32) | tb);
+}
+
+static inline uint32_t _cpu_ppc_load_decr (CPUState *env, uint64_t *next)
 {
     ppc_tb_t *tb_env = env->tb_env;
     uint32_t decr;
@@ -114,47 +565,104 @@
         decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
     else
         decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
-#if defined(DEBUG_TB)
-    printf("%s: 0x%08x\n", __func__, decr);
+#if defined(PPC_DEBUG_TB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
+    }
 #endif
+
     return decr;
 }
 
+uint32_t cpu_ppc_load_decr (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    return _cpu_ppc_load_decr(env, &tb_env->decr_next);
+}
+
+#if defined(TARGET_PPC64H)
+uint32_t cpu_ppc_load_hdecr (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    return _cpu_ppc_load_decr(env, &tb_env->hdecr_next);
+}
+
+uint64_t cpu_ppc_load_purr (CPUState *env)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+    uint64_t diff;
+
+    diff = qemu_get_clock(vm_clock) - tb_env->purr_start;
+    
+    return tb_env->purr_load + muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
+}
+#endif /* defined(TARGET_PPC64H) */
+
 /* When decrementer expires,
  * all we need to do is generate or queue a CPU exception
  */
 static inline void cpu_ppc_decr_excp (CPUState *env)
 {
     /* Raise it */
-#ifdef DEBUG_TB
-    printf("raise decrementer exception\n");
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "raise decrementer exception\n");
+    }
 #endif
-    cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+    ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
 }
 
-static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
-                                 uint32_t value, int is_excp)
+static inline void cpu_ppc_hdecr_excp (CPUState *env)
+{
+    /* Raise it */
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "raise decrementer exception\n");
+    }
+#endif
+    ppc_set_irq(env, PPC_INTERRUPT_HDECR, 1);
+}
+
+static void __cpu_ppc_store_decr (CPUState *env, uint64_t *nextp,
+                                 struct QEMUTimer *timer,
+                                 void (*raise_excp)(CPUState *),
+                                 uint32_t decr, uint32_t value,
+                                 int is_excp)
 {
     ppc_tb_t *tb_env = env->tb_env;
     uint64_t now, next;
 
-#ifdef DEBUG_TB
-    printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value);
+    }
 #endif
     now = qemu_get_clock(vm_clock);
     next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
     if (is_excp)
-        next += tb_env->decr_next - now;
+        next += *nextp - now;
     if (next == now)
-	next++;
-    tb_env->decr_next = next;
+        next++;
+    *nextp = next;
     /* Adjust timer */
-    qemu_mod_timer(tb_env->decr_timer, next);
+    qemu_mod_timer(timer, next);
     /* If we set a negative value and the decrementer was positive,
      * raise an exception.
      */
     if ((value & 0x80000000) && !(decr & 0x80000000))
-	cpu_ppc_decr_excp(env);
+        (*raise_excp)(env);
+}
+
+
+static inline void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
+                                        uint32_t value, int is_excp)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    __cpu_ppc_store_decr(env, &tb_env->decr_next, tb_env->decr_timer,
+                         &cpu_ppc_decr_excp, decr, value, is_excp);
 }
 
 void cpu_ppc_store_decr (CPUState *env, uint32_t value)
@@ -167,8 +675,54 @@
     _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
 }
 
+#if defined(TARGET_PPC64H)
+static inline void _cpu_ppc_store_hdecr (CPUState *env, uint32_t hdecr,
+                                        uint32_t value, int is_excp)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    __cpu_ppc_store_decr(env, &tb_env->hdecr_next, tb_env->hdecr_timer,
+                         &cpu_ppc_hdecr_excp, hdecr, value, is_excp);
+}
+
+void cpu_ppc_store_hdecr (CPUState *env, uint32_t value)
+{
+    _cpu_ppc_store_hdecr(env, cpu_ppc_load_hdecr(env), value, 0);
+}
+
+static void cpu_ppc_hdecr_cb (void *opaque)
+{
+    _cpu_ppc_store_hdecr(opaque, 0x00000000, 0xFFFFFFFF, 1);
+}
+
+void cpu_ppc_store_purr (CPUState *env, uint64_t value)
+{
+    ppc_tb_t *tb_env = env->tb_env;
+
+    tb_env->purr_load = value;
+    tb_env->purr_start = qemu_get_clock(vm_clock);
+}
+#endif /* defined(TARGET_PPC64H) */
+
+static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
+{
+    CPUState *env = opaque;
+    ppc_tb_t *tb_env = env->tb_env;
+
+    tb_env->tb_freq = freq;
+    /* There is a bug in Linux 2.4 kernels:
+     * if a decrementer exception is pending when it enables msr_ee at startup,
+     * it's not ready to handle it...
+     */
+    _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+#if defined(TARGET_PPC64H)
+    _cpu_ppc_store_hdecr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+    cpu_ppc_store_purr(env, 0x0000000000000000ULL);
+#endif /* defined(TARGET_PPC64H) */
+}
+
 /* Set up (once) timebase frequency (in Hz) */
-ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
+clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
 {
     ppc_tb_t *tb_env;
 
@@ -176,21 +730,424 @@
     if (tb_env == NULL)
         return NULL;
     env->tb_env = tb_env;
-    if (tb_env->tb_freq == 0 || 1) {
-	tb_env->tb_freq = freq;
-	/* Create new timer */
-	tb_env->decr_timer =
-            qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
-	/* There is a bug in  2.4 kernels:
-	 * if a decrementer exception is pending when it enables msr_ee,
-	 * it's not ready to handle it...
-	 */
-	_cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+    /* Create new timer */
+    tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
+#if defined(TARGET_PPC64H)
+    tb_env->hdecr_timer = qemu_new_timer(vm_clock, &cpu_ppc_hdecr_cb, env);
+#endif /* defined(TARGET_PPC64H) */
+    cpu_ppc_set_tb_clk(env, freq);
+
+    return &cpu_ppc_set_tb_clk;
+}
+
+/* Specific helpers for POWER & PowerPC 601 RTC */
+clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
+{
+    return cpu_ppc_tb_init(env, 7812500);
+}
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
+{
+    _cpu_ppc_store_tbu(env, value);
+}
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+{
+    return _cpu_ppc_load_tbu(env);
+}
+
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
+{
+    cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
+}
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
+{
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/*****************************************************************************/
+/* Embedded PowerPC timers */
+
+/* PIT, FIT & WDT */
+typedef struct ppcemb_timer_t ppcemb_timer_t;
+struct ppcemb_timer_t {
+    uint64_t pit_reload;  /* PIT auto-reload value        */
+    uint64_t fit_next;    /* Tick for next FIT interrupt  */
+    struct QEMUTimer *fit_timer;
+    uint64_t wdt_next;    /* Tick for next WDT interrupt  */
+    struct QEMUTimer *wdt_timer;
+};
+
+/* Fixed interval timer */
+static void cpu_4xx_fit_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+    uint64_t now, next;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    ppcemb_timer = tb_env->opaque;
+    now = qemu_get_clock(vm_clock);
+    switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
+    case 0:
+        next = 1 << 9;
+        break;
+    case 1:
+        next = 1 << 13;
+        break;
+    case 2:
+        next = 1 << 17;
+        break;
+    case 3:
+        next = 1 << 21;
+        break;
+    default:
+        /* Cannot occur, but makes gcc happy */
+        return;
+    }
+    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
+    if (next == now)
+        next++;
+    qemu_mod_timer(ppcemb_timer->fit_timer, next);
+    env->spr[SPR_40x_TSR] |= 1 << 26;
+    if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
+        ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
+                (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
+                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
+    }
+#endif
+}
+
+/* Programmable interval timer */
+static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
+{
+    ppcemb_timer_t *ppcemb_timer;
+    uint64_t now, next;
+
+    ppcemb_timer = tb_env->opaque;
+    if (ppcemb_timer->pit_reload <= 1 ||
+        !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
+        (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
+        /* Stop PIT */
+#ifdef PPC_DEBUG_TB
+        if (loglevel != 0) {
+            fprintf(logfile, "%s: stop PIT\n", __func__);
+        }
+#endif
+        qemu_del_timer(tb_env->decr_timer);
+    } else {
+#ifdef PPC_DEBUG_TB
+        if (loglevel != 0) {
+            fprintf(logfile, "%s: start PIT 0x" REGX "\n",
+                    __func__, ppcemb_timer->pit_reload);
+        }
+#endif
+        now = qemu_get_clock(vm_clock);
+        next = now + muldiv64(ppcemb_timer->pit_reload,
+                              ticks_per_sec, tb_env->tb_freq);
+        if (is_excp)
+            next += tb_env->decr_next - now;
+        if (next == now)
+            next++;
+        qemu_mod_timer(tb_env->decr_timer, next);
+        tb_env->decr_next = next;
+    }
+}
+
+static void cpu_4xx_pit_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    ppcemb_timer = tb_env->opaque;
+    env->spr[SPR_40x_TSR] |= 1 << 27;
+    if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
+        ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
+    start_stop_pit(env, tb_env, 1);
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
+                "%016" PRIx64 "\n", __func__,
+                (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
+                (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
+                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
+                ppcemb_timer->pit_reload);
+    }
+#endif
+}
+
+/* Watchdog timer */
+static void cpu_4xx_wdt_cb (void *opaque)
+{
+    CPUState *env;
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+    uint64_t now, next;
+
+    env = opaque;
+    tb_env = env->tb_env;
+    ppcemb_timer = tb_env->opaque;
+    now = qemu_get_clock(vm_clock);
+    switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
+    case 0:
+        next = 1 << 17;
+        break;
+    case 1:
+        next = 1 << 21;
+        break;
+    case 2:
+        next = 1 << 25;
+        break;
+    case 3:
+        next = 1 << 29;
+        break;
+    default:
+        /* Cannot occur, but makes gcc happy */
+        return;
+    }
+    next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
+    if (next == now)
+        next++;
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
+                env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
+    }
+#endif
+    switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
+    case 0x0:
+    case 0x1:
+        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
+        ppcemb_timer->wdt_next = next;
+        env->spr[SPR_40x_TSR] |= 1 << 31;
+        break;
+    case 0x2:
+        qemu_mod_timer(ppcemb_timer->wdt_timer, next);
+        ppcemb_timer->wdt_next = next;
+        env->spr[SPR_40x_TSR] |= 1 << 30;
+        if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
+            ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
+        break;
+    case 0x3:
+        env->spr[SPR_40x_TSR] &= ~0x30000000;
+        env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
+        switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
+        case 0x0:
+            /* No reset */
+            break;
+        case 0x1: /* Core reset */
+            ppc40x_core_reset(env);
+            break;
+        case 0x2: /* Chip reset */
+            ppc40x_chip_reset(env);
+            break;
+        case 0x3: /* System reset */
+            ppc40x_system_reset(env);
+            break;
+        }
+    }
+}
+
+void store_40x_pit (CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+
+    tb_env = env->tb_env;
+    ppcemb_timer = tb_env->opaque;
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
+    }
+#endif
+    ppcemb_timer->pit_reload = val;
+    start_stop_pit(env, tb_env, 0);
+}
+
+target_ulong load_40x_pit (CPUState *env)
+{
+    return cpu_ppc_load_decr(env);
+}
+
+void store_booke_tsr (CPUState *env, target_ulong val)
+{
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
+    }
+#endif
+    env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
+    if (val & 0x80000000)
+        ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
+}
+
+void store_booke_tcr (CPUState *env, target_ulong val)
+{
+    ppc_tb_t *tb_env;
+
+    tb_env = env->tb_env;
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
+    }
+#endif
+    env->spr[SPR_40x_TCR] = val & 0xFFC00000;
+    start_stop_pit(env, tb_env, 1);
+    cpu_4xx_wdt_cb(env);
+}
+
+static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
+{
+    CPUState *env = opaque;
+    ppc_tb_t *tb_env = env->tb_env;
+
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s set new frequency to %u\n", __func__, freq);
+    }
+#endif
+    tb_env->tb_freq = freq;
+    /* XXX: we should also update all timers */
+}
+
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
+{
+    ppc_tb_t *tb_env;
+    ppcemb_timer_t *ppcemb_timer;
+
+    tb_env = qemu_mallocz(sizeof(ppc_tb_t));
+    if (tb_env == NULL) {
+        return NULL;
+    }
+    env->tb_env = tb_env;
+    ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
+    tb_env->tb_freq = freq;
+    tb_env->opaque = ppcemb_timer;
+#ifdef PPC_DEBUG_TB
+    if (loglevel != 0) {
+        fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer,
+                &ppc_emb_set_tb_clk);
+    }
+#endif
+    if (ppcemb_timer != NULL) {
+        /* We use decr timer for PIT */
+        tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
+        ppcemb_timer->fit_timer =
+            qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
+        ppcemb_timer->wdt_timer =
+            qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
     }
 
-    return tb_env;
+    return &ppc_emb_set_tb_clk;
 }
 
+/*****************************************************************************/
+/* Embedded PowerPC Device Control Registers */
+typedef struct ppc_dcrn_t ppc_dcrn_t;
+struct ppc_dcrn_t {
+    dcr_read_cb dcr_read;
+    dcr_write_cb dcr_write;
+    void *opaque;
+};
+
+/* XXX: on 460, DCR addresses are 32 bits wide,
+ *      using DCRIPR to get the 22 upper bits of the DCR address
+ */
+#define DCRN_NB 1024
+struct ppc_dcr_t {
+    ppc_dcrn_t dcrn[DCRN_NB];
+    int (*read_error)(int dcrn);
+    int (*write_error)(int dcrn);
+};
+
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
+{
+    ppc_dcrn_t *dcr;
+
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        goto error;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->dcr_read == NULL)
+        goto error;
+    *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
+
+    return 0;
+
+ error:
+    if (dcr_env->read_error != NULL)
+        return (*dcr_env->read_error)(dcrn);
+
+    return -1;
+}
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
+{
+    ppc_dcrn_t *dcr;
+
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        goto error;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->dcr_write == NULL)
+        goto error;
+    (*dcr->dcr_write)(dcr->opaque, dcrn, val);
+
+    return 0;
+
+ error:
+    if (dcr_env->write_error != NULL)
+        return (*dcr_env->write_error)(dcrn);
+
+    return -1;
+}
+
+int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
+                      dcr_read_cb dcr_read, dcr_write_cb dcr_write)
+{
+    ppc_dcr_t *dcr_env;
+    ppc_dcrn_t *dcr;
+
+    dcr_env = env->dcr_env;
+    if (dcr_env == NULL)
+        return -1;
+    if (dcrn < 0 || dcrn >= DCRN_NB)
+        return -1;
+    dcr = &dcr_env->dcrn[dcrn];
+    if (dcr->opaque != NULL ||
+        dcr->dcr_read != NULL ||
+        dcr->dcr_write != NULL)
+        return -1;
+    dcr->opaque = opaque;
+    dcr->dcr_read = dcr_read;
+    dcr->dcr_write = dcr_write;
+
+    return 0;
+}
+
+int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
+                  int (*write_error)(int dcrn))
+{
+    ppc_dcr_t *dcr_env;
+
+    dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
+    if (dcr_env == NULL)
+        return -1;
+    dcr_env->read_error = read_error;
+    dcr_env->write_error = write_error;
+    env->dcr_env = dcr_env;
+
+    return 0;
+}
+
+
 #if 0
 /*****************************************************************************/
 /* Handle system reset (for now, just stop emulation) */
@@ -264,6 +1221,7 @@
     tmp |= m48t59_read(nvram, addr + 1) << 16;
     tmp |= m48t59_read(nvram, addr + 2) << 8;
     tmp |= m48t59_read(nvram, addr + 3);
+
     return tmp;
 }
 
@@ -316,10 +1274,10 @@
     odd = count & 1;
     count &= ~1;
     for (i = 0; i != count; i++) {
-	crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
+        crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
     }
     if (odd) {
-	crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
+        crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
     }
 
     return crc;
diff --git a/hw/ppc405.h b/hw/ppc405.h
new file mode 100644
index 0000000..eacbefe
--- /dev/null
+++ b/hw/ppc405.h
@@ -0,0 +1,126 @@
+/*
+ * QEMU PowerPC 405 shared definitions
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#if !defined(PPC_405_H)
+#define PPC_405_H
+
+/* Bootinfo as set-up by u-boot */
+typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t;
+struct ppc4xx_bd_info_t {
+    uint32_t bi_memstart;
+    uint32_t bi_memsize;
+    uint32_t bi_flashstart;
+    uint32_t bi_flashsize;
+    uint32_t bi_flashoffset; /* 0x10 */
+    uint32_t bi_sramstart;
+    uint32_t bi_sramsize;
+    uint32_t bi_bootflags;
+    uint32_t bi_ipaddr; /* 0x20 */
+    uint8_t  bi_enetaddr[6];
+    uint16_t bi_ethspeed;
+    uint32_t bi_intfreq;
+    uint32_t bi_busfreq; /* 0x30 */
+    uint32_t bi_baudrate;
+    uint8_t  bi_s_version[4];
+    uint8_t  bi_r_version[32];
+    uint32_t bi_procfreq;
+    uint32_t bi_plb_busfreq;
+    uint32_t bi_pci_busfreq;
+    uint8_t  bi_pci_enetaddr[6];
+    uint32_t bi_pci_enetaddr2[6];
+    uint32_t bi_opbfreq;
+    uint32_t bi_iic_fast[2];
+};
+
+/* PowerPC 405 core */
+CPUState *ppc405_init (const unsigned char *cpu_model,
+                       clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+                       uint32_t sysclk);
+ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
+                                uint32_t flags);
+
+/* */
+typedef struct ppc4xx_mmio_t ppc4xx_mmio_t;
+int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio,
+                          target_phys_addr_t offset, uint32_t len,
+                          CPUReadMemoryFunc **mem_read,
+                          CPUWriteMemoryFunc **mem_write, void *opaque);
+ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base);
+/* PowerPC 4xx peripheral local bus arbitrer */
+void ppc4xx_plb_init (CPUState *env);
+/* PLB to OPB bridge */
+void ppc4xx_pob_init (CPUState *env);
+/* OPB arbitrer */
+void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                       target_phys_addr_t offset);
+/* PowerPC 4xx universal interrupt controller */
+enum {
+    PPCUIC_OUTPUT_INT = 0,
+    PPCUIC_OUTPUT_CINT = 1,
+    PPCUIC_OUTPUT_NB,
+};
+qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
+                       uint32_t dcr_base, int has_ssr, int has_vr);
+/* SDRAM controller */
+void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+                        target_phys_addr_t *ram_bases,
+                        target_phys_addr_t *ram_sizes,
+                        int do_init);
+/* Peripheral controller */
+void ppc405_ebc_init (CPUState *env);
+/* DMA controller */
+void ppc405_dma_init (CPUState *env, qemu_irq irqs[4]);
+/* GPIO */
+void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                       target_phys_addr_t offset);
+/* Serial ports */
+void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                         target_phys_addr_t offset, qemu_irq irq,
+                         CharDriverState *chr);
+/* On Chip Memory */
+void ppc405_ocm_init (CPUState *env, unsigned long offset);
+/* I2C controller */
+void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                      target_phys_addr_t offset, qemu_irq irq);
+/* General purpose timers */
+void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                      target_phys_addr_t offset, qemu_irq irq[5]);
+/* Memory access layer */
+void ppc405_mal_init (CPUState *env, qemu_irq irqs[4]);
+/* PowerPC 405 microcontrollers */
+CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
+                         target_phys_addr_t ram_sizes[4],
+                         uint32_t sysclk, qemu_irq **picp,
+                         ram_addr_t *offsetp, int do_init);
+CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
+                         target_phys_addr_t ram_sizes[2],
+                         uint32_t sysclk, qemu_irq **picp,
+                         ram_addr_t *offsetp, int do_init);
+/* IBM STBxxx microcontrollers */
+CPUState *ppc_stb025_init (target_phys_addr_t ram_bases[2],
+                           target_phys_addr_t ram_sizes[2],
+                           uint32_t sysclk, qemu_irq **picp,
+                           ram_addr_t *offsetp);
+
+#endif /* !defined(PPC_405_H) */
diff --git a/hw/ppc405_boards.c b/hw/ppc405_boards.c
new file mode 100644
index 0000000..8f82ea9
--- /dev/null
+++ b/hw/ppc405_boards.c
@@ -0,0 +1,630 @@
+/*
+ * QEMU PowerPC 405 evaluation boards emulation
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+#include "ppc405.h"
+
+extern int loglevel;
+extern FILE *logfile;
+
+#define BIOS_FILENAME "ppc405_rom.bin"
+#undef BIOS_SIZE
+#define BIOS_SIZE (2048 * 1024)
+
+#define KERNEL_LOAD_ADDR 0x00000000
+#define INITRD_LOAD_ADDR 0x01800000
+
+#define USE_FLASH_BIOS
+
+#define DEBUG_BOARD_INIT
+
+/*****************************************************************************/
+/* PPC405EP reference board (IBM) */
+/* Standalone board with:
+ * - PowerPC 405EP CPU
+ * - SDRAM (0x00000000)
+ * - Flash (0xFFF80000)
+ * - SRAM  (0xFFF00000)
+ * - NVRAM (0xF0000000)
+ * - FPGA  (0xF0300000)
+ */
+typedef struct ref405ep_fpga_t ref405ep_fpga_t;
+struct ref405ep_fpga_t {
+    uint32_t base;
+    uint8_t reg0;
+    uint8_t reg1;
+};
+
+static uint32_t ref405ep_fpga_readb (void *opaque, target_phys_addr_t addr)
+{
+    ref405ep_fpga_t *fpga;
+    uint32_t ret;
+
+    fpga = opaque;
+    addr -= fpga->base;
+    switch (addr) {
+    case 0x0:
+        ret = fpga->reg0;
+        break;
+    case 0x1:
+        ret = fpga->reg1;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void ref405ep_fpga_writeb (void *opaque,
+                                  target_phys_addr_t addr, uint32_t value)
+{
+    ref405ep_fpga_t *fpga;
+
+    fpga = opaque;
+    addr -= fpga->base;
+    switch (addr) {
+    case 0x0:
+        /* Read only */
+        break;
+    case 0x1:
+        fpga->reg1 = value;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t ref405ep_fpga_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    ret = ref405ep_fpga_readb(opaque, addr) << 8;
+    ret |= ref405ep_fpga_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void ref405ep_fpga_writew (void *opaque,
+                                  target_phys_addr_t addr, uint32_t value)
+{
+    ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF);
+}
+
+static uint32_t ref405ep_fpga_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    ret = ref405ep_fpga_readb(opaque, addr) << 24;
+    ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16;
+    ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8;
+    ret |= ref405ep_fpga_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void ref405ep_fpga_writel (void *opaque,
+                                  target_phys_addr_t addr, uint32_t value)
+{
+    ref405ep_fpga_writel(opaque, addr, (value >> 24) & 0xFF);
+    ref405ep_fpga_writel(opaque, addr + 1, (value >> 16) & 0xFF);
+    ref405ep_fpga_writel(opaque, addr + 2, (value >> 8) & 0xFF);
+    ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
+}
+
+static CPUReadMemoryFunc *ref405ep_fpga_read[] = {
+    &ref405ep_fpga_readb,
+    &ref405ep_fpga_readw,
+    &ref405ep_fpga_readl,
+};
+
+static CPUWriteMemoryFunc *ref405ep_fpga_write[] = {
+    &ref405ep_fpga_writeb,
+    &ref405ep_fpga_writew,
+    &ref405ep_fpga_writel,
+};
+
+static void ref405ep_fpga_reset (void *opaque)
+{
+    ref405ep_fpga_t *fpga;
+
+    fpga = opaque;
+    fpga->reg0 = 0x00;
+    fpga->reg1 = 0x0F;
+}
+
+static void ref405ep_fpga_init (uint32_t base)
+{
+    ref405ep_fpga_t *fpga;
+    int fpga_memory;
+
+    fpga = qemu_mallocz(sizeof(ref405ep_fpga_t));
+    if (fpga != NULL) {
+        fpga->base = base;
+        fpga_memory = cpu_register_io_memory(0, ref405ep_fpga_read,
+                                             ref405ep_fpga_write, fpga);
+        cpu_register_physical_memory(base, 0x00000100, fpga_memory);
+        ref405ep_fpga_reset(fpga);
+        qemu_register_reset(&ref405ep_fpga_reset, fpga);
+    }
+}
+
+static void ref405ep_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)
+{
+    char buf[1024];
+    ppc4xx_bd_info_t bd;
+    CPUPPCState *env;
+    qemu_irq *pic;
+    ram_addr_t sram_offset, bios_offset, bdloc;
+    target_phys_addr_t ram_bases[2], ram_sizes[2];
+    target_ulong sram_size, bios_size;
+    //int phy_addr = 0;
+    //static int phy_addr = 1;
+    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+    int linux_boot;
+    int fl_idx, fl_sectors, len;
+
+    /* XXX: fix this */
+    ram_bases[0] = 0x00000000;
+    ram_sizes[0] = 0x08000000;
+    ram_bases[1] = 0x00000000;
+    ram_sizes[1] = 0x00000000;
+    ram_size = 128 * 1024 * 1024;
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register cpu\n", __func__);
+#endif
+    env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &sram_offset,
+                        kernel_filename == NULL ? 0 : 1);
+    /* allocate SRAM */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset);
+#endif
+    sram_size = 512 * 1024;
+    cpu_register_physical_memory(0xFFF00000, sram_size,
+                                 sram_offset | IO_MEM_RAM);
+    /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register BIOS\n", __func__);
+#endif
+    bios_offset = sram_offset + sram_size;
+    fl_idx = 0;
+#ifdef USE_FLASH_BIOS
+    if (pflash_table[fl_idx] != NULL) {
+        bios_size = bdrv_getlength(pflash_table[fl_idx]);
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size " ADDRX " at offset %08lx "
+               " addr " ADDRX " '%s' %d\n",
+               fl_idx, bios_size, bios_offset, -bios_size,
+               bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors);
+#endif
+        pflash_register(-(bios_size), bios_offset, pflash_table[fl_idx],
+                        65536, fl_sectors, 2,
+                        0x0001, 0x22DA, 0x0000, 0x0000);
+        fl_idx++;
+    } else
+#endif
+    {
+#ifdef DEBUG_BOARD_INIT
+        printf("Load BIOS from file\n");
+#endif
+        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+        bios_size = load_image(buf, phys_ram_base + bios_offset);
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+            exit(1);
+        }
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+        cpu_register_physical_memory((uint32_t)(-bios_size),
+                                     bios_size, bios_offset | IO_MEM_ROM);
+    }
+    bios_offset += bios_size;
+    /* Register FPGA */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register FPGA\n", __func__);
+#endif
+    ref405ep_fpga_init(0xF0300000);
+    /* Register NVRAM */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register NVRAM\n", __func__);
+#endif
+    m48t59_init(NULL, 0xF0000000, 0, 8192, 8);
+    /* Load kernel */
+    linux_boot = (kernel_filename != NULL);
+    if (linux_boot) {
+#ifdef DEBUG_BOARD_INIT
+        printf("%s: load kernel\n", __func__);
+#endif
+        memset(&bd, 0, sizeof(bd));
+        bd.bi_memstart = 0x00000000;
+        bd.bi_memsize = ram_size;
+        bd.bi_flashstart = -(bios_size);
+        bd.bi_flashsize = -bios_size;
+        bd.bi_flashoffset = 0;
+        bd.bi_sramstart = 0xFFF00000;
+        bd.bi_sramsize = sram_size;
+        bd.bi_bootflags = 0;
+        bd.bi_intfreq = 133333333;
+        bd.bi_busfreq = 33333333;
+        bd.bi_baudrate = 115200;
+        bd.bi_s_version[0] = 'Q';
+        bd.bi_s_version[1] = 'M';
+        bd.bi_s_version[2] = 'U';
+        bd.bi_s_version[3] = '\0';
+        bd.bi_r_version[0] = 'Q';
+        bd.bi_r_version[1] = 'E';
+        bd.bi_r_version[2] = 'M';
+        bd.bi_r_version[3] = 'U';
+        bd.bi_r_version[4] = '\0';
+        bd.bi_procfreq = 133333333;
+        bd.bi_plb_busfreq = 33333333;
+        bd.bi_pci_busfreq = 33333333;
+        bd.bi_opbfreq = 33333333;
+        bdloc = ppc405_set_bootinfo(env, &bd, 0x00000001);
+        env->gpr[3] = bdloc;
+        kernel_base = KERNEL_LOAD_ADDR;
+        /* now we can load the kernel */
+        kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx
+               " %02x %02x %02x %02x\n", kernel_size, kernel_base,
+               *(char *)(phys_ram_base + kernel_base),
+               *(char *)(phys_ram_base + kernel_base + 1),
+               *(char *)(phys_ram_base + kernel_base + 2),
+               *(char *)(phys_ram_base + kernel_base + 3));
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image(initrd_filename,
+                                     phys_ram_base + initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+        env->gpr[4] = initrd_base;
+        env->gpr[5] = initrd_size;
+        boot_device = 'm';
+        if (kernel_cmdline != NULL) {
+            len = strlen(kernel_cmdline);
+            bdloc -= ((len + 255) & ~255);
+            memcpy(phys_ram_base + bdloc, kernel_cmdline, len + 1);
+            env->gpr[6] = bdloc;
+            env->gpr[7] = bdloc + len;
+        } else {
+            env->gpr[6] = 0;
+            env->gpr[7] = 0;
+        }
+        env->nip = KERNEL_LOAD_ADDR;
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+        bdloc = 0;
+    }
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: Done\n", __func__);
+#endif
+    printf("bdloc %016lx %s\n",
+           (unsigned long)bdloc, (char *)(phys_ram_base + bdloc));
+}
+
+QEMUMachine ref405ep_machine = {
+    "ref405ep",
+    "ref405ep",
+    ref405ep_init,
+};
+
+/*****************************************************************************/
+/* AMCC Taihu evaluation board */
+/* - PowerPC 405EP processor
+ * - SDRAM               128 MB at 0x00000000
+ * - Boot flash          2 MB   at 0xFFE00000
+ * - Application flash   32 MB  at 0xFC000000
+ * - 2 serial ports
+ * - 2 ethernet PHY
+ * - 1 USB 1.1 device    0x50000000
+ * - 1 LCD display       0x50100000
+ * - 1 CPLD              0x50100000
+ * - 1 I2C EEPROM
+ * - 1 I2C thermal sensor
+ * - a set of LEDs
+ * - bit-bang SPI port using GPIOs
+ * - 1 EBC interface connector 0 0x50200000
+ * - 1 cardbus controller + expansion slot.
+ * - 1 PCI expansion slot.
+ */
+typedef struct taihu_cpld_t taihu_cpld_t;
+struct taihu_cpld_t {
+    uint32_t base;
+    uint8_t reg0;
+    uint8_t reg1;
+};
+
+static uint32_t taihu_cpld_readb (void *opaque, target_phys_addr_t addr)
+{
+    taihu_cpld_t *cpld;
+    uint32_t ret;
+
+    cpld = opaque;
+    addr -= cpld->base;
+    switch (addr) {
+    case 0x0:
+        ret = cpld->reg0;
+        break;
+    case 0x1:
+        ret = cpld->reg1;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void taihu_cpld_writeb (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    taihu_cpld_t *cpld;
+
+    cpld = opaque;
+    addr -= cpld->base;
+    switch (addr) {
+    case 0x0:
+        /* Read only */
+        break;
+    case 0x1:
+        cpld->reg1 = value;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t taihu_cpld_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    ret = taihu_cpld_readb(opaque, addr) << 8;
+    ret |= taihu_cpld_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void taihu_cpld_writew (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF);
+    taihu_cpld_writeb(opaque, addr + 1, value & 0xFF);
+}
+
+static uint32_t taihu_cpld_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+    ret = taihu_cpld_readb(opaque, addr) << 24;
+    ret |= taihu_cpld_readb(opaque, addr + 1) << 16;
+    ret |= taihu_cpld_readb(opaque, addr + 2) << 8;
+    ret |= taihu_cpld_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void taihu_cpld_writel (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF);
+    taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF);
+    taihu_cpld_writel(opaque, addr + 2, (value >> 8) & 0xFF);
+    taihu_cpld_writeb(opaque, addr + 3, value & 0xFF);
+}
+
+static CPUReadMemoryFunc *taihu_cpld_read[] = {
+    &taihu_cpld_readb,
+    &taihu_cpld_readw,
+    &taihu_cpld_readl,
+};
+
+static CPUWriteMemoryFunc *taihu_cpld_write[] = {
+    &taihu_cpld_writeb,
+    &taihu_cpld_writew,
+    &taihu_cpld_writel,
+};
+
+static void taihu_cpld_reset (void *opaque)
+{
+    taihu_cpld_t *cpld;
+
+    cpld = opaque;
+    cpld->reg0 = 0x01;
+    cpld->reg1 = 0x80;
+}
+
+static void taihu_cpld_init (uint32_t base)
+{
+    taihu_cpld_t *cpld;
+    int cpld_memory;
+
+    cpld = qemu_mallocz(sizeof(taihu_cpld_t));
+    if (cpld != NULL) {
+        cpld->base = base;
+        cpld_memory = cpu_register_io_memory(0, taihu_cpld_read,
+                                             taihu_cpld_write, cpld);
+        cpu_register_physical_memory(base, 0x00000100, cpld_memory);
+        taihu_cpld_reset(cpld);
+        qemu_register_reset(&taihu_cpld_reset, cpld);
+    }
+}
+
+static void taihu_405ep_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)
+{
+    char buf[1024];
+    CPUPPCState *env;
+    qemu_irq *pic;
+    ram_addr_t bios_offset;
+    target_phys_addr_t ram_bases[2], ram_sizes[2];
+    target_ulong bios_size;
+    target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+    int linux_boot;
+    int fl_idx, fl_sectors;
+
+    /* RAM is soldered to the board so the size cannot be changed */
+    ram_bases[0] = 0x00000000;
+    ram_sizes[0] = 0x04000000;
+    ram_bases[1] = 0x04000000;
+    ram_sizes[1] = 0x04000000;
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register cpu\n", __func__);
+#endif
+    env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &bios_offset,
+                        kernel_filename == NULL ? 0 : 1);
+    /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register BIOS\n", __func__);
+#endif
+    fl_idx = 0;
+#if defined(USE_FLASH_BIOS)
+    if (pflash_table[fl_idx] != NULL) {
+        bios_size = bdrv_getlength(pflash_table[fl_idx]);
+        /* XXX: should check that size is 2MB */
+        //        bios_size = 2 * 1024 * 1024;
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size " ADDRX " at offset %08lx "
+               " addr " ADDRX " '%s' %d\n",
+               fl_idx, bios_size, bios_offset, -bios_size,
+               bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors);
+#endif
+        pflash_register(-(bios_size), bios_offset, pflash_table[fl_idx],
+                        65536, fl_sectors, 4,
+                        0x0001, 0x22DA, 0x0000, 0x0000);
+        fl_idx++;
+    } else
+#endif
+    {
+#ifdef DEBUG_BOARD_INIT
+        printf("Load BIOS from file\n");
+#endif
+        snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+        bios_size = load_image(buf, phys_ram_base + bios_offset);
+        if (bios_size < 0 || bios_size > BIOS_SIZE) {
+            fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+            exit(1);
+        }
+        bios_size = (bios_size + 0xfff) & ~0xfff;
+        cpu_register_physical_memory((uint32_t)(-bios_size),
+                                     bios_size, bios_offset | IO_MEM_ROM);
+    }
+    bios_offset += bios_size;
+    /* Register Linux flash */
+    if (pflash_table[fl_idx] != NULL) {
+        bios_size = bdrv_getlength(pflash_table[fl_idx]);
+        /* XXX: should check that size is 32MB */
+        bios_size = 32 * 1024 * 1024;
+        fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+        printf("Register parallel flash %d size " ADDRX " at offset %08lx "
+               " addr " ADDRX " '%s'\n",
+               fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
+               bdrv_get_device_name(pflash_table[fl_idx]));
+#endif
+        pflash_register(0xfc000000, bios_offset, pflash_table[fl_idx],
+                        65536, fl_sectors, 4,
+                        0x0001, 0x22DA, 0x0000, 0x0000);
+        fl_idx++;
+    }
+    /* Register CLPD & LCD display */
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: register CPLD\n", __func__);
+#endif
+    taihu_cpld_init(0x50100000);
+    /* Load kernel */
+    linux_boot = (kernel_filename != NULL);
+    if (linux_boot) {
+#ifdef DEBUG_BOARD_INIT
+        printf("%s: load kernel\n", __func__);
+#endif
+        kernel_base = KERNEL_LOAD_ADDR;
+        /* now we can load the kernel */
+        kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+        /* load initrd */
+        if (initrd_filename) {
+            initrd_base = INITRD_LOAD_ADDR;
+            initrd_size = load_image(initrd_filename,
+                                     phys_ram_base + initrd_base);
+            if (initrd_size < 0) {
+                fprintf(stderr,
+                        "qemu: could not load initial ram disk '%s'\n",
+                        initrd_filename);
+                exit(1);
+            }
+        } else {
+            initrd_base = 0;
+            initrd_size = 0;
+        }
+        boot_device = 'm';
+    } else {
+        kernel_base = 0;
+        kernel_size = 0;
+        initrd_base = 0;
+        initrd_size = 0;
+    }
+#ifdef DEBUG_BOARD_INIT
+    printf("%s: Done\n", __func__);
+#endif
+}
+
+QEMUMachine taihu_machine = {
+    "taihu",
+    "taihu",
+    taihu_405ep_init,
+};
diff --git a/hw/ppc405_uc.c b/hw/ppc405_uc.c
new file mode 100644
index 0000000..b6fc491
--- /dev/null
+++ b/hw/ppc405_uc.c
@@ -0,0 +1,3461 @@
+/*
+ * QEMU PowerPC 405 embedded processors emulation
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+#include "ppc405.h"
+
+extern int loglevel;
+extern FILE *logfile;
+
+//#define DEBUG_MMIO
+#define DEBUG_OPBA
+#define DEBUG_SDRAM
+#define DEBUG_GPIO
+#define DEBUG_SERIAL
+#define DEBUG_OCM
+//#define DEBUG_I2C
+#define DEBUG_GPT
+#define DEBUG_MAL
+#define DEBUG_UIC
+#define DEBUG_CLOCKS
+//#define DEBUG_UNASSIGNED
+
+/*****************************************************************************/
+/* Generic PowerPC 405 processor instanciation */
+CPUState *ppc405_init (const unsigned char *cpu_model,
+                       clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+                       uint32_t sysclk)
+{
+    CPUState *env;
+    ppc_def_t *def;
+
+    /* init CPUs */
+    env = cpu_init();
+    qemu_register_reset(&cpu_ppc_reset, env);
+    register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+    ppc_find_by_name(cpu_model, &def);
+    if (def == NULL) {
+        cpu_abort(env, "Unable to find PowerPC %s CPU definition\n",
+                  cpu_model);
+    }
+    cpu_ppc_register(env, def);
+    cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
+    cpu_clk->opaque = env;
+    /* Set time-base frequency to sysclk */
+    tb_clk->cb = ppc_emb_timers_init(env, sysclk);
+    tb_clk->opaque = env;
+    ppc_dcr_init(env, NULL, NULL);
+
+    return env;
+}
+
+ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd,
+                                uint32_t flags)
+{
+    ram_addr_t bdloc;
+    int i, n;
+
+    /* We put the bd structure at the top of memory */
+    if (bd->bi_memsize >= 0x01000000UL)
+        bdloc = 0x01000000UL - sizeof(struct ppc4xx_bd_info_t);
+    else
+        bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
+    stl_raw(phys_ram_base + bdloc + 0x00, bd->bi_memstart);
+    stl_raw(phys_ram_base + bdloc + 0x04, bd->bi_memsize);
+    stl_raw(phys_ram_base + bdloc + 0x08, bd->bi_flashstart);
+    stl_raw(phys_ram_base + bdloc + 0x0C, bd->bi_flashsize);
+    stl_raw(phys_ram_base + bdloc + 0x10, bd->bi_flashoffset);
+    stl_raw(phys_ram_base + bdloc + 0x14, bd->bi_sramstart);
+    stl_raw(phys_ram_base + bdloc + 0x18, bd->bi_sramsize);
+    stl_raw(phys_ram_base + bdloc + 0x1C, bd->bi_bootflags);
+    stl_raw(phys_ram_base + bdloc + 0x20, bd->bi_ipaddr);
+    for (i = 0; i < 6; i++)
+        stb_raw(phys_ram_base + bdloc + 0x24 + i, bd->bi_enetaddr[i]);
+    stw_raw(phys_ram_base + bdloc + 0x2A, bd->bi_ethspeed);
+    stl_raw(phys_ram_base + bdloc + 0x2C, bd->bi_intfreq);
+    stl_raw(phys_ram_base + bdloc + 0x30, bd->bi_busfreq);
+    stl_raw(phys_ram_base + bdloc + 0x34, bd->bi_baudrate);
+    for (i = 0; i < 4; i++)
+        stb_raw(phys_ram_base + bdloc + 0x38 + i, bd->bi_s_version[i]);
+    for (i = 0; i < 32; i++)
+        stb_raw(phys_ram_base + bdloc + 0x3C + i, bd->bi_s_version[i]);
+    stl_raw(phys_ram_base + bdloc + 0x5C, bd->bi_plb_busfreq);
+    stl_raw(phys_ram_base + bdloc + 0x60, bd->bi_pci_busfreq);
+    for (i = 0; i < 6; i++)
+        stb_raw(phys_ram_base + bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
+    n = 0x6A;
+    if (flags & 0x00000001) {
+        for (i = 0; i < 6; i++)
+            stb_raw(phys_ram_base + bdloc + n++, bd->bi_pci_enetaddr2[i]);
+    }
+    stl_raw(phys_ram_base + bdloc + n, bd->bi_opbfreq);
+    n += 4;
+    for (i = 0; i < 2; i++) {
+        stl_raw(phys_ram_base + bdloc + n, bd->bi_iic_fast[i]);
+        n += 4;
+    }
+
+    return bdloc;
+}
+
+/*****************************************************************************/
+/* Shared peripherals */
+
+/*****************************************************************************/
+/* Fake device used to map multiple devices in a single memory page */
+#define MMIO_AREA_BITS 8
+#define MMIO_AREA_LEN (1 << MMIO_AREA_BITS)
+#define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS))
+#define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1))
+struct ppc4xx_mmio_t {
+    target_phys_addr_t base;
+    CPUReadMemoryFunc **mem_read[MMIO_AREA_NB];
+    CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB];
+    void *opaque[MMIO_AREA_NB];
+};
+
+static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+    ppc4xx_mmio_t *mmio;
+
+    mmio = opaque;
+    printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n",
+           addr, mmio->base);
+#endif
+
+    return 0;
+}
+
+static void unassigned_mmio_writeb (void *opaque,
+                                   target_phys_addr_t addr, uint32_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+    ppc4xx_mmio_t *mmio;
+
+    mmio = opaque;
+    printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n",
+           addr, val, mmio->base);
+#endif
+}
+
+static CPUReadMemoryFunc *unassigned_mmio_read[3] = {
+    unassigned_mmio_readb,
+    unassigned_mmio_readb,
+    unassigned_mmio_readb,
+};
+
+static CPUWriteMemoryFunc *unassigned_mmio_write[3] = {
+    unassigned_mmio_writeb,
+    unassigned_mmio_writeb,
+    unassigned_mmio_writeb,
+};
+
+static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio,
+                              target_phys_addr_t addr, int len)
+{
+    CPUReadMemoryFunc **mem_read;
+    uint32_t ret;
+    int idx;
+
+    idx = MMIO_IDX(addr - mmio->base);
+#if defined(DEBUG_MMIO)
+    printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__,
+           mmio, len, addr, idx);
+#endif
+    mem_read = mmio->mem_read[idx];
+    ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base);
+
+    return ret;
+}
+
+static void mmio_writelen (ppc4xx_mmio_t *mmio,
+                           target_phys_addr_t addr, uint32_t value, int len)
+{
+    CPUWriteMemoryFunc **mem_write;
+    int idx;
+
+    idx = MMIO_IDX(addr - mmio->base);
+#if defined(DEBUG_MMIO)
+    printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__,
+           mmio, len, addr, idx, value);
+#endif
+    mem_write = mmio->mem_write[idx];
+    (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value);
+}
+
+static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_MMIO)
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+    return mmio_readlen(opaque, addr, 0);
+}
+
+static void mmio_writeb (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+#if defined(DEBUG_MMIO)
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    mmio_writelen(opaque, addr, value, 0);
+}
+
+static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_MMIO)
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+    return mmio_readlen(opaque, addr, 1);
+}
+
+static void mmio_writew (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+#if defined(DEBUG_MMIO)
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    mmio_writelen(opaque, addr, value, 1);
+}
+
+static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_MMIO)
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+    return mmio_readlen(opaque, addr, 2);
+}
+
+static void mmio_writel (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+#if defined(DEBUG_MMIO)
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    mmio_writelen(opaque, addr, value, 2);
+}
+
+static CPUReadMemoryFunc *mmio_read[] = {
+    &mmio_readb,
+    &mmio_readw,
+    &mmio_readl,
+};
+
+static CPUWriteMemoryFunc *mmio_write[] = {
+    &mmio_writeb,
+    &mmio_writew,
+    &mmio_writel,
+};
+
+int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio,
+                          target_phys_addr_t offset, uint32_t len,
+                          CPUReadMemoryFunc **mem_read,
+                          CPUWriteMemoryFunc **mem_write, void *opaque)
+{
+    uint32_t end;
+    int idx, eidx;
+
+    if ((offset + len) > TARGET_PAGE_SIZE)
+        return -1;
+    idx = MMIO_IDX(offset);
+    end = offset + len - 1;
+    eidx = MMIO_IDX(end);
+#if defined(DEBUG_MMIO)
+    printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len,
+           end, idx, eidx);
+#endif
+    for (; idx <= eidx; idx++) {
+        mmio->mem_read[idx] = mem_read;
+        mmio->mem_write[idx] = mem_write;
+        mmio->opaque[idx] = opaque;
+    }
+
+    return 0;
+}
+
+ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base)
+{
+    ppc4xx_mmio_t *mmio;
+    int mmio_memory;
+
+    mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t));
+    if (mmio != NULL) {
+        mmio->base = base;
+        mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio);
+#if defined(DEBUG_MMIO)
+        printf("%s: %p base %08x len %08x %d\n", __func__,
+               mmio, base, TARGET_PAGE_SIZE, mmio_memory);
+#endif
+        cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory);
+        ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE,
+                             unassigned_mmio_read, unassigned_mmio_write,
+                             mmio);
+    }
+
+    return mmio;
+}
+
+/*****************************************************************************/
+/* Peripheral local bus arbitrer */
+enum {
+    PLB0_BESR = 0x084,
+    PLB0_BEAR = 0x086,
+    PLB0_ACR  = 0x087,
+};
+
+typedef struct ppc4xx_plb_t ppc4xx_plb_t;
+struct ppc4xx_plb_t {
+    uint32_t acr;
+    uint32_t bear;
+    uint32_t besr;
+};
+
+static target_ulong dcr_read_plb (void *opaque, int dcrn)
+{
+    ppc4xx_plb_t *plb;
+    target_ulong ret;
+
+    plb = opaque;
+    switch (dcrn) {
+    case PLB0_ACR:
+        ret = plb->acr;
+        break;
+    case PLB0_BEAR:
+        ret = plb->bear;
+        break;
+    case PLB0_BESR:
+        ret = plb->besr;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_plb (void *opaque, int dcrn, target_ulong val)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = opaque;
+    switch (dcrn) {
+    case PLB0_ACR:
+        /* We don't care about the actual parameters written as
+         * we don't manage any priorities on the bus
+         */
+        plb->acr = val & 0xF8000000;
+        break;
+    case PLB0_BEAR:
+        /* Read only */
+        break;
+    case PLB0_BESR:
+        /* Write-clear */
+        plb->besr &= ~val;
+        break;
+    }
+}
+
+static void ppc4xx_plb_reset (void *opaque)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = opaque;
+    plb->acr = 0x00000000;
+    plb->bear = 0x00000000;
+    plb->besr = 0x00000000;
+}
+
+void ppc4xx_plb_init (CPUState *env)
+{
+    ppc4xx_plb_t *plb;
+
+    plb = qemu_mallocz(sizeof(ppc4xx_plb_t));
+    if (plb != NULL) {
+        ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
+        ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
+        ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
+        ppc4xx_plb_reset(plb);
+        qemu_register_reset(ppc4xx_plb_reset, plb);
+    }
+}
+
+/*****************************************************************************/
+/* PLB to OPB bridge */
+enum {
+    POB0_BESR0 = 0x0A0,
+    POB0_BESR1 = 0x0A2,
+    POB0_BEAR  = 0x0A4,
+};
+
+typedef struct ppc4xx_pob_t ppc4xx_pob_t;
+struct ppc4xx_pob_t {
+    uint32_t bear;
+    uint32_t besr[2];
+};
+
+static target_ulong dcr_read_pob (void *opaque, int dcrn)
+{
+    ppc4xx_pob_t *pob;
+    target_ulong ret;
+
+    pob = opaque;
+    switch (dcrn) {
+    case POB0_BEAR:
+        ret = pob->bear;
+        break;
+    case POB0_BESR0:
+    case POB0_BESR1:
+        ret = pob->besr[dcrn - POB0_BESR0];
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_pob (void *opaque, int dcrn, target_ulong val)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = opaque;
+    switch (dcrn) {
+    case POB0_BEAR:
+        /* Read only */
+        break;
+    case POB0_BESR0:
+    case POB0_BESR1:
+        /* Write-clear */
+        pob->besr[dcrn - POB0_BESR0] &= ~val;
+        break;
+    }
+}
+
+static void ppc4xx_pob_reset (void *opaque)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = opaque;
+    /* No error */
+    pob->bear = 0x00000000;
+    pob->besr[0] = 0x0000000;
+    pob->besr[1] = 0x0000000;
+}
+
+void ppc4xx_pob_init (CPUState *env)
+{
+    ppc4xx_pob_t *pob;
+
+    pob = qemu_mallocz(sizeof(ppc4xx_pob_t));
+    if (pob != NULL) {
+        ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob);
+        ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob);
+        ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob);
+        qemu_register_reset(ppc4xx_pob_reset, pob);
+        ppc4xx_pob_reset(env);
+    }
+}
+
+/*****************************************************************************/
+/* OPB arbitrer */
+typedef struct ppc4xx_opba_t ppc4xx_opba_t;
+struct ppc4xx_opba_t {
+    target_phys_addr_t base;
+    uint8_t cr;
+    uint8_t pr;
+};
+
+static uint32_t opba_readb (void *opaque, target_phys_addr_t addr)
+{
+    ppc4xx_opba_t *opba;
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    opba = opaque;
+    switch (addr - opba->base) {
+    case 0x00:
+        ret = opba->cr;
+        break;
+    case 0x01:
+        ret = opba->pr;
+        break;
+    default:
+        ret = 0x00;
+        break;
+    }
+
+    return ret;
+}
+
+static void opba_writeb (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+    ppc4xx_opba_t *opba;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    opba = opaque;
+    switch (addr - opba->base) {
+    case 0x00:
+        opba->cr = value & 0xF8;
+        break;
+    case 0x01:
+        opba->pr = value & 0xFF;
+        break;
+    default:
+        break;
+    }
+}
+
+static uint32_t opba_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    ret = opba_readb(opaque, addr) << 8;
+    ret |= opba_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void opba_writew (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_OPBA
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    opba_writeb(opaque, addr, value >> 8);
+    opba_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t opba_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_OPBA
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    ret = opba_readb(opaque, addr) << 24;
+    ret |= opba_readb(opaque, addr + 1) << 16;
+
+    return ret;
+}
+
+static void opba_writel (void *opaque,
+                         target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_OPBA
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    opba_writeb(opaque, addr, value >> 24);
+    opba_writeb(opaque, addr + 1, value >> 16);
+}
+
+static CPUReadMemoryFunc *opba_read[] = {
+    &opba_readb,
+    &opba_readw,
+    &opba_readl,
+};
+
+static CPUWriteMemoryFunc *opba_write[] = {
+    &opba_writeb,
+    &opba_writew,
+    &opba_writel,
+};
+
+static void ppc4xx_opba_reset (void *opaque)
+{
+    ppc4xx_opba_t *opba;
+
+    opba = opaque;
+    opba->cr = 0x00; /* No dynamic priorities - park disabled */
+    opba->pr = 0x11;
+}
+
+void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                       target_phys_addr_t offset)
+{
+    ppc4xx_opba_t *opba;
+
+    opba = qemu_mallocz(sizeof(ppc4xx_opba_t));
+    if (opba != NULL) {
+        opba->base = offset;
+#ifdef DEBUG_OPBA
+        printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+        ppc4xx_mmio_register(env, mmio, offset, 0x002,
+                             opba_read, opba_write, opba);
+        qemu_register_reset(ppc4xx_opba_reset, opba);
+        ppc4xx_opba_reset(opba);
+    }
+}
+
+/*****************************************************************************/
+/* "Universal" Interrupt controller */
+enum {
+    DCR_UICSR  = 0x000,
+    DCR_UICSRS = 0x001,
+    DCR_UICER  = 0x002,
+    DCR_UICCR  = 0x003,
+    DCR_UICPR  = 0x004,
+    DCR_UICTR  = 0x005,
+    DCR_UICMSR = 0x006,
+    DCR_UICVR  = 0x007,
+    DCR_UICVCR = 0x008,
+    DCR_UICMAX = 0x009,
+};
+
+#define UIC_MAX_IRQ 32
+typedef struct ppcuic_t ppcuic_t;
+struct ppcuic_t {
+    uint32_t dcr_base;
+    int use_vectors;
+    uint32_t uicsr;  /* Status register */
+    uint32_t uicer;  /* Enable register */
+    uint32_t uiccr;  /* Critical register */
+    uint32_t uicpr;  /* Polarity register */
+    uint32_t uictr;  /* Triggering register */
+    uint32_t uicvcr; /* Vector configuration register */
+    uint32_t uicvr;
+    qemu_irq *irqs;
+};
+
+static void ppcuic_trigger_irq (ppcuic_t *uic)
+{
+    uint32_t ir, cr;
+    int start, end, inc, i;
+
+    /* Trigger interrupt if any is pending */
+    ir = uic->uicsr & uic->uicer & (~uic->uiccr);
+    cr = uic->uicsr & uic->uicer & uic->uiccr;
+#ifdef DEBUG_UIC
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n"
+                "   %08x ir %08x cr %08x\n", __func__,
+                uic->uicsr, uic->uicer, uic->uiccr,
+                uic->uicsr & uic->uicer, ir, cr);
+    }
+#endif
+    if (ir != 0x0000000) {
+#ifdef DEBUG_UIC
+        if (loglevel & CPU_LOG_INT) {
+            fprintf(logfile, "Raise UIC interrupt\n");
+        }
+#endif
+        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
+    } else {
+#ifdef DEBUG_UIC
+        if (loglevel & CPU_LOG_INT) {
+            fprintf(logfile, "Lower UIC interrupt\n");
+        }
+#endif
+        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
+    }
+    /* Trigger critical interrupt if any is pending and update vector */
+    if (cr != 0x0000000) {
+        qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
+        if (uic->use_vectors) {
+            /* Compute critical IRQ vector */
+            if (uic->uicvcr & 1) {
+                start = 31;
+                end = 0;
+                inc = -1;
+            } else {
+                start = 0;
+                end = 31;
+                inc = 1;
+            }
+            uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
+            for (i = start; i <= end; i += inc) {
+                if (cr & (1 << i)) {
+                    uic->uicvr += (i - start) * 512 * inc;
+                    break;
+                }
+            }
+        }
+#ifdef DEBUG_UIC
+        if (loglevel & CPU_LOG_INT) {
+            fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n",
+                    uic->uicvr);
+        }
+#endif
+    } else {
+#ifdef DEBUG_UIC
+        if (loglevel & CPU_LOG_INT) {
+            fprintf(logfile, "Lower UIC critical interrupt\n");
+        }
+#endif
+        qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
+        uic->uicvr = 0x00000000;
+    }
+}
+
+static void ppcuic_set_irq (void *opaque, int irq_num, int level)
+{
+    ppcuic_t *uic;
+    uint32_t mask, sr;
+
+    uic = opaque;
+    mask = 1 << irq_num;
+#ifdef DEBUG_UIC
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x "
+                "%08x\n", __func__, irq_num, level,
+                uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
+    }
+#endif
+    if (irq_num < 0 || irq_num > 31)
+        return;
+    sr = uic->uicsr;
+    if (!(uic->uicpr & mask)) {
+        /* Negatively asserted IRQ */
+        level = level == 0 ? 1 : 0;
+    }
+    /* Update status register */
+    if (uic->uictr & mask) {
+        /* Edge sensitive interrupt */
+        if (level == 1)
+            uic->uicsr |= mask;
+    } else {
+        /* Level sensitive interrupt */
+        if (level == 1)
+            uic->uicsr |= mask;
+        else
+            uic->uicsr &= ~mask;
+    }
+#ifdef DEBUG_UIC
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__,
+                irq_num, level, uic->uicsr, sr);
+    }
+#endif
+    if (sr != uic->uicsr)
+        ppcuic_trigger_irq(uic);
+}
+
+static target_ulong dcr_read_uic (void *opaque, int dcrn)
+{
+    ppcuic_t *uic;
+    target_ulong ret;
+
+    uic = opaque;
+    dcrn -= uic->dcr_base;
+    switch (dcrn) {
+    case DCR_UICSR:
+    case DCR_UICSRS:
+        ret = uic->uicsr;
+        break;
+    case DCR_UICER:
+        ret = uic->uicer;
+        break;
+    case DCR_UICCR:
+        ret = uic->uiccr;
+        break;
+    case DCR_UICPR:
+        ret = uic->uicpr;
+        break;
+    case DCR_UICTR:
+        ret = uic->uictr;
+        break;
+    case DCR_UICMSR:
+        ret = uic->uicsr & uic->uicer;
+        break;
+    case DCR_UICVR:
+        if (!uic->use_vectors)
+            goto no_read;
+        ret = uic->uicvr;
+        break;
+    case DCR_UICVCR:
+        if (!uic->use_vectors)
+            goto no_read;
+        ret = uic->uicvcr;
+        break;
+    default:
+    no_read:
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_uic (void *opaque, int dcrn, target_ulong val)
+{
+    ppcuic_t *uic;
+
+    uic = opaque;
+    dcrn -= uic->dcr_base;
+#ifdef DEBUG_UIC
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val);
+    }
+#endif
+    switch (dcrn) {
+    case DCR_UICSR:
+        uic->uicsr &= ~val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICSRS:
+        uic->uicsr |= val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICER:
+        uic->uicer = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICCR:
+        uic->uiccr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICPR:
+        uic->uicpr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICTR:
+        uic->uictr = val;
+        ppcuic_trigger_irq(uic);
+        break;
+    case DCR_UICMSR:
+        break;
+    case DCR_UICVR:
+        break;
+    case DCR_UICVCR:
+        uic->uicvcr = val & 0xFFFFFFFD;
+        ppcuic_trigger_irq(uic);
+        break;
+    }
+}
+
+static void ppcuic_reset (void *opaque)
+{
+    ppcuic_t *uic;
+
+    uic = opaque;
+    uic->uiccr = 0x00000000;
+    uic->uicer = 0x00000000;
+    uic->uicpr = 0x00000000;
+    uic->uicsr = 0x00000000;
+    uic->uictr = 0x00000000;
+    if (uic->use_vectors) {
+        uic->uicvcr = 0x00000000;
+        uic->uicvr = 0x0000000;
+    }
+}
+
+qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
+                       uint32_t dcr_base, int has_ssr, int has_vr)
+{
+    ppcuic_t *uic;
+    int i;
+
+    uic = qemu_mallocz(sizeof(ppcuic_t));
+    if (uic != NULL) {
+        uic->dcr_base = dcr_base;
+        uic->irqs = irqs;
+        if (has_vr)
+            uic->use_vectors = 1;
+        for (i = 0; i < DCR_UICMAX; i++) {
+            ppc_dcr_register(env, dcr_base + i, uic,
+                             &dcr_read_uic, &dcr_write_uic);
+        }
+        qemu_register_reset(ppcuic_reset, uic);
+        ppcuic_reset(uic);
+    }
+
+    return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
+}
+
+/*****************************************************************************/
+/* Code decompression controller */
+/* XXX: TODO */
+
+/*****************************************************************************/
+/* SDRAM controller */
+typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
+struct ppc4xx_sdram_t {
+    uint32_t addr;
+    int nbanks;
+    target_phys_addr_t ram_bases[4];
+    target_phys_addr_t ram_sizes[4];
+    uint32_t besr0;
+    uint32_t besr1;
+    uint32_t bear;
+    uint32_t cfg;
+    uint32_t status;
+    uint32_t rtr;
+    uint32_t pmit;
+    uint32_t bcr[4];
+    uint32_t tr;
+    uint32_t ecccfg;
+    uint32_t eccesr;
+    qemu_irq irq;
+};
+
+enum {
+    SDRAM0_CFGADDR = 0x010,
+    SDRAM0_CFGDATA = 0x011,
+};
+
+static uint32_t sdram_bcr (target_phys_addr_t ram_base,
+                           target_phys_addr_t ram_size)
+{
+    uint32_t bcr;
+
+    switch (ram_size) {
+    case (4 * 1024 * 1024):
+        bcr = 0x00000000;
+        break;
+    case (8 * 1024 * 1024):
+        bcr = 0x00020000;
+        break;
+    case (16 * 1024 * 1024):
+        bcr = 0x00040000;
+        break;
+    case (32 * 1024 * 1024):
+        bcr = 0x00060000;
+        break;
+    case (64 * 1024 * 1024):
+        bcr = 0x00080000;
+        break;
+    case (128 * 1024 * 1024):
+        bcr = 0x000A0000;
+        break;
+    case (256 * 1024 * 1024):
+        bcr = 0x000C0000;
+        break;
+    default:
+        printf("%s: invalid RAM size " TARGET_FMT_plx "\n",
+               __func__, ram_size);
+        return 0x00000000;
+    }
+    bcr |= ram_base & 0xFF800000;
+    bcr |= 1;
+
+    return bcr;
+}
+
+static inline target_phys_addr_t sdram_base (uint32_t bcr)
+{
+    return bcr & 0xFF800000;
+}
+
+static target_ulong sdram_size (uint32_t bcr)
+{
+    target_ulong size;
+    int sh;
+
+    sh = (bcr >> 17) & 0x7;
+    if (sh == 7)
+        size = -1;
+    else
+        size = (4 * 1024 * 1024) << sh;
+
+    return size;
+}
+
+static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled)
+{
+    if (*bcrp & 0x00000001) {
+        /* Unmap RAM */
+#ifdef DEBUG_SDRAM
+        printf("%s: unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(*bcrp), sdram_size(*bcrp));
+#endif
+        cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp),
+                                     IO_MEM_UNASSIGNED);
+    }
+    *bcrp = bcr & 0xFFDEE001;
+    if (enabled && (bcr & 0x00000001)) {
+#ifdef DEBUG_SDRAM
+        printf("%s: Map RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(bcr), sdram_size(bcr));
+#endif
+        cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr),
+                                     sdram_base(bcr) | IO_MEM_RAM);
+    }
+}
+
+static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
+{
+    int i;
+
+    for (i = 0; i < sdram->nbanks; i++) {
+        if (sdram->ram_sizes[i] != 0) {
+            sdram_set_bcr(&sdram->bcr[i],
+                          sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
+                          1);
+        } else {
+            sdram_set_bcr(&sdram->bcr[i], 0x00000000, 0);
+        }
+    }
+}
+
+static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
+{
+    int i;
+
+    for (i = 0; i < sdram->nbanks; i++) {
+#ifdef DEBUG_SDRAM
+        printf("%s: Unmap RAM area " TARGET_FMT_plx " " TARGET_FMT_lx "\n",
+               __func__, sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
+#endif
+        cpu_register_physical_memory(sdram_base(sdram->bcr[i]),
+                                     sdram_size(sdram->bcr[i]),
+                                     IO_MEM_UNASSIGNED);
+    }
+}
+
+static target_ulong dcr_read_sdram (void *opaque, int dcrn)
+{
+    ppc4xx_sdram_t *sdram;
+    target_ulong ret;
+
+    sdram = opaque;
+    switch (dcrn) {
+    case SDRAM0_CFGADDR:
+        ret = sdram->addr;
+        break;
+    case SDRAM0_CFGDATA:
+        switch (sdram->addr) {
+        case 0x00: /* SDRAM_BESR0 */
+            ret = sdram->besr0;
+            break;
+        case 0x08: /* SDRAM_BESR1 */
+            ret = sdram->besr1;
+            break;
+        case 0x10: /* SDRAM_BEAR */
+            ret = sdram->bear;
+            break;
+        case 0x20: /* SDRAM_CFG */
+            ret = sdram->cfg;
+            break;
+        case 0x24: /* SDRAM_STATUS */
+            ret = sdram->status;
+            break;
+        case 0x30: /* SDRAM_RTR */
+            ret = sdram->rtr;
+            break;
+        case 0x34: /* SDRAM_PMIT */
+            ret = sdram->pmit;
+            break;
+        case 0x40: /* SDRAM_B0CR */
+            ret = sdram->bcr[0];
+            break;
+        case 0x44: /* SDRAM_B1CR */
+            ret = sdram->bcr[1];
+            break;
+        case 0x48: /* SDRAM_B2CR */
+            ret = sdram->bcr[2];
+            break;
+        case 0x4C: /* SDRAM_B3CR */
+            ret = sdram->bcr[3];
+            break;
+        case 0x80: /* SDRAM_TR */
+            ret = -1; /* ? */
+            break;
+        case 0x94: /* SDRAM_ECCCFG */
+            ret = sdram->ecccfg;
+            break;
+        case 0x98: /* SDRAM_ECCESR */
+            ret = sdram->eccesr;
+            break;
+        default: /* Error */
+            ret = -1;
+            break;
+        }
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_sdram (void *opaque, int dcrn, target_ulong val)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = opaque;
+    switch (dcrn) {
+    case SDRAM0_CFGADDR:
+        sdram->addr = val;
+        break;
+    case SDRAM0_CFGDATA:
+        switch (sdram->addr) {
+        case 0x00: /* SDRAM_BESR0 */
+            sdram->besr0 &= ~val;
+            break;
+        case 0x08: /* SDRAM_BESR1 */
+            sdram->besr1 &= ~val;
+            break;
+        case 0x10: /* SDRAM_BEAR */
+            sdram->bear = val;
+            break;
+        case 0x20: /* SDRAM_CFG */
+            val &= 0xFFE00000;
+            if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+                printf("%s: enable SDRAM controller\n", __func__);
+#endif
+                /* validate all RAM mappings */
+                sdram_map_bcr(sdram);
+                sdram->status &= ~0x80000000;
+            } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+                printf("%s: disable SDRAM controller\n", __func__);
+#endif
+                /* invalidate all RAM mappings */
+                sdram_unmap_bcr(sdram);
+                sdram->status |= 0x80000000;
+            }
+            if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
+                sdram->status |= 0x40000000;
+            else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
+                sdram->status &= ~0x40000000;
+            sdram->cfg = val;
+            break;
+        case 0x24: /* SDRAM_STATUS */
+            /* Read-only register */
+            break;
+        case 0x30: /* SDRAM_RTR */
+            sdram->rtr = val & 0x3FF80000;
+            break;
+        case 0x34: /* SDRAM_PMIT */
+            sdram->pmit = (val & 0xF8000000) | 0x07C00000;
+            break;
+        case 0x40: /* SDRAM_B0CR */
+            sdram_set_bcr(&sdram->bcr[0], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x44: /* SDRAM_B1CR */
+            sdram_set_bcr(&sdram->bcr[1], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x48: /* SDRAM_B2CR */
+            sdram_set_bcr(&sdram->bcr[2], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x4C: /* SDRAM_B3CR */
+            sdram_set_bcr(&sdram->bcr[3], val, sdram->cfg & 0x80000000);
+            break;
+        case 0x80: /* SDRAM_TR */
+            sdram->tr = val & 0x018FC01F;
+            break;
+        case 0x94: /* SDRAM_ECCCFG */
+            sdram->ecccfg = val & 0x00F00000;
+            break;
+        case 0x98: /* SDRAM_ECCESR */
+            val &= 0xFFF0F000;
+            if (sdram->eccesr == 0 && val != 0)
+                qemu_irq_raise(sdram->irq);
+            else if (sdram->eccesr != 0 && val == 0)
+                qemu_irq_lower(sdram->irq);
+            sdram->eccesr = val;
+            break;
+        default: /* Error */
+            break;
+        }
+        break;
+    }
+}
+
+static void sdram_reset (void *opaque)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = opaque;
+    sdram->addr = 0x00000000;
+    sdram->bear = 0x00000000;
+    sdram->besr0 = 0x00000000; /* No error */
+    sdram->besr1 = 0x00000000; /* No error */
+    sdram->cfg = 0x00000000;
+    sdram->ecccfg = 0x00000000; /* No ECC */
+    sdram->eccesr = 0x00000000; /* No error */
+    sdram->pmit = 0x07C00000;
+    sdram->rtr = 0x05F00000;
+    sdram->tr = 0x00854009;
+    /* We pre-initialize RAM banks */
+    sdram->status = 0x00000000;
+    sdram->cfg = 0x00800000;
+    sdram_unmap_bcr(sdram);
+}
+
+void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+                        target_phys_addr_t *ram_bases,
+                        target_phys_addr_t *ram_sizes,
+                        int do_init)
+{
+    ppc4xx_sdram_t *sdram;
+
+    sdram = qemu_mallocz(sizeof(ppc4xx_sdram_t));
+    if (sdram != NULL) {
+        sdram->irq = irq;
+        sdram->nbanks = nbanks;
+        memset(sdram->ram_bases, 0, 4 * sizeof(target_phys_addr_t));
+        memcpy(sdram->ram_bases, ram_bases,
+               nbanks * sizeof(target_phys_addr_t));
+        memset(sdram->ram_sizes, 0, 4 * sizeof(target_phys_addr_t));
+        memcpy(sdram->ram_sizes, ram_sizes,
+               nbanks * sizeof(target_phys_addr_t));
+        sdram_reset(sdram);
+        qemu_register_reset(&sdram_reset, sdram);
+        ppc_dcr_register(env, SDRAM0_CFGADDR,
+                         sdram, &dcr_read_sdram, &dcr_write_sdram);
+        ppc_dcr_register(env, SDRAM0_CFGDATA,
+                         sdram, &dcr_read_sdram, &dcr_write_sdram);
+        if (do_init)
+            sdram_map_bcr(sdram);
+    }
+}
+
+/*****************************************************************************/
+/* Peripheral controller */
+typedef struct ppc4xx_ebc_t ppc4xx_ebc_t;
+struct ppc4xx_ebc_t {
+    uint32_t addr;
+    uint32_t bcr[8];
+    uint32_t bap[8];
+    uint32_t bear;
+    uint32_t besr0;
+    uint32_t besr1;
+    uint32_t cfg;
+};
+
+enum {
+    EBC0_CFGADDR = 0x012,
+    EBC0_CFGDATA = 0x013,
+};
+
+static target_ulong dcr_read_ebc (void *opaque, int dcrn)
+{
+    ppc4xx_ebc_t *ebc;
+    target_ulong ret;
+
+    ebc = opaque;
+    switch (dcrn) {
+    case EBC0_CFGADDR:
+        ret = ebc->addr;
+        break;
+    case EBC0_CFGDATA:
+        switch (ebc->addr) {
+        case 0x00: /* B0CR */
+            ret = ebc->bcr[0];
+            break;
+        case 0x01: /* B1CR */
+            ret = ebc->bcr[1];
+            break;
+        case 0x02: /* B2CR */
+            ret = ebc->bcr[2];
+            break;
+        case 0x03: /* B3CR */
+            ret = ebc->bcr[3];
+            break;
+        case 0x04: /* B4CR */
+            ret = ebc->bcr[4];
+            break;
+        case 0x05: /* B5CR */
+            ret = ebc->bcr[5];
+            break;
+        case 0x06: /* B6CR */
+            ret = ebc->bcr[6];
+            break;
+        case 0x07: /* B7CR */
+            ret = ebc->bcr[7];
+            break;
+        case 0x10: /* B0AP */
+            ret = ebc->bap[0];
+            break;
+        case 0x11: /* B1AP */
+            ret = ebc->bap[1];
+            break;
+        case 0x12: /* B2AP */
+            ret = ebc->bap[2];
+            break;
+        case 0x13: /* B3AP */
+            ret = ebc->bap[3];
+            break;
+        case 0x14: /* B4AP */
+            ret = ebc->bap[4];
+            break;
+        case 0x15: /* B5AP */
+            ret = ebc->bap[5];
+            break;
+        case 0x16: /* B6AP */
+            ret = ebc->bap[6];
+            break;
+        case 0x17: /* B7AP */
+            ret = ebc->bap[7];
+            break;
+        case 0x20: /* BEAR */
+            ret = ebc->bear;
+            break;
+        case 0x21: /* BESR0 */
+            ret = ebc->besr0;
+            break;
+        case 0x22: /* BESR1 */
+            ret = ebc->besr1;
+            break;
+        case 0x23: /* CFG */
+            ret = ebc->cfg;
+            break;
+        default:
+            ret = 0x00000000;
+            break;
+        }
+    default:
+        ret = 0x00000000;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_ebc (void *opaque, int dcrn, target_ulong val)
+{
+    ppc4xx_ebc_t *ebc;
+
+    ebc = opaque;
+    switch (dcrn) {
+    case EBC0_CFGADDR:
+        ebc->addr = val;
+        break;
+    case EBC0_CFGDATA:
+        switch (ebc->addr) {
+        case 0x00: /* B0CR */
+            break;
+        case 0x01: /* B1CR */
+            break;
+        case 0x02: /* B2CR */
+            break;
+        case 0x03: /* B3CR */
+            break;
+        case 0x04: /* B4CR */
+            break;
+        case 0x05: /* B5CR */
+            break;
+        case 0x06: /* B6CR */
+            break;
+        case 0x07: /* B7CR */
+            break;
+        case 0x10: /* B0AP */
+            break;
+        case 0x11: /* B1AP */
+            break;
+        case 0x12: /* B2AP */
+            break;
+        case 0x13: /* B3AP */
+            break;
+        case 0x14: /* B4AP */
+            break;
+        case 0x15: /* B5AP */
+            break;
+        case 0x16: /* B6AP */
+            break;
+        case 0x17: /* B7AP */
+            break;
+        case 0x20: /* BEAR */
+            break;
+        case 0x21: /* BESR0 */
+            break;
+        case 0x22: /* BESR1 */
+            break;
+        case 0x23: /* CFG */
+            break;
+        default:
+            break;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void ebc_reset (void *opaque)
+{
+    ppc4xx_ebc_t *ebc;
+    int i;
+
+    ebc = opaque;
+    ebc->addr = 0x00000000;
+    ebc->bap[0] = 0x7F8FFE80;
+    ebc->bcr[0] = 0xFFE28000;
+    for (i = 0; i < 8; i++) {
+        ebc->bap[i] = 0x00000000;
+        ebc->bcr[i] = 0x00000000;
+    }
+    ebc->besr0 = 0x00000000;
+    ebc->besr1 = 0x00000000;
+    ebc->cfg = 0x80400000;
+}
+
+void ppc405_ebc_init (CPUState *env)
+{
+    ppc4xx_ebc_t *ebc;
+
+    ebc = qemu_mallocz(sizeof(ppc4xx_ebc_t));
+    if (ebc != NULL) {
+        ebc_reset(ebc);
+        qemu_register_reset(&ebc_reset, ebc);
+        ppc_dcr_register(env, EBC0_CFGADDR,
+                         ebc, &dcr_read_ebc, &dcr_write_ebc);
+        ppc_dcr_register(env, EBC0_CFGDATA,
+                         ebc, &dcr_read_ebc, &dcr_write_ebc);
+    }
+}
+
+/*****************************************************************************/
+/* DMA controller */
+enum {
+    DMA0_CR0 = 0x100,
+    DMA0_CT0 = 0x101,
+    DMA0_DA0 = 0x102,
+    DMA0_SA0 = 0x103,
+    DMA0_SG0 = 0x104,
+    DMA0_CR1 = 0x108,
+    DMA0_CT1 = 0x109,
+    DMA0_DA1 = 0x10A,
+    DMA0_SA1 = 0x10B,
+    DMA0_SG1 = 0x10C,
+    DMA0_CR2 = 0x110,
+    DMA0_CT2 = 0x111,
+    DMA0_DA2 = 0x112,
+    DMA0_SA2 = 0x113,
+    DMA0_SG2 = 0x114,
+    DMA0_CR3 = 0x118,
+    DMA0_CT3 = 0x119,
+    DMA0_DA3 = 0x11A,
+    DMA0_SA3 = 0x11B,
+    DMA0_SG3 = 0x11C,
+    DMA0_SR  = 0x120,
+    DMA0_SGC = 0x123,
+    DMA0_SLP = 0x125,
+    DMA0_POL = 0x126,
+};
+
+typedef struct ppc405_dma_t ppc405_dma_t;
+struct ppc405_dma_t {
+    qemu_irq irqs[4];
+    uint32_t cr[4];
+    uint32_t ct[4];
+    uint32_t da[4];
+    uint32_t sa[4];
+    uint32_t sg[4];
+    uint32_t sr;
+    uint32_t sgc;
+    uint32_t slp;
+    uint32_t pol;
+};
+
+static target_ulong dcr_read_dma (void *opaque, int dcrn)
+{
+    ppc405_dma_t *dma;
+
+    dma = opaque;
+
+    return 0;
+}
+
+static void dcr_write_dma (void *opaque, int dcrn, target_ulong val)
+{
+    ppc405_dma_t *dma;
+
+    dma = opaque;
+}
+
+static void ppc405_dma_reset (void *opaque)
+{
+    ppc405_dma_t *dma;
+    int i;
+
+    dma = opaque;
+    for (i = 0; i < 4; i++) {
+        dma->cr[i] = 0x00000000;
+        dma->ct[i] = 0x00000000;
+        dma->da[i] = 0x00000000;
+        dma->sa[i] = 0x00000000;
+        dma->sg[i] = 0x00000000;
+    }
+    dma->sr = 0x00000000;
+    dma->sgc = 0x00000000;
+    dma->slp = 0x7C000000;
+    dma->pol = 0x00000000;
+}
+
+void ppc405_dma_init (CPUState *env, qemu_irq irqs[4])
+{
+    ppc405_dma_t *dma;
+
+    dma = qemu_mallocz(sizeof(ppc405_dma_t));
+    if (dma != NULL) {
+        memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq));
+        ppc405_dma_reset(dma);
+        qemu_register_reset(&ppc405_dma_reset, dma);
+        ppc_dcr_register(env, DMA0_CR0,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_CT0,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_DA0,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SA0,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SG0,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_CR1,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_CT1,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_DA1,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SA1,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SG1,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_CR2,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_CT2,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_DA2,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SA2,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SG2,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_CR3,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_CT3,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_DA3,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SA3,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SG3,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SR,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SGC,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_SLP,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+        ppc_dcr_register(env, DMA0_POL,
+                         dma, &dcr_read_dma, &dcr_write_dma);
+    }
+}
+
+/*****************************************************************************/
+/* GPIO */
+typedef struct ppc405_gpio_t ppc405_gpio_t;
+struct ppc405_gpio_t {
+    target_phys_addr_t base;
+    uint32_t or;
+    uint32_t tcr;
+    uint32_t osrh;
+    uint32_t osrl;
+    uint32_t tsrh;
+    uint32_t tsrl;
+    uint32_t odr;
+    uint32_t ir;
+    uint32_t rr1;
+    uint32_t isr1h;
+    uint32_t isr1l;
+};
+
+static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = opaque;
+#ifdef DEBUG_GPIO
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writeb (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = opaque;
+#ifdef DEBUG_GPIO
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+}
+
+static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = opaque;
+#ifdef DEBUG_GPIO
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writew (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = opaque;
+#ifdef DEBUG_GPIO
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+}
+
+static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = opaque;
+#ifdef DEBUG_GPIO
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+    return 0;
+}
+
+static void ppc405_gpio_writel (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = opaque;
+#ifdef DEBUG_GPIO
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+}
+
+static CPUReadMemoryFunc *ppc405_gpio_read[] = {
+    &ppc405_gpio_readb,
+    &ppc405_gpio_readw,
+    &ppc405_gpio_readl,
+};
+
+static CPUWriteMemoryFunc *ppc405_gpio_write[] = {
+    &ppc405_gpio_writeb,
+    &ppc405_gpio_writew,
+    &ppc405_gpio_writel,
+};
+
+static void ppc405_gpio_reset (void *opaque)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = opaque;
+}
+
+void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                       target_phys_addr_t offset)
+{
+    ppc405_gpio_t *gpio;
+
+    gpio = qemu_mallocz(sizeof(ppc405_gpio_t));
+    if (gpio != NULL) {
+        gpio->base = offset;
+        ppc405_gpio_reset(gpio);
+        qemu_register_reset(&ppc405_gpio_reset, gpio);
+#ifdef DEBUG_GPIO
+        printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+        ppc4xx_mmio_register(env, mmio, offset, 0x038,
+                             ppc405_gpio_read, ppc405_gpio_write, gpio);
+    }
+}
+
+/*****************************************************************************/
+/* Serial ports */
+static CPUReadMemoryFunc *serial_mm_read[] = {
+    &serial_mm_readb,
+    &serial_mm_readw,
+    &serial_mm_readl,
+};
+
+static CPUWriteMemoryFunc *serial_mm_write[] = {
+    &serial_mm_writeb,
+    &serial_mm_writew,
+    &serial_mm_writel,
+};
+
+void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                         target_phys_addr_t offset, qemu_irq irq,
+                         CharDriverState *chr)
+{
+    void *serial;
+
+#ifdef DEBUG_SERIAL
+    printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+    serial = serial_mm_init(offset, 0, irq, chr, 0);
+    ppc4xx_mmio_register(env, mmio, offset, 0x008,
+                         serial_mm_read, serial_mm_write, serial);
+}
+
+/*****************************************************************************/
+/* On Chip Memory */
+enum {
+    OCM0_ISARC   = 0x018,
+    OCM0_ISACNTL = 0x019,
+    OCM0_DSARC   = 0x01A,
+    OCM0_DSACNTL = 0x01B,
+};
+
+typedef struct ppc405_ocm_t ppc405_ocm_t;
+struct ppc405_ocm_t {
+    target_ulong offset;
+    uint32_t isarc;
+    uint32_t isacntl;
+    uint32_t dsarc;
+    uint32_t dsacntl;
+};
+
+static void ocm_update_mappings (ppc405_ocm_t *ocm,
+                                 uint32_t isarc, uint32_t isacntl,
+                                 uint32_t dsarc, uint32_t dsacntl)
+{
+#ifdef DEBUG_OCM
+    printf("OCM update ISA %08x %08x (%08x %08x) DSA %08x %08x (%08x %08x)\n",
+           isarc, isacntl, dsarc, dsacntl,
+           ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl);
+#endif
+    if (ocm->isarc != isarc ||
+        (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
+        if (ocm->isacntl & 0x80000000) {
+            /* Unmap previously assigned memory region */
+            printf("OCM unmap ISA %08x\n", ocm->isarc);
+            cpu_register_physical_memory(ocm->isarc, 0x04000000,
+                                         IO_MEM_UNASSIGNED);
+        }
+        if (isacntl & 0x80000000) {
+            /* Map new instruction memory region */
+#ifdef DEBUG_OCM
+            printf("OCM map ISA %08x\n", isarc);
+#endif
+            cpu_register_physical_memory(isarc, 0x04000000,
+                                         ocm->offset | IO_MEM_RAM);
+        }
+    }
+    if (ocm->dsarc != dsarc ||
+        (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
+        if (ocm->dsacntl & 0x80000000) {
+            /* Beware not to unmap the region we just mapped */
+            if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) {
+                /* Unmap previously assigned memory region */
+#ifdef DEBUG_OCM
+                printf("OCM unmap DSA %08x\n", ocm->dsarc);
+#endif
+                cpu_register_physical_memory(ocm->dsarc, 0x04000000,
+                                             IO_MEM_UNASSIGNED);
+            }
+        }
+        if (dsacntl & 0x80000000) {
+            /* Beware not to remap the region we just mapped */
+            if (!(isacntl & 0x80000000) || dsarc != isarc) {
+                /* Map new data memory region */
+#ifdef DEBUG_OCM
+                printf("OCM map DSA %08x\n", dsarc);
+#endif
+                cpu_register_physical_memory(dsarc, 0x04000000,
+                                             ocm->offset | IO_MEM_RAM);
+            }
+        }
+    }
+}
+
+static target_ulong dcr_read_ocm (void *opaque, int dcrn)
+{
+    ppc405_ocm_t *ocm;
+    target_ulong ret;
+
+    ocm = opaque;
+    switch (dcrn) {
+    case OCM0_ISARC:
+        ret = ocm->isarc;
+        break;
+    case OCM0_ISACNTL:
+        ret = ocm->isacntl;
+        break;
+    case OCM0_DSARC:
+        ret = ocm->dsarc;
+        break;
+    case OCM0_DSACNTL:
+        ret = ocm->dsacntl;
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_ocm (void *opaque, int dcrn, target_ulong val)
+{
+    ppc405_ocm_t *ocm;
+    uint32_t isarc, dsarc, isacntl, dsacntl;
+
+    ocm = opaque;
+    isarc = ocm->isarc;
+    dsarc = ocm->dsarc;
+    isacntl = ocm->isacntl;
+    dsacntl = ocm->dsacntl;
+    switch (dcrn) {
+    case OCM0_ISARC:
+        isarc = val & 0xFC000000;
+        break;
+    case OCM0_ISACNTL:
+        isacntl = val & 0xC0000000;
+        break;
+    case OCM0_DSARC:
+        isarc = val & 0xFC000000;
+        break;
+    case OCM0_DSACNTL:
+        isacntl = val & 0xC0000000;
+        break;
+    }
+    ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
+    ocm->isarc = isarc;
+    ocm->dsarc = dsarc;
+    ocm->isacntl = isacntl;
+    ocm->dsacntl = dsacntl;
+}
+
+static void ocm_reset (void *opaque)
+{
+    ppc405_ocm_t *ocm;
+    uint32_t isarc, dsarc, isacntl, dsacntl;
+
+    ocm = opaque;
+    isarc = 0x00000000;
+    isacntl = 0x00000000;
+    dsarc = 0x00000000;
+    dsacntl = 0x00000000;
+    ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
+    ocm->isarc = isarc;
+    ocm->dsarc = dsarc;
+    ocm->isacntl = isacntl;
+    ocm->dsacntl = dsacntl;
+}
+
+void ppc405_ocm_init (CPUState *env, unsigned long offset)
+{
+    ppc405_ocm_t *ocm;
+
+    ocm = qemu_mallocz(sizeof(ppc405_ocm_t));
+    if (ocm != NULL) {
+        ocm->offset = offset;
+        ocm_reset(ocm);
+        qemu_register_reset(&ocm_reset, ocm);
+        ppc_dcr_register(env, OCM0_ISARC,
+                         ocm, &dcr_read_ocm, &dcr_write_ocm);
+        ppc_dcr_register(env, OCM0_ISACNTL,
+                         ocm, &dcr_read_ocm, &dcr_write_ocm);
+        ppc_dcr_register(env, OCM0_DSARC,
+                         ocm, &dcr_read_ocm, &dcr_write_ocm);
+        ppc_dcr_register(env, OCM0_DSACNTL,
+                         ocm, &dcr_read_ocm, &dcr_write_ocm);
+    }
+}
+
+/*****************************************************************************/
+/* I2C controller */
+typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
+struct ppc4xx_i2c_t {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    uint8_t mdata;
+    uint8_t lmadr;
+    uint8_t hmadr;
+    uint8_t cntl;
+    uint8_t mdcntl;
+    uint8_t sts;
+    uint8_t extsts;
+    uint8_t sdata;
+    uint8_t lsadr;
+    uint8_t hsadr;
+    uint8_t clkdiv;
+    uint8_t intrmsk;
+    uint8_t xfrcnt;
+    uint8_t xtcntlss;
+    uint8_t directcntl;
+};
+
+static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr)
+{
+    ppc4xx_i2c_t *i2c;
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    i2c = opaque;
+    switch (addr - i2c->base) {
+    case 0x00:
+        //        i2c_readbyte(&i2c->mdata);
+        ret = i2c->mdata;
+        break;
+    case 0x02:
+        ret = i2c->sdata;
+        break;
+    case 0x04:
+        ret = i2c->lmadr;
+        break;
+    case 0x05:
+        ret = i2c->hmadr;
+        break;
+    case 0x06:
+        ret = i2c->cntl;
+        break;
+    case 0x07:
+        ret = i2c->mdcntl;
+        break;
+    case 0x08:
+        ret = i2c->sts;
+        break;
+    case 0x09:
+        ret = i2c->extsts;
+        break;
+    case 0x0A:
+        ret = i2c->lsadr;
+        break;
+    case 0x0B:
+        ret = i2c->hsadr;
+        break;
+    case 0x0C:
+        ret = i2c->clkdiv;
+        break;
+    case 0x0D:
+        ret = i2c->intrmsk;
+        break;
+    case 0x0E:
+        ret = i2c->xfrcnt;
+        break;
+    case 0x0F:
+        ret = i2c->xtcntlss;
+        break;
+    case 0x10:
+        ret = i2c->directcntl;
+        break;
+    default:
+        ret = 0x00;
+        break;
+    }
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " %02x\n", __func__, addr, ret);
+#endif
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writeb (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    ppc4xx_i2c_t *i2c;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    i2c = opaque;
+    switch (addr - i2c->base) {
+    case 0x00:
+        i2c->mdata = value;
+        //        i2c_sendbyte(&i2c->mdata);
+        break;
+    case 0x02:
+        i2c->sdata = value;
+        break;
+    case 0x04:
+        i2c->lmadr = value;
+        break;
+    case 0x05:
+        i2c->hmadr = value;
+        break;
+    case 0x06:
+        i2c->cntl = value;
+        break;
+    case 0x07:
+        i2c->mdcntl = value & 0xDF;
+        break;
+    case 0x08:
+        i2c->sts &= ~(value & 0x0A);
+        break;
+    case 0x09:
+        i2c->extsts &= ~(value & 0x8F);
+        break;
+    case 0x0A:
+        i2c->lsadr = value;
+        break;
+    case 0x0B:
+        i2c->hsadr = value;
+        break;
+    case 0x0C:
+        i2c->clkdiv = value;
+        break;
+    case 0x0D:
+        i2c->intrmsk = value;
+        break;
+    case 0x0E:
+        i2c->xfrcnt = value & 0x77;
+        break;
+    case 0x0F:
+        i2c->xtcntlss = value;
+        break;
+    case 0x10:
+        i2c->directcntl = value & 0x7;
+        break;
+    }
+}
+
+static uint32_t ppc4xx_i2c_readw (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    ret = ppc4xx_i2c_readb(opaque, addr) << 8;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 1);
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writew (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    ppc4xx_i2c_writeb(opaque, addr, value >> 8);
+    ppc4xx_i2c_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t ppc4xx_i2c_readl (void *opaque, target_phys_addr_t addr)
+{
+    uint32_t ret;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    ret = ppc4xx_i2c_readb(opaque, addr) << 24;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
+    ret |= ppc4xx_i2c_readb(opaque, addr + 3);
+
+    return ret;
+}
+
+static void ppc4xx_i2c_writel (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    ppc4xx_i2c_writeb(opaque, addr, value >> 24);
+    ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
+    ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
+    ppc4xx_i2c_writeb(opaque, addr + 3, value);
+}
+
+static CPUReadMemoryFunc *i2c_read[] = {
+    &ppc4xx_i2c_readb,
+    &ppc4xx_i2c_readw,
+    &ppc4xx_i2c_readl,
+};
+
+static CPUWriteMemoryFunc *i2c_write[] = {
+    &ppc4xx_i2c_writeb,
+    &ppc4xx_i2c_writew,
+    &ppc4xx_i2c_writel,
+};
+
+static void ppc4xx_i2c_reset (void *opaque)
+{
+    ppc4xx_i2c_t *i2c;
+
+    i2c = opaque;
+    i2c->mdata = 0x00;
+    i2c->sdata = 0x00;
+    i2c->cntl = 0x00;
+    i2c->mdcntl = 0x00;
+    i2c->sts = 0x00;
+    i2c->extsts = 0x00;
+    i2c->clkdiv = 0x00;
+    i2c->xfrcnt = 0x00;
+    i2c->directcntl = 0x0F;
+}
+
+void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                      target_phys_addr_t offset, qemu_irq irq)
+{
+    ppc4xx_i2c_t *i2c;
+
+    i2c = qemu_mallocz(sizeof(ppc4xx_i2c_t));
+    if (i2c != NULL) {
+        i2c->base = offset;
+        i2c->irq = irq;
+        ppc4xx_i2c_reset(i2c);
+#ifdef DEBUG_I2C
+        printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+        ppc4xx_mmio_register(env, mmio, offset, 0x011,
+                             i2c_read, i2c_write, i2c);
+        qemu_register_reset(ppc4xx_i2c_reset, i2c);
+    }
+}
+
+/*****************************************************************************/
+/* General purpose timers */
+typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
+struct ppc4xx_gpt_t {
+    target_phys_addr_t base;
+    int64_t tb_offset;
+    uint32_t tb_freq;
+    struct QEMUTimer *timer;
+    qemu_irq irqs[5];
+    uint32_t oe;
+    uint32_t ol;
+    uint32_t im;
+    uint32_t is;
+    uint32_t ie;
+    uint32_t comp[5];
+    uint32_t mask[5];
+};
+
+static uint32_t ppc4xx_gpt_readb (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPT
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    /* XXX: generate a bus fault */
+    return -1;
+}
+
+static void ppc4xx_gpt_writeb (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    /* XXX: generate a bus fault */
+}
+
+static uint32_t ppc4xx_gpt_readw (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPT
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    /* XXX: generate a bus fault */
+    return -1;
+}
+
+static void ppc4xx_gpt_writew (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    /* XXX: generate a bus fault */
+}
+
+static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
+{
+    /* XXX: TODO */
+    return 0;
+}
+
+static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level)
+{
+    /* XXX: TODO */
+}
+
+static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt)
+{
+    uint32_t mask;
+    int i;
+
+    mask = 0x80000000;
+    for (i = 0; i < 5; i++) {
+        if (gpt->oe & mask) {
+            /* Output is enabled */
+            if (ppc4xx_gpt_compare(gpt, i)) {
+                /* Comparison is OK */
+                ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask);
+            } else {
+                /* Comparison is KO */
+                ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1);
+            }
+        }
+        mask = mask >> 1;
+    }
+}
+
+static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt)
+{
+    uint32_t mask;
+    int i;
+
+    mask = 0x00008000;
+    for (i = 0; i < 5; i++) {
+        if (gpt->is & gpt->im & mask)
+            qemu_irq_raise(gpt->irqs[i]);
+        else
+            qemu_irq_lower(gpt->irqs[i]);
+        mask = mask >> 1;
+    }
+}
+
+static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
+{
+    /* XXX: TODO */
+}
+
+static uint32_t ppc4xx_gpt_readl (void *opaque, target_phys_addr_t addr)
+{
+    ppc4xx_gpt_t *gpt;
+    uint32_t ret;
+    int idx;
+
+#ifdef DEBUG_GPT
+    printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+    gpt = opaque;
+    switch (addr - gpt->base) {
+    case 0x00:
+        /* Time base counter */
+        ret = muldiv64(qemu_get_clock(vm_clock) + gpt->tb_offset,
+                       gpt->tb_freq, ticks_per_sec);
+        break;
+    case 0x10:
+        /* Output enable */
+        ret = gpt->oe;
+        break;
+    case 0x14:
+        /* Output level */
+        ret = gpt->ol;
+        break;
+    case 0x18:
+        /* Interrupt mask */
+        ret = gpt->im;
+        break;
+    case 0x1C:
+    case 0x20:
+        /* Interrupt status */
+        ret = gpt->is;
+        break;
+    case 0x24:
+        /* Interrupt enable */
+        ret = gpt->ie;
+        break;
+    case 0x80 ... 0x90:
+        /* Compare timer */
+        idx = ((addr - gpt->base) - 0x80) >> 2;
+        ret = gpt->comp[idx];
+        break;
+    case 0xC0 ... 0xD0:
+        /* Compare mask */
+        idx = ((addr - gpt->base) - 0xC0) >> 2;
+        ret = gpt->mask[idx];
+        break;
+    default:
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
+static void ppc4xx_gpt_writel (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
+{
+    ppc4xx_gpt_t *gpt;
+    int idx;
+
+#ifdef DEBUG_I2C
+    printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+    gpt = opaque;
+    switch (addr - gpt->base) {
+    case 0x00:
+        /* Time base counter */
+        gpt->tb_offset = muldiv64(value, ticks_per_sec, gpt->tb_freq)
+            - qemu_get_clock(vm_clock);
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    case 0x10:
+        /* Output enable */
+        gpt->oe = value & 0xF8000000;
+        ppc4xx_gpt_set_outputs(gpt);
+        break;
+    case 0x14:
+        /* Output level */
+        gpt->ol = value & 0xF8000000;
+        ppc4xx_gpt_set_outputs(gpt);
+        break;
+    case 0x18:
+        /* Interrupt mask */
+        gpt->im = value & 0x0000F800;
+        break;
+    case 0x1C:
+        /* Interrupt status set */
+        gpt->is |= value & 0x0000F800;
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x20:
+        /* Interrupt status clear */
+        gpt->is &= ~(value & 0x0000F800);
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x24:
+        /* Interrupt enable */
+        gpt->ie = value & 0x0000F800;
+        ppc4xx_gpt_set_irqs(gpt);
+        break;
+    case 0x80 ... 0x90:
+        /* Compare timer */
+        idx = ((addr - gpt->base) - 0x80) >> 2;
+        gpt->comp[idx] = value & 0xF8000000;
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    case 0xC0 ... 0xD0:
+        /* Compare mask */
+        idx = ((addr - gpt->base) - 0xC0) >> 2;
+        gpt->mask[idx] = value & 0xF8000000;
+        ppc4xx_gpt_compute_timer(gpt);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *gpt_read[] = {
+    &ppc4xx_gpt_readb,
+    &ppc4xx_gpt_readw,
+    &ppc4xx_gpt_readl,
+};
+
+static CPUWriteMemoryFunc *gpt_write[] = {
+    &ppc4xx_gpt_writeb,
+    &ppc4xx_gpt_writew,
+    &ppc4xx_gpt_writel,
+};
+
+static void ppc4xx_gpt_cb (void *opaque)
+{
+    ppc4xx_gpt_t *gpt;
+
+    gpt = opaque;
+    ppc4xx_gpt_set_irqs(gpt);
+    ppc4xx_gpt_set_outputs(gpt);
+    ppc4xx_gpt_compute_timer(gpt);
+}
+
+static void ppc4xx_gpt_reset (void *opaque)
+{
+    ppc4xx_gpt_t *gpt;
+    int i;
+
+    gpt = opaque;
+    qemu_del_timer(gpt->timer);
+    gpt->oe = 0x00000000;
+    gpt->ol = 0x00000000;
+    gpt->im = 0x00000000;
+    gpt->is = 0x00000000;
+    gpt->ie = 0x00000000;
+    for (i = 0; i < 5; i++) {
+        gpt->comp[i] = 0x00000000;
+        gpt->mask[i] = 0x00000000;
+    }
+}
+
+void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio,
+                      target_phys_addr_t offset, qemu_irq irqs[5])
+{
+    ppc4xx_gpt_t *gpt;
+    int i;
+
+    gpt = qemu_mallocz(sizeof(ppc4xx_gpt_t));
+    if (gpt != NULL) {
+        gpt->base = offset;
+        for (i = 0; i < 5; i++)
+            gpt->irqs[i] = irqs[i];
+        gpt->timer = qemu_new_timer(vm_clock, &ppc4xx_gpt_cb, gpt);
+        ppc4xx_gpt_reset(gpt);
+#ifdef DEBUG_GPT
+        printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+        ppc4xx_mmio_register(env, mmio, offset, 0x0D4,
+                             gpt_read, gpt_write, gpt);
+        qemu_register_reset(ppc4xx_gpt_reset, gpt);
+    }
+}
+
+/*****************************************************************************/
+/* MAL */
+enum {
+    MAL0_CFG      = 0x180,
+    MAL0_ESR      = 0x181,
+    MAL0_IER      = 0x182,
+    MAL0_TXCASR   = 0x184,
+    MAL0_TXCARR   = 0x185,
+    MAL0_TXEOBISR = 0x186,
+    MAL0_TXDEIR   = 0x187,
+    MAL0_RXCASR   = 0x190,
+    MAL0_RXCARR   = 0x191,
+    MAL0_RXEOBISR = 0x192,
+    MAL0_RXDEIR   = 0x193,
+    MAL0_TXCTP0R  = 0x1A0,
+    MAL0_TXCTP1R  = 0x1A1,
+    MAL0_TXCTP2R  = 0x1A2,
+    MAL0_TXCTP3R  = 0x1A3,
+    MAL0_RXCTP0R  = 0x1C0,
+    MAL0_RXCTP1R  = 0x1C1,
+    MAL0_RCBS0    = 0x1E0,
+    MAL0_RCBS1    = 0x1E1,
+};
+
+typedef struct ppc40x_mal_t ppc40x_mal_t;
+struct ppc40x_mal_t {
+    qemu_irq irqs[4];
+    uint32_t cfg;
+    uint32_t esr;
+    uint32_t ier;
+    uint32_t txcasr;
+    uint32_t txcarr;
+    uint32_t txeobisr;
+    uint32_t txdeir;
+    uint32_t rxcasr;
+    uint32_t rxcarr;
+    uint32_t rxeobisr;
+    uint32_t rxdeir;
+    uint32_t txctpr[4];
+    uint32_t rxctpr[2];
+    uint32_t rcbs[2];
+};
+
+static void ppc40x_mal_reset (void *opaque);
+
+static target_ulong dcr_read_mal (void *opaque, int dcrn)
+{
+    ppc40x_mal_t *mal;
+    target_ulong ret;
+
+    mal = opaque;
+    switch (dcrn) {
+    case MAL0_CFG:
+        ret = mal->cfg;
+        break;
+    case MAL0_ESR:
+        ret = mal->esr;
+        break;
+    case MAL0_IER:
+        ret = mal->ier;
+        break;
+    case MAL0_TXCASR:
+        ret = mal->txcasr;
+        break;
+    case MAL0_TXCARR:
+        ret = mal->txcarr;
+        break;
+    case MAL0_TXEOBISR:
+        ret = mal->txeobisr;
+        break;
+    case MAL0_TXDEIR:
+        ret = mal->txdeir;
+        break;
+    case MAL0_RXCASR:
+        ret = mal->rxcasr;
+        break;
+    case MAL0_RXCARR:
+        ret = mal->rxcarr;
+        break;
+    case MAL0_RXEOBISR:
+        ret = mal->rxeobisr;
+        break;
+    case MAL0_RXDEIR:
+        ret = mal->rxdeir;
+        break;
+    case MAL0_TXCTP0R:
+        ret = mal->txctpr[0];
+        break;
+    case MAL0_TXCTP1R:
+        ret = mal->txctpr[1];
+        break;
+    case MAL0_TXCTP2R:
+        ret = mal->txctpr[2];
+        break;
+    case MAL0_TXCTP3R:
+        ret = mal->txctpr[3];
+        break;
+    case MAL0_RXCTP0R:
+        ret = mal->rxctpr[0];
+        break;
+    case MAL0_RXCTP1R:
+        ret = mal->rxctpr[1];
+        break;
+    case MAL0_RCBS0:
+        ret = mal->rcbs[0];
+        break;
+    case MAL0_RCBS1:
+        ret = mal->rcbs[1];
+        break;
+    default:
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_mal (void *opaque, int dcrn, target_ulong val)
+{
+    ppc40x_mal_t *mal;
+    int idx;
+
+    mal = opaque;
+    switch (dcrn) {
+    case MAL0_CFG:
+        if (val & 0x80000000)
+            ppc40x_mal_reset(mal);
+        mal->cfg = val & 0x00FFC087;
+        break;
+    case MAL0_ESR:
+        /* Read/clear */
+        mal->esr &= ~val;
+        break;
+    case MAL0_IER:
+        mal->ier = val & 0x0000001F;
+        break;
+    case MAL0_TXCASR:
+        mal->txcasr = val & 0xF0000000;
+        break;
+    case MAL0_TXCARR:
+        mal->txcarr = val & 0xF0000000;
+        break;
+    case MAL0_TXEOBISR:
+        /* Read/clear */
+        mal->txeobisr &= ~val;
+        break;
+    case MAL0_TXDEIR:
+        /* Read/clear */
+        mal->txdeir &= ~val;
+        break;
+    case MAL0_RXCASR:
+        mal->rxcasr = val & 0xC0000000;
+        break;
+    case MAL0_RXCARR:
+        mal->rxcarr = val & 0xC0000000;
+        break;
+    case MAL0_RXEOBISR:
+        /* Read/clear */
+        mal->rxeobisr &= ~val;
+        break;
+    case MAL0_RXDEIR:
+        /* Read/clear */
+        mal->rxdeir &= ~val;
+        break;
+    case MAL0_TXCTP0R:
+        idx = 0;
+        goto update_tx_ptr;
+    case MAL0_TXCTP1R:
+        idx = 1;
+        goto update_tx_ptr;
+    case MAL0_TXCTP2R:
+        idx = 2;
+        goto update_tx_ptr;
+    case MAL0_TXCTP3R:
+        idx = 3;
+    update_tx_ptr:
+        mal->txctpr[idx] = val;
+        break;
+    case MAL0_RXCTP0R:
+        idx = 0;
+        goto update_rx_ptr;
+    case MAL0_RXCTP1R:
+        idx = 1;
+    update_rx_ptr:
+        mal->rxctpr[idx] = val;
+        break;
+    case MAL0_RCBS0:
+        idx = 0;
+        goto update_rx_size;
+    case MAL0_RCBS1:
+        idx = 1;
+    update_rx_size:
+        mal->rcbs[idx] = val & 0x000000FF;
+        break;
+    }
+}
+
+static void ppc40x_mal_reset (void *opaque)
+{
+    ppc40x_mal_t *mal;
+
+    mal = opaque;
+    mal->cfg = 0x0007C000;
+    mal->esr = 0x00000000;
+    mal->ier = 0x00000000;
+    mal->rxcasr = 0x00000000;
+    mal->rxdeir = 0x00000000;
+    mal->rxeobisr = 0x00000000;
+    mal->txcasr = 0x00000000;
+    mal->txdeir = 0x00000000;
+    mal->txeobisr = 0x00000000;
+}
+
+void ppc405_mal_init (CPUState *env, qemu_irq irqs[4])
+{
+    ppc40x_mal_t *mal;
+    int i;
+
+    mal = qemu_mallocz(sizeof(ppc40x_mal_t));
+    if (mal != NULL) {
+        for (i = 0; i < 4; i++)
+            mal->irqs[i] = irqs[i];
+        ppc40x_mal_reset(mal);
+        qemu_register_reset(&ppc40x_mal_reset, mal);
+        ppc_dcr_register(env, MAL0_CFG,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_ESR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_IER,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCASR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCARR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXEOBISR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXDEIR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXCASR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXCARR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXEOBISR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXDEIR,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCTP0R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCTP1R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCTP2R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_TXCTP3R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXCTP0R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RXCTP1R,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RCBS0,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+        ppc_dcr_register(env, MAL0_RCBS1,
+                         mal, &dcr_read_mal, &dcr_write_mal);
+    }
+}
+
+/*****************************************************************************/
+/* SPR */
+void ppc40x_core_reset (CPUState *env)
+{
+    target_ulong dbsr;
+
+    printf("Reset PowerPC core\n");
+    cpu_ppc_reset(env);
+    dbsr = env->spr[SPR_40x_DBSR];
+    dbsr &= ~0x00000300;
+    dbsr |= 0x00000100;
+    env->spr[SPR_40x_DBSR] = dbsr;
+    cpu_loop_exit();
+}
+
+void ppc40x_chip_reset (CPUState *env)
+{
+    target_ulong dbsr;
+
+    printf("Reset PowerPC chip\n");
+    cpu_ppc_reset(env);
+    /* XXX: TODO reset all internal peripherals */
+    dbsr = env->spr[SPR_40x_DBSR];
+    dbsr &= ~0x00000300;
+    dbsr |= 0x00000200;
+    env->spr[SPR_40x_DBSR] = dbsr;
+    cpu_loop_exit();
+}
+
+void ppc40x_system_reset (CPUState *env)
+{
+    printf("Reset PowerPC system\n");
+    qemu_system_reset_request();
+}
+
+void store_40x_dbcr0 (CPUState *env, uint32_t val)
+{
+    switch ((val >> 28) & 0x3) {
+    case 0x0:
+        /* No action */
+        break;
+    case 0x1:
+        /* Core reset */
+        ppc40x_core_reset(env);
+        break;
+    case 0x2:
+        /* Chip reset */
+        ppc40x_chip_reset(env);
+        break;
+    case 0x3:
+        /* System reset */
+        ppc40x_system_reset(env);
+        break;
+    }
+}
+
+/*****************************************************************************/
+/* PowerPC 405CR */
+enum {
+    PPC405CR_CPC0_PLLMR  = 0x0B0,
+    PPC405CR_CPC0_CR0    = 0x0B1,
+    PPC405CR_CPC0_CR1    = 0x0B2,
+    PPC405CR_CPC0_PSR    = 0x0B4,
+    PPC405CR_CPC0_JTAGID = 0x0B5,
+    PPC405CR_CPC0_ER     = 0x0B9,
+    PPC405CR_CPC0_FR     = 0x0BA,
+    PPC405CR_CPC0_SR     = 0x0BB,
+};
+
+enum {
+    PPC405CR_CPU_CLK   = 0,
+    PPC405CR_TMR_CLK   = 1,
+    PPC405CR_PLB_CLK   = 2,
+    PPC405CR_SDRAM_CLK = 3,
+    PPC405CR_OPB_CLK   = 4,
+    PPC405CR_EXT_CLK   = 5,
+    PPC405CR_UART_CLK  = 6,
+    PPC405CR_CLK_NB    = 7,
+};
+
+typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
+struct ppc405cr_cpc_t {
+    clk_setup_t clk_setup[PPC405CR_CLK_NB];
+    uint32_t sysclk;
+    uint32_t psr;
+    uint32_t cr0;
+    uint32_t cr1;
+    uint32_t jtagid;
+    uint32_t pllmr;
+    uint32_t er;
+    uint32_t fr;
+};
+
+static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
+{
+    uint64_t VCO_out, PLL_out;
+    uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk;
+    int M, D0, D1, D2;
+
+    D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */
+    if (cpc->pllmr & 0x80000000) {
+        D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */
+        D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */
+        M = D0 * D1 * D2;
+        VCO_out = cpc->sysclk * M;
+        if (VCO_out < 400000000 || VCO_out > 800000000) {
+            /* PLL cannot lock */
+            cpc->pllmr &= ~0x80000000;
+            goto bypass_pll;
+        }
+        PLL_out = VCO_out / D2;
+    } else {
+        /* Bypass PLL */
+    bypass_pll:
+        M = D0;
+        PLL_out = cpc->sysclk * M;
+    }
+    CPU_clk = PLL_out;
+    if (cpc->cr1 & 0x00800000)
+        TMR_clk = cpc->sysclk; /* Should have a separate clock */
+    else
+        TMR_clk = CPU_clk;
+    PLB_clk = CPU_clk / D0;
+    SDRAM_clk = PLB_clk;
+    D0 = ((cpc->pllmr >> 10) & 0x3) + 1;
+    OPB_clk = PLB_clk / D0;
+    D0 = ((cpc->pllmr >> 24) & 0x3) + 2;
+    EXT_clk = PLB_clk / D0;
+    D0 = ((cpc->cr0 >> 1) & 0x1F) + 1;
+    UART_clk = CPU_clk / D0;
+    /* Setup CPU clocks */
+    clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk);
+    /* Setup time-base clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk);
+    /* Setup PLB clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk);
+    /* Setup SDRAM clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk);
+    /* Setup OPB clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk);
+    /* Setup external clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk);
+    /* Setup UART clock */
+    clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk);
+}
+
+static target_ulong dcr_read_crcpc (void *opaque, int dcrn)
+{
+    ppc405cr_cpc_t *cpc;
+    target_ulong ret;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405CR_CPC0_PLLMR:
+        ret = cpc->pllmr;
+        break;
+    case PPC405CR_CPC0_CR0:
+        ret = cpc->cr0;
+        break;
+    case PPC405CR_CPC0_CR1:
+        ret = cpc->cr1;
+        break;
+    case PPC405CR_CPC0_PSR:
+        ret = cpc->psr;
+        break;
+    case PPC405CR_CPC0_JTAGID:
+        ret = cpc->jtagid;
+        break;
+    case PPC405CR_CPC0_ER:
+        ret = cpc->er;
+        break;
+    case PPC405CR_CPC0_FR:
+        ret = cpc->fr;
+        break;
+    case PPC405CR_CPC0_SR:
+        ret = ~(cpc->er | cpc->fr) & 0xFFFF0000;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_crcpc (void *opaque, int dcrn, target_ulong val)
+{
+    ppc405cr_cpc_t *cpc;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405CR_CPC0_PLLMR:
+        cpc->pllmr = val & 0xFFF77C3F;
+        break;
+    case PPC405CR_CPC0_CR0:
+        cpc->cr0 = val & 0x0FFFFFFE;
+        break;
+    case PPC405CR_CPC0_CR1:
+        cpc->cr1 = val & 0x00800000;
+        break;
+    case PPC405CR_CPC0_PSR:
+        /* Read-only */
+        break;
+    case PPC405CR_CPC0_JTAGID:
+        /* Read-only */
+        break;
+    case PPC405CR_CPC0_ER:
+        cpc->er = val & 0xBFFC0000;
+        break;
+    case PPC405CR_CPC0_FR:
+        cpc->fr = val & 0xBFFC0000;
+        break;
+    case PPC405CR_CPC0_SR:
+        /* Read-only */
+        break;
+    }
+}
+
+static void ppc405cr_cpc_reset (void *opaque)
+{
+    ppc405cr_cpc_t *cpc;
+    int D;
+
+    cpc = opaque;
+    /* Compute PLLMR value from PSR settings */
+    cpc->pllmr = 0x80000000;
+    /* PFWD */
+    switch ((cpc->psr >> 30) & 3) {
+    case 0:
+        /* Bypass */
+        cpc->pllmr &= ~0x80000000;
+        break;
+    case 1:
+        /* Divide by 3 */
+        cpc->pllmr |= 5 << 16;
+        break;
+    case 2:
+        /* Divide by 4 */
+        cpc->pllmr |= 4 << 16;
+        break;
+    case 3:
+        /* Divide by 6 */
+        cpc->pllmr |= 2 << 16;
+        break;
+    }
+    /* PFBD */
+    D = (cpc->psr >> 28) & 3;
+    cpc->pllmr |= (D + 1) << 20;
+    /* PT   */
+    D = (cpc->psr >> 25) & 7;
+    switch (D) {
+    case 0x2:
+        cpc->pllmr |= 0x13;
+        break;
+    case 0x4:
+        cpc->pllmr |= 0x15;
+        break;
+    case 0x5:
+        cpc->pllmr |= 0x16;
+        break;
+    default:
+        break;
+    }
+    /* PDC  */
+    D = (cpc->psr >> 23) & 3;
+    cpc->pllmr |= D << 26;
+    /* ODP  */
+    D = (cpc->psr >> 21) & 3;
+    cpc->pllmr |= D << 10;
+    /* EBPD */
+    D = (cpc->psr >> 17) & 3;
+    cpc->pllmr |= D << 24;
+    cpc->cr0 = 0x0000003C;
+    cpc->cr1 = 0x2B0D8800;
+    cpc->er = 0x00000000;
+    cpc->fr = 0x00000000;
+    ppc405cr_clk_setup(cpc);
+}
+
+static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc)
+{
+    int D;
+
+    /* XXX: this should be read from IO pins */
+    cpc->psr = 0x00000000; /* 8 bits ROM */
+    /* PFWD */
+    D = 0x2; /* Divide by 4 */
+    cpc->psr |= D << 30;
+    /* PFBD */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 28;
+    /* PDC */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 23;
+    /* PT */
+    D = 0x5; /* M = 16 */
+    cpc->psr |= D << 25;
+    /* ODP */
+    D = 0x1; /* Divide by 2 */
+    cpc->psr |= D << 21;
+    /* EBDP */
+    D = 0x2; /* Divide by 4 */
+    cpc->psr |= D << 17;
+}
+
+static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7],
+                               uint32_t sysclk)
+{
+    ppc405cr_cpc_t *cpc;
+
+    cpc = qemu_mallocz(sizeof(ppc405cr_cpc_t));
+    if (cpc != NULL) {
+        memcpy(cpc->clk_setup, clk_setup,
+               PPC405CR_CLK_NB * sizeof(clk_setup_t));
+        cpc->sysclk = sysclk;
+        cpc->jtagid = 0x42051049;
+        ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc,
+                         &dcr_read_crcpc, &dcr_write_crcpc);
+        ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc,
+                         &dcr_read_crcpc, &dcr_write_crcpc);
+        ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc,
+                         &dcr_read_crcpc, &dcr_write_crcpc);
+        ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc,
+                         &dcr_read_crcpc, &dcr_write_crcpc);
+        ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc,
+                         &dcr_read_crcpc, &dcr_write_crcpc);
+        ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc,
+                         &dcr_read_crcpc, &dcr_write_crcpc);
+        ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc,
+                         &dcr_read_crcpc, &dcr_write_crcpc);
+        ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc,
+                         &dcr_read_crcpc, &dcr_write_crcpc);
+        ppc405cr_clk_init(cpc);
+        qemu_register_reset(ppc405cr_cpc_reset, cpc);
+        ppc405cr_cpc_reset(cpc);
+    }
+}
+
+CPUState *ppc405cr_init (target_phys_addr_t ram_bases[4],
+                         target_phys_addr_t ram_sizes[4],
+                         uint32_t sysclk, qemu_irq **picp,
+                         ram_addr_t *offsetp, int do_init)
+{
+    clk_setup_t clk_setup[PPC405CR_CLK_NB];
+    qemu_irq dma_irqs[4];
+    CPUState *env;
+    ppc4xx_mmio_t *mmio;
+    qemu_irq *pic, *irqs;
+    ram_addr_t offset;
+    int i;
+
+    memset(clk_setup, 0, sizeof(clk_setup));
+    env = ppc405_init("405cr", &clk_setup[PPC405CR_CPU_CLK],
+                      &clk_setup[PPC405CR_TMR_CLK], sysclk);
+    /* Memory mapped devices registers */
+    mmio = ppc4xx_mmio_init(env, 0xEF600000);
+    /* PLB arbitrer */
+    ppc4xx_plb_init(env);
+    /* PLB to OPB bridge */
+    ppc4xx_pob_init(env);
+    /* OBP arbitrer */
+    ppc4xx_opba_init(env, mmio, 0x600);
+    /* Universal interrupt controller */
+    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    *picp = pic;
+    /* SDRAM controller */
+    ppc405_sdram_init(env, pic[14], 1, ram_bases, ram_sizes, do_init);
+    offset = 0;
+    for (i = 0; i < 4; i++)
+        offset += ram_sizes[i];
+    /* External bus controller */
+    ppc405_ebc_init(env);
+    /* DMA controller */
+    dma_irqs[0] = pic[26];
+    dma_irqs[1] = pic[25];
+    dma_irqs[2] = pic[24];
+    dma_irqs[3] = pic[23];
+    ppc405_dma_init(env, dma_irqs);
+    /* Serial ports */
+    if (serial_hds[0] != NULL) {
+        ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]);
+    }
+    if (serial_hds[1] != NULL) {
+        ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]);
+    }
+    /* IIC controller */
+    ppc405_i2c_init(env, mmio, 0x500, pic[29]);
+    /* GPIO */
+    ppc405_gpio_init(env, mmio, 0x700);
+    /* CPU control */
+    ppc405cr_cpc_init(env, clk_setup, sysclk);
+    *offsetp = offset;
+
+    return env;
+}
+
+/*****************************************************************************/
+/* PowerPC 405EP */
+/* CPU control */
+enum {
+    PPC405EP_CPC0_PLLMR0 = 0x0F0,
+    PPC405EP_CPC0_BOOT   = 0x0F1,
+    PPC405EP_CPC0_EPCTL  = 0x0F3,
+    PPC405EP_CPC0_PLLMR1 = 0x0F4,
+    PPC405EP_CPC0_UCR    = 0x0F5,
+    PPC405EP_CPC0_SRR    = 0x0F6,
+    PPC405EP_CPC0_JTAGID = 0x0F7,
+    PPC405EP_CPC0_PCI    = 0x0F9,
+#if 0
+    PPC405EP_CPC0_ER     = xxx,
+    PPC405EP_CPC0_FR     = xxx,
+    PPC405EP_CPC0_SR     = xxx,
+#endif
+};
+
+enum {
+    PPC405EP_CPU_CLK   = 0,
+    PPC405EP_PLB_CLK   = 1,
+    PPC405EP_OPB_CLK   = 2,
+    PPC405EP_EBC_CLK   = 3,
+    PPC405EP_MAL_CLK   = 4,
+    PPC405EP_PCI_CLK   = 5,
+    PPC405EP_UART0_CLK = 6,
+    PPC405EP_UART1_CLK = 7,
+    PPC405EP_CLK_NB    = 8,
+};
+
+typedef struct ppc405ep_cpc_t ppc405ep_cpc_t;
+struct ppc405ep_cpc_t {
+    uint32_t sysclk;
+    clk_setup_t clk_setup[PPC405EP_CLK_NB];
+    uint32_t boot;
+    uint32_t epctl;
+    uint32_t pllmr[2];
+    uint32_t ucr;
+    uint32_t srr;
+    uint32_t jtagid;
+    uint32_t pci;
+    /* Clock and power management */
+    uint32_t er;
+    uint32_t fr;
+    uint32_t sr;
+};
+
+static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc)
+{
+    uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk;
+    uint32_t UART0_clk, UART1_clk;
+    uint64_t VCO_out, PLL_out;
+    int M, D;
+
+    VCO_out = 0;
+    if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) {
+        M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */
+        //        printf("FBMUL %01x %d\n", (cpc->pllmr[1] >> 20) & 0xF, M);
+        D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */
+        //        printf("FWDA %01x %d\n", (cpc->pllmr[1] >> 16) & 0x7, D);
+        VCO_out = cpc->sysclk * M * D;
+        if (VCO_out < 500000000UL || VCO_out > 1000000000UL) {
+            /* Error - unlock the PLL */
+            printf("VCO out of range %" PRIu64 "\n", VCO_out);
+#if 0
+            cpc->pllmr[1] &= ~0x80000000;
+            goto pll_bypass;
+#endif
+        }
+        PLL_out = VCO_out / D;
+        /* Pretend the PLL is locked */
+        cpc->boot |= 0x00000001;
+    } else {
+#if 0
+    pll_bypass:
+#endif
+        PLL_out = cpc->sysclk;
+        if (cpc->pllmr[1] & 0x40000000) {
+            /* Pretend the PLL is not locked */
+            cpc->boot &= ~0x00000001;
+        }
+    }
+    /* Now, compute all other clocks */
+    D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */
+#ifdef DEBUG_CLOCKS
+    //    printf("CCDV %01x %d\n", (cpc->pllmr[0] >> 20) & 0x3, D);
+#endif
+    CPU_clk = PLL_out / D;
+    D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */
+#ifdef DEBUG_CLOCKS
+    //    printf("CBDV %01x %d\n", (cpc->pllmr[0] >> 16) & 0x3, D);
+#endif
+    PLB_clk = CPU_clk / D;
+    D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */
+#ifdef DEBUG_CLOCKS
+    //    printf("OPDV %01x %d\n", (cpc->pllmr[0] >> 12) & 0x3, D);
+#endif
+    OPB_clk = PLB_clk / D;
+    D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */
+#ifdef DEBUG_CLOCKS
+    //    printf("EPDV %01x %d\n", (cpc->pllmr[0] >> 8) & 0x3, D);
+#endif
+    EBC_clk = PLB_clk / D;
+    D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */
+#ifdef DEBUG_CLOCKS
+    //    printf("MPDV %01x %d\n", (cpc->pllmr[0] >> 4) & 0x3, D);
+#endif
+    MAL_clk = PLB_clk / D;
+    D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */
+#ifdef DEBUG_CLOCKS
+    //    printf("PPDV %01x %d\n", cpc->pllmr[0] & 0x3, D);
+#endif
+    PCI_clk = PLB_clk / D;
+    D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */
+#ifdef DEBUG_CLOCKS
+    //    printf("U0DIV %01x %d\n", cpc->ucr & 0x7F, D);
+#endif
+    UART0_clk = PLL_out / D;
+    D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */
+#ifdef DEBUG_CLOCKS
+    //    printf("U1DIV %01x %d\n", (cpc->ucr >> 8) & 0x7F, D);
+#endif
+    UART1_clk = PLL_out / D;
+#ifdef DEBUG_CLOCKS
+    printf("Setup PPC405EP clocks - sysclk %d VCO %" PRIu64
+           " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out);
+    printf("CPU %d PLB %d OPB %d EBC %d MAL %d PCI %d UART0 %d UART1 %d\n",
+           CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk,
+           UART0_clk, UART1_clk);
+    printf("CB %p opaque %p\n", cpc->clk_setup[PPC405EP_CPU_CLK].cb,
+           cpc->clk_setup[PPC405EP_CPU_CLK].opaque);
+#endif
+    /* Setup CPU clocks */
+    clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk);
+    /* Setup PLB clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk);
+    /* Setup OPB clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk);
+    /* Setup external clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk);
+    /* Setup MAL clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk);
+    /* Setup PCI clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk);
+    /* Setup UART0 clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk);
+    /* Setup UART1 clock */
+    clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk);
+}
+
+static target_ulong dcr_read_epcpc (void *opaque, int dcrn)
+{
+    ppc405ep_cpc_t *cpc;
+    target_ulong ret;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405EP_CPC0_BOOT:
+        ret = cpc->boot;
+        break;
+    case PPC405EP_CPC0_EPCTL:
+        ret = cpc->epctl;
+        break;
+    case PPC405EP_CPC0_PLLMR0:
+        ret = cpc->pllmr[0];
+        break;
+    case PPC405EP_CPC0_PLLMR1:
+        ret = cpc->pllmr[1];
+        break;
+    case PPC405EP_CPC0_UCR:
+        ret = cpc->ucr;
+        break;
+    case PPC405EP_CPC0_SRR:
+        ret = cpc->srr;
+        break;
+    case PPC405EP_CPC0_JTAGID:
+        ret = cpc->jtagid;
+        break;
+    case PPC405EP_CPC0_PCI:
+        ret = cpc->pci;
+        break;
+    default:
+        /* Avoid gcc warning */
+        ret = 0;
+        break;
+    }
+
+    return ret;
+}
+
+static void dcr_write_epcpc (void *opaque, int dcrn, target_ulong val)
+{
+    ppc405ep_cpc_t *cpc;
+
+    cpc = opaque;
+    switch (dcrn) {
+    case PPC405EP_CPC0_BOOT:
+        /* Read-only register */
+        break;
+    case PPC405EP_CPC0_EPCTL:
+        /* Don't care for now */
+        cpc->epctl = val & 0xC00000F3;
+        break;
+    case PPC405EP_CPC0_PLLMR0:
+        cpc->pllmr[0] = val & 0x00633333;
+        ppc405ep_compute_clocks(cpc);
+        break;
+    case PPC405EP_CPC0_PLLMR1:
+        cpc->pllmr[1] = val & 0xC0F73FFF;
+        ppc405ep_compute_clocks(cpc);
+        break;
+    case PPC405EP_CPC0_UCR:
+        /* UART control - don't care for now */
+        cpc->ucr = val & 0x003F7F7F;
+        break;
+    case PPC405EP_CPC0_SRR:
+        cpc->srr = val;
+        break;
+    case PPC405EP_CPC0_JTAGID:
+        /* Read-only */
+        break;
+    case PPC405EP_CPC0_PCI:
+        cpc->pci = val;
+        break;
+    }
+}
+
+static void ppc405ep_cpc_reset (void *opaque)
+{
+    ppc405ep_cpc_t *cpc = opaque;
+
+    cpc->boot = 0x00000010;     /* Boot from PCI - IIC EEPROM disabled */
+    cpc->epctl = 0x00000000;
+    cpc->pllmr[0] = 0x00011010;
+    cpc->pllmr[1] = 0x40000000;
+    cpc->ucr = 0x00000000;
+    cpc->srr = 0x00040000;
+    cpc->pci = 0x00000000;
+    cpc->er = 0x00000000;
+    cpc->fr = 0x00000000;
+    cpc->sr = 0x00000000;
+    ppc405ep_compute_clocks(cpc);
+}
+
+/* XXX: sysclk should be between 25 and 100 MHz */
+static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8],
+                               uint32_t sysclk)
+{
+    ppc405ep_cpc_t *cpc;
+
+    cpc = qemu_mallocz(sizeof(ppc405ep_cpc_t));
+    if (cpc != NULL) {
+        memcpy(cpc->clk_setup, clk_setup,
+               PPC405EP_CLK_NB * sizeof(clk_setup_t));
+        cpc->jtagid = 0x20267049;
+        cpc->sysclk = sysclk;
+        ppc405ep_cpc_reset(cpc);
+        qemu_register_reset(&ppc405ep_cpc_reset, cpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+#if 0
+        ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+        ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc,
+                         &dcr_read_epcpc, &dcr_write_epcpc);
+#endif
+    }
+}
+
+CPUState *ppc405ep_init (target_phys_addr_t ram_bases[2],
+                         target_phys_addr_t ram_sizes[2],
+                         uint32_t sysclk, qemu_irq **picp,
+                         ram_addr_t *offsetp, int do_init)
+{
+    clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
+    qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
+    CPUState *env;
+    ppc4xx_mmio_t *mmio;
+    qemu_irq *pic, *irqs;
+    ram_addr_t offset;
+    int i;
+
+    memset(clk_setup, 0, sizeof(clk_setup));
+    /* init CPUs */
+    env = ppc405_init("405ep", &clk_setup[PPC405EP_CPU_CLK],
+                      &tlb_clk_setup, sysclk);
+    clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb;
+    clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque;
+    /* Internal devices init */
+    /* Memory mapped devices registers */
+    mmio = ppc4xx_mmio_init(env, 0xEF600000);
+    /* PLB arbitrer */
+    ppc4xx_plb_init(env);
+    /* PLB to OPB bridge */
+    ppc4xx_pob_init(env);
+    /* OBP arbitrer */
+    ppc4xx_opba_init(env, mmio, 0x600);
+    /* Universal interrupt controller */
+    irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+    irqs[PPCUIC_OUTPUT_INT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_INT];
+    irqs[PPCUIC_OUTPUT_CINT] =
+        ((qemu_irq *)env->irq_inputs)[PPC40x_INPUT_CINT];
+    pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+    *picp = pic;
+    /* SDRAM controller */
+    ppc405_sdram_init(env, pic[14], 2, ram_bases, ram_sizes, do_init);
+    offset = 0;
+    for (i = 0; i < 2; i++)
+        offset += ram_sizes[i];
+    /* External bus controller */
+    ppc405_ebc_init(env);
+    /* DMA controller */
+    dma_irqs[0] = pic[26];
+    dma_irqs[1] = pic[25];
+    dma_irqs[2] = pic[24];
+    dma_irqs[3] = pic[23];
+    ppc405_dma_init(env, dma_irqs);
+    /* IIC controller */
+    ppc405_i2c_init(env, mmio, 0x500, pic[29]);
+    /* GPIO */
+    ppc405_gpio_init(env, mmio, 0x700);
+    /* Serial ports */
+    if (serial_hds[0] != NULL) {
+        ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]);
+    }
+    if (serial_hds[1] != NULL) {
+        ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]);
+    }
+    /* OCM */
+    ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]);
+    offset += 4096;
+    /* GPT */
+    gpt_irqs[0] = pic[12];
+    gpt_irqs[1] = pic[11];
+    gpt_irqs[2] = pic[10];
+    gpt_irqs[3] = pic[9];
+    gpt_irqs[4] = pic[8];
+    ppc4xx_gpt_init(env, mmio, 0x000, gpt_irqs);
+    /* PCI */
+    /* Uses pic[28], pic[15], pic[13] */
+    /* MAL */
+    mal_irqs[0] = pic[20];
+    mal_irqs[1] = pic[19];
+    mal_irqs[2] = pic[18];
+    mal_irqs[3] = pic[17];
+    ppc405_mal_init(env, mal_irqs);
+    /* Ethernet */
+    /* Uses pic[22], pic[16], pic[14] */
+    /* CPU control */
+    ppc405ep_cpc_init(env, clk_setup, sysclk);
+    *offsetp = offset;
+
+    return env;
+}
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
index 1e0fd2e..6474615 100644
--- a/hw/ppc_chrp.c
+++ b/hw/ppc_chrp.c
@@ -1,8 +1,8 @@
 /*
  * QEMU PPC CHRP/PMAC hardware System Emulator
- * 
- * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
+ * Copyright (c) 2004-2007 Fabrice Bellard
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -23,6 +23,9 @@
  */
 #include "vl.h"
 
+/* SMP is not enabled, for now */
+#define MAX_CPUS 1
+
 #define BIOS_FILENAME "ppc_rom.bin"
 #define VGABIOS_FILENAME "video.x"
 #define NVRAM_SIZE        0x2000
@@ -43,22 +46,26 @@
 
 /* DBDMA: currently no op - should suffice right now */
 
-static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void dbdma_writeb (void *opaque,
+                          target_phys_addr_t addr, uint32_t value)
 {
-    printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value);
+    printf("%s: 0x" PADDRX " <= 0x%08x\n", __func__, addr, value);
 }
 
-static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void dbdma_writew (void *opaque,
+                          target_phys_addr_t addr, uint32_t value)
 {
 }
 
-static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void dbdma_writel (void *opaque,
+                          target_phys_addr_t addr, uint32_t value)
 {
 }
 
 static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr)
 {
-    printf("%s: 0x%08x => 0x00000000\n", __func__, addr);
+    printf("%s: 0x" PADDRX " => 0x00000000\n", __func__, addr);
+
     return 0;
 }
 
@@ -89,7 +96,8 @@
     uint8_t data[0x2000];
 } MacIONVRAMState;
 
-static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void macio_nvram_writeb (void *opaque,
+                                target_phys_addr_t addr, uint32_t value)
 {
     MacIONVRAMState *s = opaque;
     addr = (addr >> 4) & 0x1fff;
@@ -105,6 +113,7 @@
     addr = (addr >> 4) & 0x1fff;
     value = s->data[addr];
     //    printf("macio_nvram_readb %04x = %02x\n", addr, value);
+
     return value;
 }
 
@@ -120,22 +129,23 @@
     &macio_nvram_readb,
 };
 
-static MacIONVRAMState *macio_nvram_init(void)
+static MacIONVRAMState *macio_nvram_init (void)
 {
     MacIONVRAMState *s;
     s = qemu_mallocz(sizeof(MacIONVRAMState));
     if (!s)
         return NULL;
-    macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read, 
+    macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read,
                                                    macio_nvram_write, s);
+
     return s;
 }
 
-static void macio_map(PCIDevice *pci_dev, int region_num, 
-                      uint32_t addr, uint32_t size, int type)
+static void macio_map (PCIDevice *pci_dev, int region_num,
+                       uint32_t addr, uint32_t size, int type)
 {
     if (heathrow_pic_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x00000, 0x1000, 
+        cpu_register_physical_memory(addr + 0x00000, 0x1000,
                                      heathrow_pic_mem_index);
     }
     cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index);
@@ -145,14 +155,15 @@
     if (ide1_mem_index >= 0)
         cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
     if (openpic_mem_index >= 0) {
-        cpu_register_physical_memory(addr + 0x40000, 0x40000, 
+        cpu_register_physical_memory(addr + 0x40000, 0x40000,
                                      openpic_mem_index);
     }
     if (macio_nvram_mem_index >= 0)
-        cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index);
+        cpu_register_physical_memory(addr + 0x60000, 0x20000,
+                                     macio_nvram_mem_index);
 }
 
-static void macio_init(PCIBus *bus, int device_id)
+static void macio_init (PCIBus *bus, int device_id)
 {
     PCIDevice *d;
 
@@ -170,10 +181,10 @@
     d->config[0x0e] = 0x00; // header_type
 
     d->config[0x3d] = 0x01; // interrupt on pin 1
-    
+
     dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL);
 
-    pci_register_io_region(d, 0, 0x80000, 
+    pci_register_io_region(d, 0, 0x80000,
                            PCI_ADDRESS_SPACE_MEM, macio_map);
 }
 
@@ -201,11 +212,12 @@
 
 /* temporary frame buffer OSI calls for the video.x driver. The right
    solution is to modify the driver to use VGA PCI I/Os */
-static int vga_osi_call(CPUState *env)
+/* XXX: to be removed. This is no way related to emulation */
+static int vga_osi_call (CPUState *env)
 {
     static int vga_vbl_enabled;
     int linesize;
-    
+
     //    printf("osi_call R5=%d\n", env->gpr[5]);
 
     /* same handler as PearPC, coming from the original MOL video
@@ -226,7 +238,7 @@
                 break;
             }
         }
-        env->gpr[3] = 0; 
+        env->gpr[3] = 0;
         env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
         env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
         env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
@@ -252,24 +264,20 @@
         break;
     case 64: /* get color */
         /* R6 = index */
-        env->gpr[3] = 0; 
+        env->gpr[3] = 0;
         break;
     case 116: /* set hwcursor */
         /* R6 = x, R7 = y, R8 = visible, R9 = data */
         break;
     default:
-        fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]);
+        fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]);
         break;
     }
+
     return 1; /* osi_call handled */
 }
 
-/* XXX: suppress that */
-static void pic_irq_request(void *opaque, int level)
-{
-}
-
-static uint8_t nvram_chksum(const uint8_t *buf, int n)
+static uint8_t nvram_chksum (const uint8_t *buf, int n)
 {
     int sum, i;
     sum = 0;
@@ -279,31 +287,31 @@
 }
 
 /* set a free Mac OS NVRAM partition */
-void pmac_format_nvram_partition(uint8_t *buf, int len)
+void pmac_format_nvram_partition (uint8_t *buf, int len)
 {
     char partition_name[12] = "wwwwwwwwwwww";
-    
+
     buf[0] = 0x7f; /* free partition magic */
     buf[1] = 0; /* checksum */
     buf[2] = len >> 8;
     buf[3] = len;
     memcpy(buf + 4, partition_name, 12);
     buf[1] = nvram_chksum(buf, 16);
-}    
+}
 
 /* PowerPC CHRP hardware initialisation */
-static void ppc_chrp_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,
-                          int is_heathrow)
+static void ppc_chrp_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,
+                           int is_heathrow)
 {
-    CPUState *env;
+    CPUState *env, *envs[MAX_CPUS];
     char buf[1024];
-    SetIRQFunc *set_irq;
-    void *pic;
+    qemu_irq *pic, **openpic_irqs;
     m48t59_t *nvram;
     int unin_memory;
     int linux_boot, i;
@@ -313,38 +321,28 @@
     PCIBus *pci_bus;
     const char *arch_name;
     int vga_bios_size, bios_size;
+    qemu_irq *dummy_irq;
 
     linux_boot = (kernel_filename != NULL);
 
     /* init CPUs */
     env = cpu_init();
+    qemu_register_reset(&cpu_ppc_reset, env);
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
 
-    /* Register CPU as a 74x/75x */
-    /* XXX: CPU model (or PVR) should be provided on command line */
-    //    ppc_find_by_name("750gx", &def); // Linux boot OK
-    //    ppc_find_by_name("750fx", &def); // Linux boot OK
-    /* Linux does not boot on 750cxe (and probably other 750cx based)
-     * because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
-     */
-    //    ppc_find_by_name("750cxe", &def);
-    //    ppc_find_by_name("750p", &def);
-    //    ppc_find_by_name("740p", &def);
-    ppc_find_by_name("750", &def);
-    //    ppc_find_by_name("740", &def);
-    //    ppc_find_by_name("G3", &def);
-    //    ppc_find_by_name("604r", &def);
-    //    ppc_find_by_name("604e", &def);
-    //    ppc_find_by_name("604", &def);
+    if (cpu_model == NULL)
+        cpu_model = "default";
+    ppc_find_by_name(cpu_model, &def);
     if (def == NULL) {
         cpu_abort(env, "Unable to find PowerPC CPU definition\n");
     }
-    cpu_ppc_register(env, def);
-
-    /* Set time-base frequency to 100 Mhz */
-    cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
-    
-    env->osi_call = vga_osi_call;
+    for (i = 0; i < smp_cpus; i++) {
+        cpu_ppc_register(env, def);
+        /* Set time-base frequency to 100 Mhz */
+        cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
+        env->osi_call = vga_osi_call;
+        envs[i] = env;
+    }
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
@@ -354,13 +352,13 @@
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
     bios_size = load_image(buf, phys_ram_base + bios_offset);
     if (bios_size < 0 || bios_size > BIOS_SIZE) {
-        fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+        cpu_abort(env, "qemu: could not load PowerPC bios '%s'\n", buf);
         exit(1);
     }
     bios_size = (bios_size + 0xfff) & ~0xfff;
-    cpu_register_physical_memory((uint32_t)(-bios_size), 
+    cpu_register_physical_memory((uint32_t)(-bios_size),
                                  bios_size, bios_offset | IO_MEM_ROM);
-    
+
     /* allocate and load VGA BIOS */
     vga_bios_offset = bios_offset + bios_size;
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
@@ -376,19 +374,19 @@
         phys_ram_base[vga_bios_offset + 1] = 'D';
         phys_ram_base[vga_bios_offset + 2] = 'R';
         phys_ram_base[vga_bios_offset + 3] = 'V';
-        cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4), 
+        cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
                      vga_bios_size);
         vga_bios_size += 8;
     }
     vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
-    
+
     if (linux_boot) {
         kernel_base = KERNEL_LOAD_ADDR;
         /* now we can load the kernel */
         kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
         if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
-                    kernel_filename);
+            cpu_abort(env, "qemu: could not load kernel '%s'\n",
+                      kernel_filename);
             exit(1);
         }
         /* load initrd */
@@ -397,8 +395,8 @@
             initrd_size = load_image(initrd_filename,
                                      phys_ram_base + initrd_base);
             if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
-                        initrd_filename);
+                cpu_abort(env, "qemu: could not load initial ram disk '%s'\n",
+                          initrd_filename);
                 exit(1);
             }
         } else {
@@ -415,38 +413,41 @@
 
     if (is_heathrow) {
         isa_mem_base = 0x80000000;
-        
+
         /* Register 2 MB of ISA IO space */
         isa_mmio_init(0xfe000000, 0x00200000);
 
         /* init basic PC hardware */
+        if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+            cpu_abort(env, "Only 6xx bus is supported on heathrow machine\n");
+            exit(1);
+        }
         pic = heathrow_pic_init(&heathrow_pic_mem_index);
-        set_irq = heathrow_pic_set_irq;
         pci_bus = pci_grackle_init(0xfec00000, pic);
-        pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, 
+        pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
                      ram_size, vga_ram_size,
                      vga_bios_offset, vga_bios_size);
 
         /* XXX: suppress that */
-        isa_pic = pic_init(pic_irq_request, NULL);
-        
+        dummy_irq = i8259_init(NULL);
+
         /* XXX: use Mac Serial port */
-        serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
-        
+        serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
+
         for(i = 0; i < nb_nics; i++) {
             if (!nd_table[i].model)
                 nd_table[i].model = "ne2k_pci";
             pci_nic_init(pci_bus, &nd_table[i], -1);
         }
-        
+
         pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
 
         /* cuda also initialize ADB */
-        cuda_mem_index = cuda_init(set_irq, pic, 0x12);
-        
+        cuda_mem_index = cuda_init(pic[0x12]);
+
         adb_kbd_init(&adb_bus);
         adb_mouse_init(&adb_bus);
-        
+
         {
             MacIONVRAMState *nvr;
             nvr = macio_nvram_init();
@@ -454,22 +455,63 @@
         }
 
         macio_init(pci_bus, 0x0017);
-        
-        nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
-        
+
+        nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
+
         arch_name = "HEATHROW";
     } else {
         isa_mem_base = 0x80000000;
-        
+
         /* Register 8 MB of ISA IO space */
         isa_mmio_init(0xf2000000, 0x00800000);
-        
+
         /* UniN init */
         unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
         cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
 
-        pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
-        set_irq = openpic_set_irq;
+        openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
+        openpic_irqs[0] =
+            qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+        for (i = 0; i < smp_cpus; i++) {
+            /* Mac99 IRQ connection between OpenPIC outputs pins
+             * and PowerPC input pins
+             */
+            switch (PPC_INPUT(env)) {
+            case PPC_FLAGS_INPUT_6xx:
+                openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
+                openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+                    ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
+                openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+                    ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
+                openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+                    ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
+                /* Not connected ? */
+                openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
+                /* Check this */
+                openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+                    ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
+                break;
+            case PPC_FLAGS_INPUT_970:
+                openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
+                openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+                    ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
+                openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+                    ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
+                openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+                    ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
+                /* Not connected ? */
+                openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
+                /* Check this */
+                openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+                    ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
+                break;
+            default:
+                cpu_abort(env, "Bus model not supported on mac99 machine\n");
+                exit(1);
+            }
+        }
+        pic = openpic_init(NULL, &openpic_mem_index, smp_cpus,
+                           openpic_irqs, NULL);
         pci_bus = pci_pmac_init(pic);
         /* init basic PC hardware */
         pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
@@ -477,36 +519,36 @@
                      vga_bios_offset, vga_bios_size);
 
         /* XXX: suppress that */
-        isa_pic = pic_init(pic_irq_request, NULL);
-        
+        dummy_irq = i8259_init(NULL);
+
         /* XXX: use Mac Serial port */
-        serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
-        
+        serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
         for(i = 0; i < nb_nics; i++) {
-            pci_ne2000_init(pci_bus, &nd_table[i], -1);
+            if (!nd_table[i].model)
+                nd_table[i].model = "ne2k_pci";
+            pci_nic_init(pci_bus, &nd_table[i], -1);
         }
-        
 #if 1
-        ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13);
-        ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14);
+        ide0_mem_index = pmac_ide_init(&bs_table[0], pic[0x13]);
+        ide1_mem_index = pmac_ide_init(&bs_table[2], pic[0x14]);
 #else
         pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
 #endif
         /* cuda also initialize ADB */
-        cuda_mem_index = cuda_init(set_irq, pic, 0x19);
-        
+        cuda_mem_index = cuda_init(pic[0x19]);
+
         adb_kbd_init(&adb_bus);
         adb_mouse_init(&adb_bus);
-        
+
         macio_init(pci_bus, 0x0022);
-        
-        nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
-        
+
+        nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
+
         arch_name = "MAC99";
     }
 
     if (usb_enabled) {
-        usb_ohci_init(pci_bus, 3, -1);
+        usb_ohci_init_pci(pci_bus, 3, -1);
     }
 
     if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
@@ -525,30 +567,32 @@
     register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
 }
 
-static void ppc_core99_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)
+static void ppc_core99_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)
 {
     ppc_chrp_init(ram_size, vga_ram_size, boot_device,
                   ds, fd_filename, snapshot,
                   kernel_filename, kernel_cmdline,
-                  initrd_filename, 0);
+                  initrd_filename, cpu_model, 0);
 }
-    
-static void ppc_heathrow_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)
+
+static void ppc_heathrow_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)
 {
     ppc_chrp_init(ram_size, vga_ram_size, boot_device,
                   ds, fd_filename, snapshot,
                   kernel_filename, kernel_cmdline,
-                  initrd_filename, 1);
+                  initrd_filename, cpu_model, 1);
 }
 
 QEMUMachine core99_machine = {
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index c4b7ff5..504ca33 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -1,8 +1,8 @@
 /*
  * QEMU PPC PREP hardware System Emulator
- * 
- * Copyright (c) 2003-2004 Jocelyn Mayer
- * 
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -76,7 +76,7 @@
 int speaker_data_on;
 int dummy_refresh_clock;
 
-static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void speaker_ioport_write (void *opaque, uint32_t addr, uint32_t val)
 {
 #if 0
     speaker_data_on = (val >> 1) & 1;
@@ -84,29 +84,22 @@
 #endif
 }
 
-static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
+static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
 {
 #if 0
     int out;
     out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
     dummy_refresh_clock ^= 1;
     return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
-      (dummy_refresh_clock << 4);
+        (dummy_refresh_clock << 4);
 #endif
     return 0;
 }
 
-static void pic_irq_request(void *opaque, int level)
-{
-    if (level)
-        cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
-    else
-        cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
-}
-
 /* PCI intack register */
 /* Read-only register (?) */
-static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void _PPC_intack_write (void *opaque,
+                               target_phys_addr_t addr, uint32_t value)
 {
     //    printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value);
 }
@@ -117,7 +110,7 @@
 
     if (addr == 0xBFFFFFF0)
         retval = pic_intack_read(isa_pic);
-       //   printf("%s: 0x%08x <= %d\n", __func__, addr, retval);
+    //   printf("%s: 0x%08x <= %d\n", __func__, addr, retval);
 
     return retval;
 }
@@ -184,12 +177,14 @@
     /* Error diagnostic */
 } XCSR;
 
-static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void PPC_XCSR_writeb (void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
 {
     printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
 }
 
-static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void PPC_XCSR_writew (void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
 {
 #ifdef TARGET_WORDS_BIGENDIAN
     value = bswap16(value);
@@ -197,7 +192,8 @@
     printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
 }
 
-static void PPC_XCSR_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void PPC_XCSR_writel (void *opaque,
+                             target_phys_addr_t addr, uint32_t value)
 {
 #ifdef TARGET_WORDS_BIGENDIAN
     value = bswap32(value);
@@ -294,7 +290,7 @@
         /* Special port 92 */
         /* Check soft reset asked */
         if (val & 0x01) {
-            //            cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
+            //            cpu_interrupt(first_cpu, PPC_INTERRUPT_RESET);
         }
         /* Check LE mode */
         if (val & 0x02) {
@@ -518,10 +514,12 @@
 #define NVRAM_SIZE        0x2000
 
 /* PowerPC PREP hardware initialisation */
-static void ppc_prep_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)
+static void ppc_prep_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;
     char buf[1024];
@@ -532,23 +530,23 @@
     uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
     ppc_def_t *def;
     PCIBus *pci_bus;
+    qemu_irq *i8259;
 
     sysctrl = qemu_mallocz(sizeof(sysctrl_t));
     if (sysctrl == NULL)
-	return;
+        return;
 
     linux_boot = (kernel_filename != NULL);
-    
+
     /* init CPUs */
 
     env = cpu_init();
+    qemu_register_reset(&cpu_ppc_reset, env);
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
-    
-    /* Register CPU as a 604 */
-    /* XXX: CPU model (or PVR) should be provided on command line */
-    //    ppc_find_by_name("604r", &def);
-    //    ppc_find_by_name("604e", &def);
-    ppc_find_by_name("604", &def);
+
+    if (cpu_model == NULL)
+        cpu_model = "default";
+    ppc_find_by_name(cpu_model, &def);
     if (def == NULL) {
         cpu_abort(env, "Unable to find PowerPC CPU definition\n");
     }
@@ -564,11 +562,11 @@
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
     bios_size = load_image(buf, phys_ram_base + bios_offset);
     if (bios_size < 0 || bios_size > BIOS_SIZE) {
-        fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
+        cpu_abort(env, "qemu: could not load PPC PREP bios '%s'\n", buf);
         exit(1);
     }
     bios_size = (bios_size + 0xfff) & ~0xfff;
-    cpu_register_physical_memory((uint32_t)(-bios_size), 
+    cpu_register_physical_memory((uint32_t)(-bios_size),
                                  bios_size, bios_offset | IO_MEM_ROM);
 
     if (linux_boot) {
@@ -576,8 +574,8 @@
         /* now we can load the kernel */
         kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
         if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
-                    kernel_filename);
+            cpu_abort(env, "qemu: could not load kernel '%s'\n",
+                      kernel_filename);
             exit(1);
         }
         /* load initrd */
@@ -586,8 +584,8 @@
             initrd_size = load_image(initrd_filename,
                                      phys_ram_base + initrd_base);
             if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
-                        initrd_filename);
+                cpu_abort(env, "qemu: could not load initial ram disk '%s'\n",
+                          initrd_filename);
                 exit(1);
             }
         } else {
@@ -603,7 +601,12 @@
     }
 
     isa_mem_base = 0xc0000000;
-    pci_bus = pci_prep_init();
+    if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+        cpu_abort(env, "Only 6xx bus is supported on PREP machine\n");
+        exit(1);
+    }
+    i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
+    pci_bus = pci_prep_init(i8259);
     //    pci_bus = i440fx_init();
     /* Register 8 MB of ISA IO space (needed for non-contiguous map) */
     PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read,
@@ -611,37 +614,40 @@
     cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
 
     /* init basic PC hardware */
-    pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, 
+    pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size,
                  vga_ram_size, 0, 0);
-    rtc_init(0x70, 8);
     //    openpic = openpic_init(0x00000000, 0xF0000000, 1);
-    isa_pic = pic_init(pic_irq_request, first_cpu);
-    //    pit = pit_init(0x40, 0);
+    //    pit = pit_init(0x40, i8259[0]);
+    rtc_init(0x70, i8259[8]);
 
-    serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
+    serial_init(0x3f8, i8259[4], serial_hds[0]);
     nb_nics1 = nb_nics;
     if (nb_nics1 > NE2000_NB_MAX)
         nb_nics1 = NE2000_NB_MAX;
     for(i = 0; i < nb_nics1; i++) {
         if (nd_table[0].model == NULL
             || strcmp(nd_table[0].model, "ne2k_isa") == 0) {
-            isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
+            isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]);
+        } else if (strcmp(nd_table[0].model, "?") == 0) {
+            fprintf(stderr, "qemu: Supported NICs: ne2k_isa\n");
+            exit (1);
         } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
+            /* Why ? */
+            cpu_abort(env, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
             exit (1);
         }
     }
 
     for(i = 0; i < 2; i++) {
-        isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+        isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
                      bs_table[2 * i], bs_table[2 * i + 1]);
     }
-    kbd_init();
+    i8042_init(i8259[1], i8259[12], 0x60);
     DMA_init(1);
     //    AUD_init();
     //    SB16_init();
 
-    fdctrl_init(6, 2, 0, 0x3f0, fd_table);
+    fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table);
 
     /* Register speaker port */
     register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
@@ -660,15 +666,16 @@
     cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
     /* PowerPC control and status register group */
 #if 0
-    PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL);
+    PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write,
+                                           NULL);
     cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
 #endif
 
     if (usb_enabled) {
-        usb_ohci_init(pci_bus, 3, -1);
+        usb_ohci_init_pci(pci_bus, 3, -1);
     }
 
-    nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
+    nvram = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
     if (nvram == NULL)
         return;
     sysctrl->nvram = nvram;
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
index 3d93c06..f384e42 100644
--- a/hw/prep_pci.c
+++ b/hw/prep_pci.c
@@ -2,7 +2,7 @@
  * QEMU PREP PCI host
  *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -123,19 +123,19 @@
     return (irq_num + (pci_dev->devfn >> 3)) & 1;
 }
 
-static void prep_set_irq(void *pic, int irq_num, int level)
+static void prep_set_irq(qemu_irq *pic, int irq_num, int level)
 {
-    pic_set_irq(irq_num ? 11 : 9, level);
+    qemu_set_irq(pic[irq_num ? 11 : 9], level);
 }
 
-PCIBus *pci_prep_init(void)
+PCIBus *pci_prep_init(qemu_irq *pic)
 {
     PREPPCIState *s;
     PCIDevice *d;
     int PPC_io_memory;
 
     s = qemu_mallocz(sizeof(PREPPCIState));
-    s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0, 2);
+    s->bus = pci_register_bus(prep_set_irq, prep_map_irq, pic, 0, 2);
 
     register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
     register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
@@ -147,12 +147,12 @@
     register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
     register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
 
-    PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read, 
+    PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read,
                                            PPC_PCIIO_write, s);
     cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
 
-    /* PCI host bridge */ 
-    d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven", 
+    /* PCI host bridge */
+    d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
                             sizeof(PCIDevice), 0, NULL, NULL);
     d->config[0x00] = 0x57; // vendor_id : Motorola
     d->config[0x01] = 0x10;
diff --git a/hw/ps2.c b/hw/ps2.c
index 3794c60..5367df1 100644
--- a/hw/ps2.c
+++ b/hw/ps2.c
@@ -1,8 +1,8 @@
 /*
  * QEMU PS/2 keyboard/mouse emulation
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -146,7 +146,7 @@
     PS2State *s = (PS2State *)opaque;
     PS2Queue *q;
     int val, index;
-    
+
     q = &s->queue;
     if (q->count == 0) {
         /* NOTE: if no data left, we return the last keyboard one
@@ -294,7 +294,7 @@
     s->mouse_dz -= dz1;
 }
 
-static void ps2_mouse_event(void *opaque, 
+static void ps2_mouse_event(void *opaque,
                             int dx, int dy, int dz, int buttons_state)
 {
     PS2MouseState *s = opaque;
@@ -311,7 +311,7 @@
         s->mouse_buttons == buttons_state)
 	return;
     s->mouse_buttons = buttons_state;
-    
+
     if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
         (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
         for(;;) {
@@ -324,6 +324,11 @@
     }
 }
 
+void ps2_mouse_fake_event(void *opaque)
+{
+    ps2_mouse_event(opaque, 1, 0, 0, 0);
+}
+
 void ps2_write_mouse(void *opaque, int val)
 {
     PS2MouseState *s = (PS2MouseState *)opaque;
@@ -429,12 +434,12 @@
                 s->mouse_detect_state = 0;
             break;
         case 2:
-            if (val == 80) 
+            if (val == 80)
                 s->mouse_type = 3; /* IMPS/2 */
             s->mouse_detect_state = 0;
             break;
         case 3:
-            if (val == 80) 
+            if (val == 80)
                 s->mouse_type = 4; /* IMEX */
             s->mouse_detect_state = 0;
             break;
diff --git a/hw/ptimer.c b/hw/ptimer.c
new file mode 100644
index 0000000..d81503a
--- /dev/null
+++ b/hw/ptimer.c
@@ -0,0 +1,191 @@
+/*
+ * 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.  */
+    uint64_t limit;
+    uint64_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);
+    }
+}
+
+uint64_t ptimer_get_count(ptimer_state *s)
+{
+    int64_t now;
+    uint64_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 {
+            uint64_t rem;
+            uint64_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, uint64_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 "lose" 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)
+{
+    s->period = period;
+    s->period_frac = 0;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+/* Set counter frequency in Hz.  */
+void ptimer_set_freq(ptimer_state *s, uint32_t freq)
+{
+    s->period = 1000000000ll / freq;
+    s->period_frac = (1000000000ll << 32) / freq;
+    if (s->enabled) {
+        s->next_event = qemu_get_clock(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+/* Set the initial countdown value.  If reload is nonzero then also set
+   count = limit.  */
+void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
+{
+    s->limit = limit;
+    if (reload)
+        s->delta = limit;
+    if (s->enabled && reload) {
+        s->next_event = qemu_get_clock(vm_clock);
+        ptimer_reload(s);
+    }
+}
+
+void qemu_put_ptimer(QEMUFile *f, ptimer_state *s)
+{
+    qemu_put_byte(f, s->enabled);
+    qemu_put_be64s(f, &s->limit);
+    qemu_put_be64s(f, &s->delta);
+    qemu_put_be32s(f, &s->period_frac);
+    qemu_put_be64s(f, &s->period);
+    qemu_put_be64s(f, &s->last_event);
+    qemu_put_be64s(f, &s->next_event);
+    qemu_put_timer(f, s->timer);
+}
+
+void qemu_get_ptimer(QEMUFile *f, ptimer_state *s)
+{
+    s->enabled = qemu_get_byte(f);
+    qemu_get_be64s(f, &s->limit);
+    qemu_get_be64s(f, &s->delta);
+    qemu_get_be32s(f, &s->period_frac);
+    qemu_get_be64s(f, &s->period);
+    qemu_get_be64s(f, &s->last_event);
+    qemu_get_be64s(f, &s->next_event);
+    qemu_get_timer(f, s->timer);
+}
+
+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;
+}
+
diff --git a/hw/pxa.h b/hw/pxa.h
new file mode 100644
index 0000000..90ffd60
--- /dev/null
+++ b/hw/pxa.h
@@ -0,0 +1,214 @@
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licenced under the GPL.
+ */
+#ifndef PXA_H
+# define PXA_H			"pxa.h"
+
+/* Interrupt numbers */
+# define PXA2XX_PIC_SSP3	0
+# define PXA2XX_PIC_USBH2	2
+# define PXA2XX_PIC_USBH1	3
+# define PXA2XX_PIC_PWRI2C	6
+# define PXA25X_PIC_HWUART	7
+# define PXA27X_PIC_OST_4_11	7
+# define PXA2XX_PIC_GPIO_0	8
+# define PXA2XX_PIC_GPIO_1	9
+# define PXA2XX_PIC_GPIO_X	10
+# define PXA2XX_PIC_I2S 	13
+# define PXA26X_PIC_ASSP	15
+# define PXA25X_PIC_NSSP	16
+# define PXA27X_PIC_SSP2	16
+# define PXA2XX_PIC_LCD		17
+# define PXA2XX_PIC_I2C		18
+# define PXA2XX_PIC_ICP		19
+# define PXA2XX_PIC_STUART	20
+# define PXA2XX_PIC_BTUART	21
+# define PXA2XX_PIC_FFUART	22
+# define PXA2XX_PIC_MMC		23
+# define PXA2XX_PIC_SSP		24
+# define PXA2XX_PIC_DMA		25
+# define PXA2XX_PIC_OST_0	26
+# define PXA2XX_PIC_RTC1HZ	30
+# define PXA2XX_PIC_RTCALARM	31
+
+/* DMA requests */
+# define PXA2XX_RX_RQ_I2S	2
+# define PXA2XX_TX_RQ_I2S	3
+# define PXA2XX_RX_RQ_BTUART	4
+# define PXA2XX_TX_RQ_BTUART	5
+# define PXA2XX_RX_RQ_FFUART	6
+# define PXA2XX_TX_RQ_FFUART	7
+# define PXA2XX_RX_RQ_SSP1	13
+# define PXA2XX_TX_RQ_SSP1	14
+# define PXA2XX_RX_RQ_SSP2	15
+# define PXA2XX_TX_RQ_SSP2	16
+# define PXA2XX_RX_RQ_ICP	17
+# define PXA2XX_TX_RQ_ICP	18
+# define PXA2XX_RX_RQ_STUART	19
+# define PXA2XX_TX_RQ_STUART	20
+# define PXA2XX_RX_RQ_MMCI	21
+# define PXA2XX_TX_RQ_MMCI	22
+# define PXA2XX_USB_RQ(x)	((x) + 24)
+# define PXA2XX_RX_RQ_SSP3	66
+# define PXA2XX_TX_RQ_SSP3	67
+
+# define PXA2XX_SDRAM_BASE	0xa0000000
+# define PXA2XX_INTERNAL_BASE	0x5c000000
+# define PXA2XX_INTERNAL_SIZE	0x40000
+
+/* pxa2xx_pic.c */
+qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env);
+
+/* pxa2xx_timer.c */
+void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs);
+void pxa27x_timer_init(target_phys_addr_t base, qemu_irq *irqs, qemu_irq irq4);
+
+/* pxa2xx_gpio.c */
+struct pxa2xx_gpio_info_s;
+struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
+                CPUState *env, qemu_irq *pic, int lines);
+void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level);
+void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line,
+                gpio_handler_t handler, void *opaque);
+void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s,
+                void (*handler)(void *opaque), void *opaque);
+
+/* pxa2xx_dma.c */
+struct pxa2xx_dma_state_s;
+struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
+                qemu_irq irq);
+struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
+                qemu_irq irq);
+void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on);
+
+/* pxa2xx_lcd.c */
+struct pxa2xx_lcdc_s;
+struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base,
+                qemu_irq irq, DisplayState *ds);
+void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s,
+                void (*cb)(void *opaque), void *opaque);
+void pxa2xx_lcdc_oritentation(void *opaque, int angle);
+
+/* pxa2xx_mmci.c */
+struct pxa2xx_mmci_s;
+struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base,
+                qemu_irq irq, void *dma);
+void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque,
+                void (*readonly_cb)(void *, int),
+                void (*coverswitch_cb)(void *, int));
+
+/* pxa2xx_pcmcia.c */
+struct pxa2xx_pcmcia_s;
+struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base);
+int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card);
+int pxa2xx_pcmcia_dettach(void *opaque);
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq);
+
+/* pxa2xx.c */
+struct pxa2xx_ssp_s;
+void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
+                uint32_t (*readfn)(void *opaque),
+                void (*writefn)(void *opaque, uint32_t value), void *opaque);
+
+struct pxa2xx_i2c_s;
+struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base,
+                qemu_irq irq, uint32_t page_size);
+i2c_bus *pxa2xx_i2c_bus(struct pxa2xx_i2c_s *s);
+
+struct pxa2xx_i2s_s;
+struct pxa2xx_fir_s;
+
+struct pxa2xx_state_s {
+    CPUState *env;
+    qemu_irq *pic;
+    struct pxa2xx_dma_state_s *dma;
+    struct pxa2xx_gpio_info_s *gpio;
+    struct pxa2xx_lcdc_s *lcd;
+    struct pxa2xx_ssp_s **ssp;
+    struct pxa2xx_i2c_s *i2c[2];
+    struct pxa2xx_mmci_s *mmc;
+    struct pxa2xx_pcmcia_s *pcmcia[2];
+    struct pxa2xx_i2s_s *i2s;
+    struct pxa2xx_fir_s *fir;
+
+    /* Power management */
+    target_phys_addr_t pm_base;
+    uint32_t pm_regs[0x40];
+
+    /* Clock management */
+    target_phys_addr_t cm_base;
+    uint32_t cm_regs[4];
+    uint32_t clkcfg;
+
+    /* Memory management */
+    target_phys_addr_t mm_base;
+    uint32_t mm_regs[0x1a];
+
+    /* Performance monitoring */
+    uint32_t pmnc;
+
+    /* Real-Time clock */
+    target_phys_addr_t rtc_base;
+    uint32_t rttr;
+    uint32_t rtsr;
+    uint32_t rtar;
+    uint32_t rdar1;
+    uint32_t rdar2;
+    uint32_t ryar1;
+    uint32_t ryar2;
+    uint32_t swar1;
+    uint32_t swar2;
+    uint32_t piar;
+    uint32_t last_rcnr;
+    uint32_t last_rdcr;
+    uint32_t last_rycr;
+    uint32_t last_swcr;
+    uint32_t last_rtcpicr;
+    int64_t last_hz;
+    int64_t last_sw;
+    int64_t last_pi;
+    QEMUTimer *rtc_hz;
+    QEMUTimer *rtc_rdal1;
+    QEMUTimer *rtc_rdal2;
+    QEMUTimer *rtc_swal1;
+    QEMUTimer *rtc_swal2;
+    QEMUTimer *rtc_pi;
+};
+
+struct pxa2xx_i2s_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    struct pxa2xx_dma_state_s *dma;
+    void (*data_req)(void *, int, int);
+
+    uint32_t control[2];
+    uint32_t status;
+    uint32_t mask;
+    uint32_t clk;
+
+    int enable;
+    int rx_len;
+    int tx_len;
+    void (*codec_out)(void *, uint32_t);
+    uint32_t (*codec_in)(void *);
+    void *opaque;
+
+    int fifo_len;
+    uint32_t fifo[16];
+};
+
+# define PA_FMT			"0x%08lx"
+# define REG_FMT		"0x%lx"
+
+struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, DisplayState *ds,
+                const char *revision);
+struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, DisplayState *ds);
+
+void pxa2xx_reset(int line, int level, void *opaque);
+
+#endif	/* PXA_H */
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
new file mode 100644
index 0000000..6109fc1
--- /dev/null
+++ b/hw/pxa2xx.c
@@ -0,0 +1,2235 @@
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licenced under the GPL.
+ */
+
+# include "vl.h"
+
+static struct {
+    target_phys_addr_t io_base;
+    int irqn;
+} pxa255_serial[] = {
+    { 0x40100000, PXA2XX_PIC_FFUART },
+    { 0x40200000, PXA2XX_PIC_BTUART },
+    { 0x40700000, PXA2XX_PIC_STUART },
+    { 0x41600000, PXA25X_PIC_HWUART },
+    { 0, 0 }
+}, pxa270_serial[] = {
+    { 0x40100000, PXA2XX_PIC_FFUART },
+    { 0x40200000, PXA2XX_PIC_BTUART },
+    { 0x40700000, PXA2XX_PIC_STUART },
+    { 0, 0 }
+};
+
+static struct {
+    target_phys_addr_t io_base;
+    int irqn;
+} pxa250_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0, 0 }
+}, pxa255_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41400000, PXA25X_PIC_NSSP },
+    { 0, 0 }
+}, pxa26x_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41400000, PXA25X_PIC_NSSP },
+    { 0x41500000, PXA26X_PIC_ASSP },
+    { 0, 0 }
+}, pxa27x_ssp[] = {
+    { 0x41000000, PXA2XX_PIC_SSP },
+    { 0x41700000, PXA27X_PIC_SSP2 },
+    { 0x41900000, PXA2XX_PIC_SSP3 },
+    { 0, 0 }
+};
+
+#define PMCR	0x00	/* Power Manager Control register */
+#define PSSR	0x04	/* Power Manager Sleep Status register */
+#define PSPR	0x08	/* Power Manager Scratch-Pad register */
+#define PWER	0x0c	/* Power Manager Wake-Up Enable register */
+#define PRER	0x10	/* Power Manager Rising-Edge Detect Enable register */
+#define PFER	0x14	/* Power Manager Falling-Edge Detect Enable register */
+#define PEDR	0x18	/* Power Manager Edge-Detect Status register */
+#define PCFR	0x1c	/* Power Manager General Configuration register */
+#define PGSR0	0x20	/* Power Manager GPIO Sleep-State register 0 */
+#define PGSR1	0x24	/* Power Manager GPIO Sleep-State register 1 */
+#define PGSR2	0x28	/* Power Manager GPIO Sleep-State register 2 */
+#define PGSR3	0x2c	/* Power Manager GPIO Sleep-State register 3 */
+#define RCSR	0x30	/* Reset Controller Status register */
+#define PSLR	0x34	/* Power Manager Sleep Configuration register */
+#define PTSR	0x38	/* Power Manager Standby Configuration register */
+#define PVCR	0x40	/* Power Manager Voltage Change Control register */
+#define PUCR	0x4c	/* Power Manager USIM Card Control/Status register */
+#define PKWR	0x50	/* Power Manager Keyboard Wake-Up Enable register */
+#define PKSR	0x54	/* Power Manager Keyboard Level-Detect Status */
+#define PCMD0	0x80	/* Power Manager I2C Command register File 0 */
+#define PCMD31	0xfc	/* Power Manager I2C Command register File 31 */
+
+static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->pm_base;
+
+    switch (addr) {
+    case PMCR ... PCMD31:
+        if (addr & 3)
+            goto fail;
+
+        return s->pm_regs[addr >> 2];
+    default:
+    fail:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->pm_base;
+
+    switch (addr) {
+    case PMCR:
+        s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
+        s->pm_regs[addr >> 2] |= value & 0x15;
+        break;
+
+    case PSSR:	/* Read-clean registers */
+    case RCSR:
+    case PKSR:
+        s->pm_regs[addr >> 2] &= ~value;
+        break;
+
+    default:	/* Read-write registers */
+        if (addr >= PMCR && addr <= PCMD31 && !(addr & 3)) {
+            s->pm_regs[addr >> 2] = value;
+            break;
+        }
+
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_pm_readfn[] = {
+    pxa2xx_pm_read,
+    pxa2xx_pm_read,
+    pxa2xx_pm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pm_writefn[] = {
+    pxa2xx_pm_write,
+    pxa2xx_pm_write,
+    pxa2xx_pm_write,
+};
+
+static void pxa2xx_pm_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 0x40; i ++)
+        qemu_put_be32s(f, &s->pm_regs[i]);
+}
+
+static int pxa2xx_pm_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 0x40; i ++)
+        qemu_get_be32s(f, &s->pm_regs[i]);
+
+    return 0;
+}
+
+#define CCCR	0x00	/* Core Clock Configuration register */
+#define CKEN	0x04	/* Clock Enable register */
+#define OSCC	0x08	/* Oscillator Configuration register */
+#define CCSR	0x0c	/* Core Clock Status register */
+
+static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->cm_base;
+
+    switch (addr) {
+    case CCCR:
+    case CKEN:
+    case OSCC:
+        return s->cm_regs[addr >> 2];
+
+    case CCSR:
+        return s->cm_regs[CCCR >> 2] | (3 << 28);
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->cm_base;
+
+    switch (addr) {
+    case CCCR:
+    case CKEN:
+        s->cm_regs[addr >> 2] = value;
+        break;
+
+    case OSCC:
+        s->cm_regs[addr >> 2] &= ~0x6c;
+        s->cm_regs[addr >> 2] |= value & 0x6e;
+        if ((value >> 1) & 1)			/* OON */
+            s->cm_regs[addr >> 2] |= 1 << 0;	/* Oscillator is now stable */
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_cm_readfn[] = {
+    pxa2xx_cm_read,
+    pxa2xx_cm_read,
+    pxa2xx_cm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_cm_writefn[] = {
+    pxa2xx_cm_write,
+    pxa2xx_cm_write,
+    pxa2xx_cm_write,
+};
+
+static void pxa2xx_cm_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 4; i ++)
+        qemu_put_be32s(f, &s->cm_regs[i]);
+    qemu_put_be32s(f, &s->clkcfg);
+    qemu_put_be32s(f, &s->pmnc);
+}
+
+static int pxa2xx_cm_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 4; i ++)
+        qemu_get_be32s(f, &s->cm_regs[i]);
+    qemu_get_be32s(f, &s->clkcfg);
+    qemu_get_be32s(f, &s->pmnc);
+
+    return 0;
+}
+
+static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+    switch (reg) {
+    case 6:	/* Clock Configuration register */
+        return s->clkcfg;
+
+    case 7:	/* Power Mode register */
+        return 0;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    static const char *pwrmode[8] = {
+        "Normal", "Idle", "Deep-idle", "Standby",
+        "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
+    };
+
+    switch (reg) {
+    case 6:	/* Clock Configuration register */
+        s->clkcfg = value & 0xf;
+        if (value & 2)
+            printf("%s: CPU frequency change attempt\n", __FUNCTION__);
+        break;
+
+    case 7:	/* Power Mode register */
+        if (value & 8)
+            printf("%s: CPU voltage change attempt\n", __FUNCTION__);
+        switch (value & 7) {
+        case 0:
+            /* Do nothing */
+            break;
+
+        case 1:
+            /* Idle */
+            if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) {	/* CPDIS */
+                cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+                break;
+            }
+            /* Fall through.  */
+
+        case 2:
+            /* Deep-Idle */
+            cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+            s->pm_regs[RCSR >> 2] |= 0x8;	/* Set GPR */
+            goto message;
+
+        case 3:
+            s->env->uncached_cpsr =
+                    ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+            s->env->cp15.c1_sys = 0;
+            s->env->cp15.c1_coproc = 0;
+            s->env->cp15.c2_base = 0;
+            s->env->cp15.c3 = 0;
+            s->pm_regs[PSSR >> 2] |= 0x8;	/* Set STS */
+            s->pm_regs[RCSR >> 2] |= 0x8;	/* Set GPR */
+
+            /*
+             * The scratch-pad register is almost universally used
+             * for storing the return address on suspend.  For the
+             * lack of a resuming bootloader, perform a jump
+             * directly to that address.
+             */
+            memset(s->env->regs, 0, 4 * 15);
+            s->env->regs[15] = s->pm_regs[PSPR >> 2];
+
+#if 0
+            buffer = 0xe59ff000;	/* ldr     pc, [pc, #0] */
+            cpu_physical_memory_write(0, &buffer, 4);
+            buffer = s->pm_regs[PSPR >> 2];
+            cpu_physical_memory_write(8, &buffer, 4);
+#endif
+
+            /* Suspend */
+            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
+
+            goto message;
+
+        default:
+        message:
+            printf("%s: machine entered %s mode\n", __FUNCTION__,
+                            pwrmode[value & 7]);
+        }
+        break;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+/* Performace Monitoring Registers */
+#define CPPMNC		0	/* Performance Monitor Control register */
+#define CPCCNT		1	/* Clock Counter register */
+#define CPINTEN		4	/* Interrupt Enable register */
+#define CPFLAG		5	/* Overflow Flag register */
+#define CPEVTSEL	8	/* Event Selection register */
+
+#define CPPMN0		0	/* Performance Count register 0 */
+#define CPPMN1		1	/* Performance Count register 1 */
+#define CPPMN2		2	/* Performance Count register 2 */
+#define CPPMN3		3	/* Performance Count register 3 */
+
+static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+    switch (reg) {
+    case CPPMNC:
+        return s->pmnc;
+    case CPCCNT:
+        if (s->pmnc & 1)
+            return qemu_get_clock(vm_clock);
+        else
+            return 0;
+    case CPINTEN:
+    case CPFLAG:
+    case CPEVTSEL:
+        return 0;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_perf_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+    switch (reg) {
+    case CPPMNC:
+        s->pmnc = value;
+        break;
+
+    case CPCCNT:
+    case CPINTEN:
+    case CPFLAG:
+    case CPEVTSEL:
+        break;
+
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm)
+{
+    switch (crm) {
+    case 0:
+        return pxa2xx_clkpwr_read(opaque, op2, reg, crm);
+    case 1:
+        return pxa2xx_perf_read(opaque, op2, reg, crm);
+    case 2:
+        switch (reg) {
+        case CPPMN0:
+        case CPPMN1:
+        case CPPMN2:
+        case CPPMN3:
+            return 0;
+        }
+        /* Fall through */
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    switch (crm) {
+    case 0:
+        pxa2xx_clkpwr_write(opaque, op2, reg, crm, value);
+        break;
+    case 1:
+        pxa2xx_perf_write(opaque, op2, reg, crm, value);
+        break;
+    case 2:
+        switch (reg) {
+        case CPPMN0:
+        case CPPMN1:
+        case CPPMN2:
+        case CPPMN3:
+            return;
+        }
+        /* Fall through */
+    default:
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        break;
+    }
+}
+
+#define MDCNFG		0x00	/* SDRAM Configuration register */
+#define MDREFR		0x04	/* SDRAM Refresh Control register */
+#define MSC0		0x08	/* Static Memory Control register 0 */
+#define MSC1		0x0c	/* Static Memory Control register 1 */
+#define MSC2		0x10	/* Static Memory Control register 2 */
+#define MECR		0x14	/* Expansion Memory Bus Config register */
+#define SXCNFG		0x1c	/* Synchronous Static Memory Config register */
+#define MCMEM0		0x28	/* PC Card Memory Socket 0 Timing register */
+#define MCMEM1		0x2c	/* PC Card Memory Socket 1 Timing register */
+#define MCATT0		0x30	/* PC Card Attribute Socket 0 register */
+#define MCATT1		0x34	/* PC Card Attribute Socket 1 register */
+#define MCIO0		0x38	/* PC Card I/O Socket 0 Timing register */
+#define MCIO1		0x3c	/* PC Card I/O Socket 1 Timing register */
+#define MDMRS		0x40	/* SDRAM Mode Register Set Config register */
+#define BOOT_DEF	0x44	/* Boot-time Default Configuration register */
+#define ARB_CNTL	0x48	/* Arbiter Control register */
+#define BSCNTR0		0x4c	/* Memory Buffer Strength Control register 0 */
+#define BSCNTR1		0x50	/* Memory Buffer Strength Control register 1 */
+#define LCDBSCNTR	0x54	/* LCD Buffer Strength Control register */
+#define MDMRSLP		0x58	/* Low Power SDRAM Mode Set Config register */
+#define BSCNTR2		0x5c	/* Memory Buffer Strength Control register 2 */
+#define BSCNTR3		0x60	/* Memory Buffer Strength Control register 3 */
+#define SA1110		0x64	/* SA-1110 Memory Compatibility register */
+
+static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->mm_base;
+
+    switch (addr) {
+    case MDCNFG ... SA1110:
+        if ((addr & 3) == 0)
+            return s->mm_regs[addr >> 2];
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->mm_base;
+
+    switch (addr) {
+    case MDCNFG ... SA1110:
+        if ((addr & 3) == 0) {
+            s->mm_regs[addr >> 2] = value;
+            break;
+        }
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_mm_readfn[] = {
+    pxa2xx_mm_read,
+    pxa2xx_mm_read,
+    pxa2xx_mm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_mm_writefn[] = {
+    pxa2xx_mm_write,
+    pxa2xx_mm_write,
+    pxa2xx_mm_write,
+};
+
+static void pxa2xx_mm_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 0x1a; i ++)
+        qemu_put_be32s(f, &s->mm_regs[i]);
+}
+
+static int pxa2xx_mm_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 0x1a; i ++)
+        qemu_get_be32s(f, &s->mm_regs[i]);
+
+    return 0;
+}
+
+/* Synchronous Serial Ports */
+struct pxa2xx_ssp_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    int enable;
+
+    uint32_t sscr[2];
+    uint32_t sspsp;
+    uint32_t ssto;
+    uint32_t ssitr;
+    uint32_t sssr;
+    uint8_t sstsa;
+    uint8_t ssrsa;
+    uint8_t ssacd;
+
+    uint32_t rx_fifo[16];
+    int rx_level;
+    int rx_start;
+
+    uint32_t (*readfn)(void *opaque);
+    void (*writefn)(void *opaque, uint32_t value);
+    void *opaque;
+};
+
+#define SSCR0	0x00	/* SSP Control register 0 */
+#define SSCR1	0x04	/* SSP Control register 1 */
+#define SSSR	0x08	/* SSP Status register */
+#define SSITR	0x0c	/* SSP Interrupt Test register */
+#define SSDR	0x10	/* SSP Data register */
+#define SSTO	0x28	/* SSP Time-Out register */
+#define SSPSP	0x2c	/* SSP Programmable Serial Protocol register */
+#define SSTSA	0x30	/* SSP TX Time Slot Active register */
+#define SSRSA	0x34	/* SSP RX Time Slot Active register */
+#define SSTSS	0x38	/* SSP Time Slot Status register */
+#define SSACD	0x3c	/* SSP Audio Clock Divider register */
+
+/* Bitfields for above registers */
+#define SSCR0_SPI(x)	(((x) & 0x30) == 0x00)
+#define SSCR0_SSP(x)	(((x) & 0x30) == 0x10)
+#define SSCR0_UWIRE(x)	(((x) & 0x30) == 0x20)
+#define SSCR0_PSP(x)	(((x) & 0x30) == 0x30)
+#define SSCR0_SSE	(1 << 7)
+#define SSCR0_RIM	(1 << 22)
+#define SSCR0_TIM	(1 << 23)
+#define SSCR0_MOD	(1 << 31)
+#define SSCR0_DSS(x)	(((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
+#define SSCR1_RIE	(1 << 0)
+#define SSCR1_TIE	(1 << 1)
+#define SSCR1_LBM	(1 << 2)
+#define SSCR1_MWDS	(1 << 5)
+#define SSCR1_TFT(x)	((((x) >> 6) & 0xf) + 1)
+#define SSCR1_RFT(x)	((((x) >> 10) & 0xf) + 1)
+#define SSCR1_EFWR	(1 << 14)
+#define SSCR1_PINTE	(1 << 18)
+#define SSCR1_TINTE	(1 << 19)
+#define SSCR1_RSRE	(1 << 20)
+#define SSCR1_TSRE	(1 << 21)
+#define SSCR1_EBCEI	(1 << 29)
+#define SSITR_INT	(7 << 5)
+#define SSSR_TNF	(1 << 2)
+#define SSSR_RNE	(1 << 3)
+#define SSSR_TFS	(1 << 5)
+#define SSSR_RFS	(1 << 6)
+#define SSSR_ROR	(1 << 7)
+#define SSSR_PINT	(1 << 18)
+#define SSSR_TINT	(1 << 19)
+#define SSSR_EOC	(1 << 20)
+#define SSSR_TUR	(1 << 21)
+#define SSSR_BCE	(1 << 23)
+#define SSSR_RW		0x00bc0080
+
+static void pxa2xx_ssp_int_update(struct pxa2xx_ssp_s *s)
+{
+    int level = 0;
+
+    level |= s->ssitr & SSITR_INT;
+    level |= (s->sssr & SSSR_BCE)  &&  (s->sscr[1] & SSCR1_EBCEI);
+    level |= (s->sssr & SSSR_TUR)  && !(s->sscr[0] & SSCR0_TIM);
+    level |= (s->sssr & SSSR_EOC)  &&  (s->sssr & (SSSR_TINT | SSSR_PINT));
+    level |= (s->sssr & SSSR_TINT) &&  (s->sscr[1] & SSCR1_TINTE);
+    level |= (s->sssr & SSSR_PINT) &&  (s->sscr[1] & SSCR1_PINTE);
+    level |= (s->sssr & SSSR_ROR)  && !(s->sscr[0] & SSCR0_RIM);
+    level |= (s->sssr & SSSR_RFS)  &&  (s->sscr[1] & SSCR1_RIE);
+    level |= (s->sssr & SSSR_TFS)  &&  (s->sscr[1] & SSCR1_TIE);
+    qemu_set_irq(s->irq, !!level);
+}
+
+static void pxa2xx_ssp_fifo_update(struct pxa2xx_ssp_s *s)
+{
+    s->sssr &= ~(0xf << 12);	/* Clear RFL */
+    s->sssr &= ~(0xf << 8);	/* Clear TFL */
+    s->sssr &= ~SSSR_TNF;
+    if (s->enable) {
+        s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
+        if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
+            s->sssr |= SSSR_RFS;
+        else
+            s->sssr &= ~SSSR_RFS;
+        if (0 <= SSCR1_TFT(s->sscr[1]))
+            s->sssr |= SSSR_TFS;
+        else
+            s->sssr &= ~SSSR_TFS;
+        if (s->rx_level)
+            s->sssr |= SSSR_RNE;
+        else
+            s->sssr &= ~SSSR_RNE;
+        s->sssr |= SSSR_TNF;
+    }
+
+    pxa2xx_ssp_int_update(s);
+}
+
+static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
+    uint32_t retval;
+    addr -= s->base;
+
+    switch (addr) {
+    case SSCR0:
+        return s->sscr[0];
+    case SSCR1:
+        return s->sscr[1];
+    case SSPSP:
+        return s->sspsp;
+    case SSTO:
+        return s->ssto;
+    case SSITR:
+        return s->ssitr;
+    case SSSR:
+        return s->sssr | s->ssitr;
+    case SSDR:
+        if (!s->enable)
+            return 0xffffffff;
+        if (s->rx_level < 1) {
+            printf("%s: SSP Rx Underrun\n", __FUNCTION__);
+            return 0xffffffff;
+        }
+        s->rx_level --;
+        retval = s->rx_fifo[s->rx_start ++];
+        s->rx_start &= 0xf;
+        pxa2xx_ssp_fifo_update(s);
+        return retval;
+    case SSTSA:
+        return s->sstsa;
+    case SSRSA:
+        return s->ssrsa;
+    case SSTSS:
+        return 0;
+    case SSACD:
+        return s->ssacd;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
+    addr -= s->base;
+
+    switch (addr) {
+    case SSCR0:
+        s->sscr[0] = value & 0xc7ffffff;
+        s->enable = value & SSCR0_SSE;
+        if (value & SSCR0_MOD)
+            printf("%s: Attempt to use network mode\n", __FUNCTION__);
+        if (s->enable && SSCR0_DSS(value) < 4)
+            printf("%s: Wrong data size: %i bits\n", __FUNCTION__,
+                            SSCR0_DSS(value));
+        if (!(value & SSCR0_SSE)) {
+            s->sssr = 0;
+            s->ssitr = 0;
+            s->rx_level = 0;
+        }
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSCR1:
+        s->sscr[1] = value;
+        if (value & (SSCR1_LBM | SSCR1_EFWR))
+            printf("%s: Attempt to use SSP test mode\n", __FUNCTION__);
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSPSP:
+        s->sspsp = value;
+        break;
+
+    case SSTO:
+        s->ssto = value;
+        break;
+
+    case SSITR:
+        s->ssitr = value & SSITR_INT;
+        pxa2xx_ssp_int_update(s);
+        break;
+
+    case SSSR:
+        s->sssr &= ~(value & SSSR_RW);
+        pxa2xx_ssp_int_update(s);
+        break;
+
+    case SSDR:
+        if (SSCR0_UWIRE(s->sscr[0])) {
+            if (s->sscr[1] & SSCR1_MWDS)
+                value &= 0xffff;
+            else
+                value &= 0xff;
+        } else
+            /* Note how 32bits overflow does no harm here */
+            value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
+
+        /* Data goes from here to the Tx FIFO and is shifted out from
+         * there directly to the slave, no need to buffer it.
+         */
+        if (s->enable) {
+            if (s->writefn)
+                s->writefn(s->opaque, value);
+
+            if (s->rx_level < 0x10) {
+                if (s->readfn)
+                    s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] =
+                            s->readfn(s->opaque);
+                else
+                    s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = 0x0;
+            } else
+                s->sssr |= SSSR_ROR;
+        }
+        pxa2xx_ssp_fifo_update(s);
+        break;
+
+    case SSTSA:
+        s->sstsa = value;
+        break;
+
+    case SSRSA:
+        s->ssrsa = value;
+        break;
+
+    case SSACD:
+        s->ssacd = value;
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+}
+
+void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
+                uint32_t (*readfn)(void *opaque),
+                void (*writefn)(void *opaque, uint32_t value), void *opaque)
+{
+    if (!port) {
+        printf("%s: no such SSP\n", __FUNCTION__);
+        exit(-1);
+    }
+
+    port->opaque = opaque;
+    port->readfn = readfn;
+    port->writefn = writefn;
+}
+
+static CPUReadMemoryFunc *pxa2xx_ssp_readfn[] = {
+    pxa2xx_ssp_read,
+    pxa2xx_ssp_read,
+    pxa2xx_ssp_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_ssp_writefn[] = {
+    pxa2xx_ssp_write,
+    pxa2xx_ssp_write,
+    pxa2xx_ssp_write,
+};
+
+static void pxa2xx_ssp_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
+    int i;
+
+    qemu_put_be32(f, s->enable);
+
+    qemu_put_be32s(f, &s->sscr[0]);
+    qemu_put_be32s(f, &s->sscr[1]);
+    qemu_put_be32s(f, &s->sspsp);
+    qemu_put_be32s(f, &s->ssto);
+    qemu_put_be32s(f, &s->ssitr);
+    qemu_put_be32s(f, &s->sssr);
+    qemu_put_8s(f, &s->sstsa);
+    qemu_put_8s(f, &s->ssrsa);
+    qemu_put_8s(f, &s->ssacd);
+
+    qemu_put_byte(f, s->rx_level);
+    for (i = 0; i < s->rx_level; i ++)
+        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 0xf]);
+}
+
+static int pxa2xx_ssp_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
+    int i;
+
+    s->enable = qemu_get_be32(f);
+
+    qemu_get_be32s(f, &s->sscr[0]);
+    qemu_get_be32s(f, &s->sscr[1]);
+    qemu_get_be32s(f, &s->sspsp);
+    qemu_get_be32s(f, &s->ssto);
+    qemu_get_be32s(f, &s->ssitr);
+    qemu_get_be32s(f, &s->sssr);
+    qemu_get_8s(f, &s->sstsa);
+    qemu_get_8s(f, &s->ssrsa);
+    qemu_get_8s(f, &s->ssacd);
+
+    s->rx_level = qemu_get_byte(f);
+    s->rx_start = 0;
+    for (i = 0; i < s->rx_level; i ++)
+        s->rx_fifo[i] = qemu_get_byte(f);
+
+    return 0;
+}
+
+/* Real-Time Clock */
+#define RCNR		0x00	/* RTC Counter register */
+#define RTAR		0x04	/* RTC Alarm register */
+#define RTSR		0x08	/* RTC Status register */
+#define RTTR		0x0c	/* RTC Timer Trim register */
+#define RDCR		0x10	/* RTC Day Counter register */
+#define RYCR		0x14	/* RTC Year Counter register */
+#define RDAR1		0x18	/* RTC Wristwatch Day Alarm register 1 */
+#define RYAR1		0x1c	/* RTC Wristwatch Year Alarm register 1 */
+#define RDAR2		0x20	/* RTC Wristwatch Day Alarm register 2 */
+#define RYAR2		0x24	/* RTC Wristwatch Year Alarm register 2 */
+#define SWCR		0x28	/* RTC Stopwatch Counter register */
+#define SWAR1		0x2c	/* RTC Stopwatch Alarm register 1 */
+#define SWAR2		0x30	/* RTC Stopwatch Alarm register 2 */
+#define RTCPICR		0x34	/* RTC Periodic Interrupt Counter register */
+#define PIAR		0x38	/* RTC Periodic Interrupt Alarm register */
+
+static inline void pxa2xx_rtc_int_update(struct pxa2xx_state_s *s)
+{
+    qemu_set_irq(s->pic[PXA2XX_PIC_RTCALARM], !!(s->rtsr & 0x2553));
+}
+
+static void pxa2xx_rtc_hzupdate(struct pxa2xx_state_s *s)
+{
+    int64_t rt = qemu_get_clock(rt_clock);
+    s->last_rcnr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_rdcr += ((rt - s->last_hz) << 15) /
+            (1000 * ((s->rttr & 0xffff) + 1));
+    s->last_hz = rt;
+}
+
+static void pxa2xx_rtc_swupdate(struct pxa2xx_state_s *s)
+{
+    int64_t rt = qemu_get_clock(rt_clock);
+    if (s->rtsr & (1 << 12))
+        s->last_swcr += (rt - s->last_sw) / 10;
+    s->last_sw = rt;
+}
+
+static void pxa2xx_rtc_piupdate(struct pxa2xx_state_s *s)
+{
+    int64_t rt = qemu_get_clock(rt_clock);
+    if (s->rtsr & (1 << 15))
+        s->last_swcr += rt - s->last_pi;
+    s->last_pi = rt;
+}
+
+static inline void pxa2xx_rtc_alarm_update(struct pxa2xx_state_s *s,
+                uint32_t rtsr)
+{
+    if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
+        qemu_mod_timer(s->rtc_hz, s->last_hz +
+                (((s->rtar - s->last_rcnr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15));
+    else
+        qemu_del_timer(s->rtc_hz);
+
+    if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
+        qemu_mod_timer(s->rtc_rdal1, s->last_hz +
+                (((s->rdar1 - s->last_rdcr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_rdal1);
+
+    if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
+        qemu_mod_timer(s->rtc_rdal2, s->last_hz +
+                (((s->rdar2 - s->last_rdcr) * 1000 *
+                  ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_rdal2);
+
+    if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
+        qemu_mod_timer(s->rtc_swal1, s->last_sw +
+                        (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_swal1);
+
+    if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
+        qemu_mod_timer(s->rtc_swal2, s->last_sw +
+                        (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
+    else
+        qemu_del_timer(s->rtc_swal2);
+
+    if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
+        qemu_mod_timer(s->rtc_pi, s->last_pi +
+                        (s->piar & 0xffff) - s->last_rtcpicr);
+    else
+        qemu_del_timer(s->rtc_pi);
+}
+
+static inline void pxa2xx_rtc_hz_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 0);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 4);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 6);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_swal1_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 8);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_swal2_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 10);
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_pi_tick(void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    s->rtsr |= (1 << 13);
+    pxa2xx_rtc_piupdate(s);
+    s->last_rtcpicr = 0;
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+    pxa2xx_rtc_int_update(s);
+}
+
+static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->rtc_base;
+
+    switch (addr) {
+    case RTTR:
+        return s->rttr;
+    case RTSR:
+        return s->rtsr;
+    case RTAR:
+        return s->rtar;
+    case RDAR1:
+        return s->rdar1;
+    case RDAR2:
+        return s->rdar2;
+    case RYAR1:
+        return s->ryar1;
+    case RYAR2:
+        return s->ryar2;
+    case SWAR1:
+        return s->swar1;
+    case SWAR2:
+        return s->swar2;
+    case PIAR:
+        return s->piar;
+    case RCNR:
+        return s->last_rcnr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    case RDCR:
+        return s->last_rdcr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
+                (1000 * ((s->rttr & 0xffff) + 1));
+    case RYCR:
+        return s->last_rycr;
+    case SWCR:
+        if (s->rtsr & (1 << 12))
+            return s->last_swcr + (qemu_get_clock(rt_clock) - s->last_sw) / 10;
+        else
+            return s->last_swcr;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    addr -= s->rtc_base;
+
+    switch (addr) {
+    case RTTR:
+        if (!(s->rttr & (1 << 31))) {
+            pxa2xx_rtc_hzupdate(s);
+            s->rttr = value;
+            pxa2xx_rtc_alarm_update(s, s->rtsr);
+        }
+        break;
+
+    case RTSR:
+        if ((s->rtsr ^ value) & (1 << 15))
+            pxa2xx_rtc_piupdate(s);
+
+        if ((s->rtsr ^ value) & (1 << 12))
+            pxa2xx_rtc_swupdate(s);
+
+        if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
+            pxa2xx_rtc_alarm_update(s, value);
+
+        s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
+        pxa2xx_rtc_int_update(s);
+        break;
+
+    case RTAR:
+        s->rtar = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDAR1:
+        s->rdar1 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDAR2:
+        s->rdar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYAR1:
+        s->ryar1 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYAR2:
+        s->ryar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case SWAR1:
+        pxa2xx_rtc_swupdate(s);
+        s->swar1 = value;
+        s->last_swcr = 0;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case SWAR2:
+        s->swar2 = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case PIAR:
+        s->piar = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RCNR:
+        pxa2xx_rtc_hzupdate(s);
+        s->last_rcnr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RDCR:
+        pxa2xx_rtc_hzupdate(s);
+        s->last_rdcr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RYCR:
+        s->last_rycr = value;
+        break;
+
+    case SWCR:
+        pxa2xx_rtc_swupdate(s);
+        s->last_swcr = value;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    case RTCPICR:
+        pxa2xx_rtc_piupdate(s);
+        s->last_rtcpicr = value & 0xffff;
+        pxa2xx_rtc_alarm_update(s, s->rtsr);
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_rtc_readfn[] = {
+    pxa2xx_rtc_read,
+    pxa2xx_rtc_read,
+    pxa2xx_rtc_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = {
+    pxa2xx_rtc_write,
+    pxa2xx_rtc_write,
+    pxa2xx_rtc_write,
+};
+
+static void pxa2xx_rtc_init(struct pxa2xx_state_s *s)
+{
+    struct tm *tm;
+    time_t ti;
+    int wom;
+
+    s->rttr = 0x7fff;
+    s->rtsr = 0;
+
+    time(&ti);
+    if (rtc_utc)
+        tm = gmtime(&ti);
+    else
+        tm = localtime(&ti);
+    wom = ((tm->tm_mday - 1) / 7) + 1;
+
+    s->last_rcnr = (uint32_t) ti;
+    s->last_rdcr = (wom << 20) | ((tm->tm_wday + 1) << 17) |
+            (tm->tm_hour << 12) | (tm->tm_min << 6) | tm->tm_sec;
+    s->last_rycr = ((tm->tm_year + 1900) << 9) |
+            ((tm->tm_mon + 1) << 5) | tm->tm_mday;
+    s->last_swcr = (tm->tm_hour << 19) |
+            (tm->tm_min << 13) | (tm->tm_sec << 7);
+    s->last_rtcpicr = 0;
+    s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock);
+
+    s->rtc_hz    = qemu_new_timer(rt_clock, pxa2xx_rtc_hz_tick,    s);
+    s->rtc_rdal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal1_tick, s);
+    s->rtc_rdal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal2_tick, s);
+    s->rtc_swal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal1_tick, s);
+    s->rtc_swal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal2_tick, s);
+    s->rtc_pi    = qemu_new_timer(rt_clock, pxa2xx_rtc_pi_tick,    s);
+}
+
+static void pxa2xx_rtc_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+    pxa2xx_rtc_hzupdate(s);
+    pxa2xx_rtc_piupdate(s);
+    pxa2xx_rtc_swupdate(s);
+
+    qemu_put_be32s(f, &s->rttr);
+    qemu_put_be32s(f, &s->rtsr);
+    qemu_put_be32s(f, &s->rtar);
+    qemu_put_be32s(f, &s->rdar1);
+    qemu_put_be32s(f, &s->rdar2);
+    qemu_put_be32s(f, &s->ryar1);
+    qemu_put_be32s(f, &s->ryar2);
+    qemu_put_be32s(f, &s->swar1);
+    qemu_put_be32s(f, &s->swar2);
+    qemu_put_be32s(f, &s->piar);
+    qemu_put_be32s(f, &s->last_rcnr);
+    qemu_put_be32s(f, &s->last_rdcr);
+    qemu_put_be32s(f, &s->last_rycr);
+    qemu_put_be32s(f, &s->last_swcr);
+    qemu_put_be32s(f, &s->last_rtcpicr);
+    qemu_put_be64s(f, &s->last_hz);
+    qemu_put_be64s(f, &s->last_sw);
+    qemu_put_be64s(f, &s->last_pi);
+}
+
+static int pxa2xx_rtc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+    qemu_get_be32s(f, &s->rttr);
+    qemu_get_be32s(f, &s->rtsr);
+    qemu_get_be32s(f, &s->rtar);
+    qemu_get_be32s(f, &s->rdar1);
+    qemu_get_be32s(f, &s->rdar2);
+    qemu_get_be32s(f, &s->ryar1);
+    qemu_get_be32s(f, &s->ryar2);
+    qemu_get_be32s(f, &s->swar1);
+    qemu_get_be32s(f, &s->swar2);
+    qemu_get_be32s(f, &s->piar);
+    qemu_get_be32s(f, &s->last_rcnr);
+    qemu_get_be32s(f, &s->last_rdcr);
+    qemu_get_be32s(f, &s->last_rycr);
+    qemu_get_be32s(f, &s->last_swcr);
+    qemu_get_be32s(f, &s->last_rtcpicr);
+    qemu_get_be64s(f, &s->last_hz);
+    qemu_get_be64s(f, &s->last_sw);
+    qemu_get_be64s(f, &s->last_pi);
+
+    pxa2xx_rtc_alarm_update(s, s->rtsr);
+
+    return 0;
+}
+
+/* I2C Interface */
+struct pxa2xx_i2c_s {
+    i2c_slave slave;
+    i2c_bus *bus;
+    target_phys_addr_t base;
+    qemu_irq irq;
+
+    uint16_t control;
+    uint16_t status;
+    uint8_t ibmr;
+    uint8_t data;
+};
+
+#define IBMR	0x80	/* I2C Bus Monitor register */
+#define IDBR	0x88	/* I2C Data Buffer register */
+#define ICR	0x90	/* I2C Control register */
+#define ISR	0x98	/* I2C Status register */
+#define ISAR	0xa0	/* I2C Slave Address register */
+
+static void pxa2xx_i2c_update(struct pxa2xx_i2c_s *s)
+{
+    uint16_t level = 0;
+    level |= s->status & s->control & (1 << 10);		/* BED */
+    level |= (s->status & (1 << 7)) && (s->control & (1 << 9));	/* IRF */
+    level |= (s->status & (1 << 6)) && (s->control & (1 << 8));	/* ITE */
+    level |= s->status & (1 << 9);				/* SAD */
+    qemu_set_irq(s->irq, !!level);
+}
+
+/* These are only stubs now.  */
+static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c;
+
+    switch (event) {
+    case I2C_START_SEND:
+        s->status |= (1 << 9);				/* set SAD */
+        s->status &= ~(1 << 0);				/* clear RWM */
+        break;
+    case I2C_START_RECV:
+        s->status |= (1 << 9);				/* set SAD */
+        s->status |= 1 << 0;				/* set RWM */
+        break;
+    case I2C_FINISH:
+        s->status |= (1 << 4);				/* set SSD */
+        break;
+    case I2C_NACK:
+        s->status |= 1 << 1;				/* set ACKNAK */
+        break;
+    }
+    pxa2xx_i2c_update(s);
+}
+
+static int pxa2xx_i2c_rx(i2c_slave *i2c)
+{
+    struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c;
+    if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
+        return 0;
+
+    if (s->status & (1 << 0)) {			/* RWM */
+        s->status |= 1 << 6;			/* set ITE */
+    }
+    pxa2xx_i2c_update(s);
+
+    return s->data;
+}
+
+static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data)
+{
+    struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c;
+    if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
+        return 1;
+
+    if (!(s->status & (1 << 0))) {		/* RWM */
+        s->status |= 1 << 7;			/* set IRF */
+        s->data = data;
+    }
+    pxa2xx_i2c_update(s);
+
+    return 1;
+}
+
+static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
+    addr -= s->base;
+
+    switch (addr) {
+    case ICR:
+        return s->control;
+    case ISR:
+        return s->status | (i2c_bus_busy(s->bus) << 2);
+    case ISAR:
+        return s->slave.address;
+    case IDBR:
+        return s->data;
+    case IBMR:
+        if (s->status & (1 << 2))
+            s->ibmr ^= 3;	/* Fake SCL and SDA pin changes */
+        else
+            s->ibmr = 0;
+        return s->ibmr;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
+    int ack;
+    addr -= s->base;
+
+    switch (addr) {
+    case ICR:
+        s->control = value & 0xfff7;
+        if ((value & (1 << 3)) && (value & (1 << 6))) {	/* TB and IUE */
+            /* TODO: slave mode */
+            if (value & (1 << 0)) {			/* START condition */
+                if (s->data & 1)
+                    s->status |= 1 << 0;		/* set RWM */
+                else
+                    s->status &= ~(1 << 0);		/* clear RWM */
+                ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1);
+            } else {
+                if (s->status & (1 << 0)) {		/* RWM */
+                    s->data = i2c_recv(s->bus);
+                    if (value & (1 << 2))		/* ACKNAK */
+                        i2c_nack(s->bus);
+                    ack = 1;
+                } else
+                    ack = !i2c_send(s->bus, s->data);
+            }
+
+            if (value & (1 << 1))			/* STOP condition */
+                i2c_end_transfer(s->bus);
+
+            if (ack) {
+                if (value & (1 << 0))			/* START condition */
+                    s->status |= 1 << 6;		/* set ITE */
+                else
+                    if (s->status & (1 << 0))		/* RWM */
+                        s->status |= 1 << 7;		/* set IRF */
+                    else
+                        s->status |= 1 << 6;		/* set ITE */
+                s->status &= ~(1 << 1);			/* clear ACKNAK */
+            } else {
+                s->status |= 1 << 6;			/* set ITE */
+                s->status |= 1 << 10;			/* set BED */
+                s->status |= 1 << 1;			/* set ACKNAK */
+            }
+        }
+        if (!(value & (1 << 3)) && (value & (1 << 6)))	/* !TB and IUE */
+            if (value & (1 << 4))			/* MA */
+                i2c_end_transfer(s->bus);
+        pxa2xx_i2c_update(s);
+        break;
+
+    case ISR:
+        s->status &= ~(value & 0x07f0);
+        pxa2xx_i2c_update(s);
+        break;
+
+    case ISAR:
+        i2c_set_slave_address(&s->slave, value & 0x7f);
+        break;
+
+    case IDBR:
+        s->data = value & 0xff;
+        break;
+
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_i2c_readfn[] = {
+    pxa2xx_i2c_read,
+    pxa2xx_i2c_read,
+    pxa2xx_i2c_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_i2c_writefn[] = {
+    pxa2xx_i2c_write,
+    pxa2xx_i2c_write,
+    pxa2xx_i2c_write,
+};
+
+static void pxa2xx_i2c_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
+
+    qemu_put_be16s(f, &s->control);
+    qemu_put_be16s(f, &s->status);
+    qemu_put_8s(f, &s->ibmr);
+    qemu_put_8s(f, &s->data);
+
+    i2c_bus_save(f, s->bus);
+    i2c_slave_save(f, &s->slave);
+}
+
+static int pxa2xx_i2c_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
+
+    qemu_get_be16s(f, &s->control);
+    qemu_get_be16s(f, &s->status);
+    qemu_get_8s(f, &s->ibmr);
+    qemu_get_8s(f, &s->data);
+
+    i2c_bus_load(f, s->bus);
+    i2c_slave_load(f, &s->slave);
+    return 0;
+}
+
+struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base,
+                qemu_irq irq, uint32_t page_size)
+{
+    int iomemtype;
+    struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *)
+            i2c_slave_init(i2c_init_bus(), 0, sizeof(struct pxa2xx_i2c_s));
+
+    s->base = base;
+    s->irq = irq;
+    s->slave.event = pxa2xx_i2c_event;
+    s->slave.recv = pxa2xx_i2c_rx;
+    s->slave.send = pxa2xx_i2c_tx;
+    s->bus = i2c_init_bus();
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn,
+                    pxa2xx_i2c_writefn, s);
+    cpu_register_physical_memory(s->base & ~page_size, page_size, iomemtype);
+
+    register_savevm("pxa2xx_i2c", base, 0,
+                    pxa2xx_i2c_save, pxa2xx_i2c_load, s);
+
+    return s;
+}
+
+i2c_bus *pxa2xx_i2c_bus(struct pxa2xx_i2c_s *s)
+{
+    return s->bus;
+}
+
+/* PXA Inter-IC Sound Controller */
+static void pxa2xx_i2s_reset(struct pxa2xx_i2s_s *i2s)
+{
+    i2s->rx_len = 0;
+    i2s->tx_len = 0;
+    i2s->fifo_len = 0;
+    i2s->clk = 0x1a;
+    i2s->control[0] = 0x00;
+    i2s->control[1] = 0x00;
+    i2s->status = 0x00;
+    i2s->mask = 0x00;
+}
+
+#define SACR_TFTH(val)	((val >> 8) & 0xf)
+#define SACR_RFTH(val)	((val >> 12) & 0xf)
+#define SACR_DREC(val)	(val & (1 << 3))
+#define SACR_DPRL(val)	(val & (1 << 4))
+
+static inline void pxa2xx_i2s_update(struct pxa2xx_i2s_s *i2s)
+{
+    int rfs, tfs;
+    rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
+            !SACR_DREC(i2s->control[1]);
+    tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
+            i2s->enable && !SACR_DPRL(i2s->control[1]);
+
+    pxa2xx_dma_request(i2s->dma, PXA2XX_RX_RQ_I2S, rfs);
+    pxa2xx_dma_request(i2s->dma, PXA2XX_TX_RQ_I2S, tfs);
+
+    i2s->status &= 0xe0;
+    if (i2s->fifo_len < 16 || !i2s->enable)
+        i2s->status |= 1 << 0;			/* TNF */
+    if (i2s->rx_len)
+        i2s->status |= 1 << 1;			/* RNE */
+    if (i2s->enable)
+        i2s->status |= 1 << 2;			/* BSY */
+    if (tfs)
+        i2s->status |= 1 << 3;			/* TFS */
+    if (rfs)
+        i2s->status |= 1 << 4;			/* RFS */
+    if (!(i2s->tx_len && i2s->enable))
+        i2s->status |= i2s->fifo_len << 8;	/* TFL */
+    i2s->status |= MAX(i2s->rx_len, 0xf) << 12;	/* RFL */
+
+    qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
+}
+
+#define SACR0	0x00	/* Serial Audio Global Control register */
+#define SACR1	0x04	/* Serial Audio I2S/MSB-Justified Control register */
+#define SASR0	0x0c	/* Serial Audio Interface and FIFO Status register */
+#define SAIMR	0x14	/* Serial Audio Interrupt Mask register */
+#define SAICR	0x18	/* Serial Audio Interrupt Clear register */
+#define SADIV	0x60	/* Serial Audio Clock Divider register */
+#define SADR	0x80	/* Serial Audio Data register */
+
+static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+    addr -= s->base;
+
+    switch (addr) {
+    case SACR0:
+        return s->control[0];
+    case SACR1:
+        return s->control[1];
+    case SASR0:
+        return s->status;
+    case SAIMR:
+        return s->mask;
+    case SAICR:
+        return 0;
+    case SADIV:
+        return s->clk;
+    case SADR:
+        if (s->rx_len > 0) {
+            s->rx_len --;
+            pxa2xx_i2s_update(s);
+            return s->codec_in(s->opaque);
+        }
+        return 0;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+    uint32_t *sample;
+    addr -= s->base;
+
+    switch (addr) {
+    case SACR0:
+        if (value & (1 << 3))				/* RST */
+            pxa2xx_i2s_reset(s);
+        s->control[0] = value & 0xff3d;
+        if (!s->enable && (value & 1) && s->tx_len) {	/* ENB */
+            for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
+                s->codec_out(s->opaque, *sample);
+            s->status &= ~(1 << 7);			/* I2SOFF */
+        }
+        if (value & (1 << 4))				/* EFWR */
+            printf("%s: Attempt to use special function\n", __FUNCTION__);
+        s->enable = ((value ^ 4) & 5) == 5;		/* ENB && !RST*/
+        pxa2xx_i2s_update(s);
+        break;
+    case SACR1:
+        s->control[1] = value & 0x0039;
+        if (value & (1 << 5))				/* ENLBF */
+            printf("%s: Attempt to use loopback function\n", __FUNCTION__);
+        if (value & (1 << 4))				/* DPRL */
+            s->fifo_len = 0;
+        pxa2xx_i2s_update(s);
+        break;
+    case SAIMR:
+        s->mask = value & 0x0078;
+        pxa2xx_i2s_update(s);
+        break;
+    case SAICR:
+        s->status &= ~(value & (3 << 5));
+        pxa2xx_i2s_update(s);
+        break;
+    case SADIV:
+        s->clk = value & 0x007f;
+        break;
+    case SADR:
+        if (s->tx_len && s->enable) {
+            s->tx_len --;
+            pxa2xx_i2s_update(s);
+            s->codec_out(s->opaque, value);
+        } else if (s->fifo_len < 16) {
+            s->fifo[s->fifo_len ++] = value;
+            pxa2xx_i2s_update(s);
+        }
+        break;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_i2s_readfn[] = {
+    pxa2xx_i2s_read,
+    pxa2xx_i2s_read,
+    pxa2xx_i2s_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_i2s_writefn[] = {
+    pxa2xx_i2s_write,
+    pxa2xx_i2s_write,
+    pxa2xx_i2s_write,
+};
+
+static void pxa2xx_i2s_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+
+    qemu_put_be32s(f, &s->control[0]);
+    qemu_put_be32s(f, &s->control[1]);
+    qemu_put_be32s(f, &s->status);
+    qemu_put_be32s(f, &s->mask);
+    qemu_put_be32s(f, &s->clk);
+
+    qemu_put_be32(f, s->enable);
+    qemu_put_be32(f, s->rx_len);
+    qemu_put_be32(f, s->tx_len);
+    qemu_put_be32(f, s->fifo_len);
+}
+
+static int pxa2xx_i2s_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+
+    qemu_get_be32s(f, &s->control[0]);
+    qemu_get_be32s(f, &s->control[1]);
+    qemu_get_be32s(f, &s->status);
+    qemu_get_be32s(f, &s->mask);
+    qemu_get_be32s(f, &s->clk);
+
+    s->enable = qemu_get_be32(f);
+    s->rx_len = qemu_get_be32(f);
+    s->tx_len = qemu_get_be32(f);
+    s->fifo_len = qemu_get_be32(f);
+
+    return 0;
+}
+
+static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
+{
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+    uint32_t *sample;
+
+    /* Signal FIFO errors */
+    if (s->enable && s->tx_len)
+        s->status |= 1 << 5;		/* TUR */
+    if (s->enable && s->rx_len)
+        s->status |= 1 << 6;		/* ROR */
+
+    /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
+     * handle the cases where it makes a difference.  */
+    s->tx_len = tx - s->fifo_len;
+    s->rx_len = rx;
+    /* Note that is s->codec_out wasn't set, we wouldn't get called.  */
+    if (s->enable)
+        for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
+            s->codec_out(s->opaque, *sample);
+    pxa2xx_i2s_update(s);
+}
+
+static struct pxa2xx_i2s_s *pxa2xx_i2s_init(target_phys_addr_t base,
+                qemu_irq irq, struct pxa2xx_dma_state_s *dma)
+{
+    int iomemtype;
+    struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_i2s_s));
+
+    s->base = base;
+    s->irq = irq;
+    s->dma = dma;
+    s->data_req = pxa2xx_i2s_data_req;
+
+    pxa2xx_i2s_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_i2s_readfn,
+                    pxa2xx_i2s_writefn, s);
+    cpu_register_physical_memory(s->base & 0xfff00000, 0x100000, iomemtype);
+
+    register_savevm("pxa2xx_i2s", base, 0,
+                    pxa2xx_i2s_save, pxa2xx_i2s_load, s);
+
+    return s;
+}
+
+/* PXA Fast Infra-red Communications Port */
+struct pxa2xx_fir_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    struct pxa2xx_dma_state_s *dma;
+    int enable;
+    CharDriverState *chr;
+
+    uint8_t control[3];
+    uint8_t status[2];
+
+    int rx_len;
+    int rx_start;
+    uint8_t rx_fifo[64];
+};
+
+static void pxa2xx_fir_reset(struct pxa2xx_fir_s *s)
+{
+    s->control[0] = 0x00;
+    s->control[1] = 0x00;
+    s->control[2] = 0x00;
+    s->status[0] = 0x00;
+    s->status[1] = 0x00;
+    s->enable = 0;
+}
+
+static inline void pxa2xx_fir_update(struct pxa2xx_fir_s *s)
+{
+    static const int tresh[4] = { 8, 16, 32, 0 };
+    int intr = 0;
+    if ((s->control[0] & (1 << 4)) &&			/* RXE */
+                    s->rx_len >= tresh[s->control[2] & 3])	/* TRIG */
+        s->status[0] |= 1 << 4;				/* RFS */
+    else
+        s->status[0] &= ~(1 << 4);			/* RFS */
+    if (s->control[0] & (1 << 3))			/* TXE */
+        s->status[0] |= 1 << 3;				/* TFS */
+    else
+        s->status[0] &= ~(1 << 3);			/* TFS */
+    if (s->rx_len)
+        s->status[1] |= 1 << 2;				/* RNE */
+    else
+        s->status[1] &= ~(1 << 2);			/* RNE */
+    if (s->control[0] & (1 << 4))			/* RXE */
+        s->status[1] |= 1 << 0;				/* RSY */
+    else
+        s->status[1] &= ~(1 << 0);			/* RSY */
+
+    intr |= (s->control[0] & (1 << 5)) &&		/* RIE */
+            (s->status[0] & (1 << 4));			/* RFS */
+    intr |= (s->control[0] & (1 << 6)) &&		/* TIE */
+            (s->status[0] & (1 << 3));			/* TFS */
+    intr |= (s->control[2] & (1 << 4)) &&		/* TRAIL */
+            (s->status[0] & (1 << 6));			/* EOC */
+    intr |= (s->control[0] & (1 << 2)) &&		/* TUS */
+            (s->status[0] & (1 << 1));			/* TUR */
+    intr |= s->status[0] & 0x25;			/* FRE, RAB, EIF */
+
+    pxa2xx_dma_request(s->dma, PXA2XX_RX_RQ_ICP, (s->status[0] >> 4) & 1);
+    pxa2xx_dma_request(s->dma, PXA2XX_TX_RQ_ICP, (s->status[0] >> 3) & 1);
+
+    qemu_set_irq(s->irq, intr && s->enable);
+}
+
+#define ICCR0	0x00	/* FICP Control register 0 */
+#define ICCR1	0x04	/* FICP Control register 1 */
+#define ICCR2	0x08	/* FICP Control register 2 */
+#define ICDR	0x0c	/* FICP Data register */
+#define ICSR0	0x14	/* FICP Status register 0 */
+#define ICSR1	0x18	/* FICP Status register 1 */
+#define ICFOR	0x1c	/* FICP FIFO Occupancy Status register */
+
+static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    uint8_t ret;
+    addr -= s->base;
+
+    switch (addr) {
+    case ICCR0:
+        return s->control[0];
+    case ICCR1:
+        return s->control[1];
+    case ICCR2:
+        return s->control[2];
+    case ICDR:
+        s->status[0] &= ~0x01;
+        s->status[1] &= ~0x72;
+        if (s->rx_len) {
+            s->rx_len --;
+            ret = s->rx_fifo[s->rx_start ++];
+            s->rx_start &= 63;
+            pxa2xx_fir_update(s);
+            return ret;
+        }
+        printf("%s: Rx FIFO underrun.\n", __FUNCTION__);
+        break;
+    case ICSR0:
+        return s->status[0];
+    case ICSR1:
+        return s->status[1] | (1 << 3);			/* TNF */
+    case ICFOR:
+        return s->rx_len;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+        break;
+    }
+    return 0;
+}
+
+static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    uint8_t ch;
+    addr -= s->base;
+
+    switch (addr) {
+    case ICCR0:
+        s->control[0] = value;
+        if (!(value & (1 << 4)))			/* RXE */
+            s->rx_len = s->rx_start = 0;
+        if (!(value & (1 << 3)))			/* TXE */
+            /* Nop */;
+        s->enable = value & 1;				/* ITR */
+        if (!s->enable)
+            s->status[0] = 0;
+        pxa2xx_fir_update(s);
+        break;
+    case ICCR1:
+        s->control[1] = value;
+        break;
+    case ICCR2:
+        s->control[2] = value & 0x3f;
+        pxa2xx_fir_update(s);
+        break;
+    case ICDR:
+        if (s->control[2] & (1 << 2))			/* TXP */
+            ch = value;
+        else
+            ch = ~value;
+        if (s->chr && s->enable && (s->control[0] & (1 << 3)))	/* TXE */
+            qemu_chr_write(s->chr, &ch, 1);
+        break;
+    case ICSR0:
+        s->status[0] &= ~(value & 0x66);
+        pxa2xx_fir_update(s);
+        break;
+    case ICFOR:
+        break;
+    default:
+        printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_fir_readfn[] = {
+    pxa2xx_fir_read,
+    pxa2xx_fir_read,
+    pxa2xx_fir_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_fir_writefn[] = {
+    pxa2xx_fir_write,
+    pxa2xx_fir_write,
+    pxa2xx_fir_write,
+};
+
+static int pxa2xx_fir_is_empty(void *opaque)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    return (s->rx_len < 64);
+}
+
+static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    if (!(s->control[0] & (1 << 4)))			/* RXE */
+        return;
+
+    while (size --) {
+        s->status[1] |= 1 << 4;				/* EOF */
+        if (s->rx_len >= 64) {
+            s->status[1] |= 1 << 6;			/* ROR */
+            break;
+        }
+
+        if (s->control[2] & (1 << 3))			/* RXP */
+            s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
+        else
+            s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
+    }
+
+    pxa2xx_fir_update(s);
+}
+
+static void pxa2xx_fir_event(void *opaque, int event)
+{
+}
+
+static void pxa2xx_fir_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    int i;
+
+    qemu_put_be32(f, s->enable);
+
+    qemu_put_8s(f, &s->control[0]);
+    qemu_put_8s(f, &s->control[1]);
+    qemu_put_8s(f, &s->control[2]);
+    qemu_put_8s(f, &s->status[0]);
+    qemu_put_8s(f, &s->status[1]);
+
+    qemu_put_byte(f, s->rx_len);
+    for (i = 0; i < s->rx_len; i ++)
+        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 63]);
+}
+
+static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+    int i;
+
+    s->enable = qemu_get_be32(f);
+
+    qemu_get_8s(f, &s->control[0]);
+    qemu_get_8s(f, &s->control[1]);
+    qemu_get_8s(f, &s->control[2]);
+    qemu_get_8s(f, &s->status[0]);
+    qemu_get_8s(f, &s->status[1]);
+
+    s->rx_len = qemu_get_byte(f);
+    s->rx_start = 0;
+    for (i = 0; i < s->rx_len; i ++)
+        s->rx_fifo[i] = qemu_get_byte(f);
+
+    return 0;
+}
+
+static struct pxa2xx_fir_s *pxa2xx_fir_init(target_phys_addr_t base,
+                qemu_irq irq, struct pxa2xx_dma_state_s *dma,
+                CharDriverState *chr)
+{
+    int iomemtype;
+    struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_fir_s));
+
+    s->base = base;
+    s->irq = irq;
+    s->dma = dma;
+    s->chr = chr;
+
+    pxa2xx_fir_reset(s);
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_fir_readfn,
+                    pxa2xx_fir_writefn, s);
+    cpu_register_physical_memory(s->base, 0x1000, iomemtype);
+
+    if (chr)
+        qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
+                        pxa2xx_fir_rx, pxa2xx_fir_event, s);
+
+    register_savevm("pxa2xx_fir", 0, 0, pxa2xx_fir_save, pxa2xx_fir_load, s);
+
+    return s;
+}
+
+void pxa2xx_reset(int line, int level, void *opaque)
+{
+    struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+    if (level && (s->pm_regs[PCFR >> 2] & 0x10)) {	/* GPR_EN */
+        cpu_reset(s->env);
+        /* TODO: reset peripherals */
+    }
+}
+
+/* Initialise a PXA270 integrated chip (ARM based core).  */
+struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size,
+                DisplayState *ds, const char *revision)
+{
+    struct pxa2xx_state_s *s;
+    struct pxa2xx_ssp_s *ssp;
+    int iomemtype, i;
+    s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
+
+    if (revision && strncmp(revision, "pxa27", 5)) {
+        fprintf(stderr, "Machine requires a PXA27x processor.\n");
+        exit(1);
+    }
+
+    s->env = cpu_init();
+    cpu_arm_set_model(s->env, revision ?: "pxa270");
+    register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env);
+
+    /* SDRAM & Internal Memory Storage */
+    cpu_register_physical_memory(PXA2XX_SDRAM_BASE,
+                    sdram_size, qemu_ram_alloc(sdram_size) | IO_MEM_RAM);
+    cpu_register_physical_memory(PXA2XX_INTERNAL_BASE,
+                    0x40000, qemu_ram_alloc(0x40000) | IO_MEM_RAM);
+
+    s->pic = pxa2xx_pic_init(0x40d00000, s->env);
+
+    s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
+
+    pxa27x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0],
+                    s->pic[PXA27X_PIC_OST_4_11]);
+
+    s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
+
+    s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma);
+
+    for (i = 0; pxa270_serial[i].io_base; i ++)
+        if (serial_hds[i])
+            serial_mm_init(pxa270_serial[i].io_base, 2,
+                            s->pic[pxa270_serial[i].irqn], serial_hds[i], 1);
+        else
+            break;
+    if (serial_hds[i])
+        s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
+                        s->dma, serial_hds[i]);
+
+    if (ds)
+        s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds);
+
+    s->cm_base = 0x41300000;
+    s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
+    s->clkcfg = 0x00000009;		/* Turbo mode active */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn,
+                    pxa2xx_cm_writefn, s);
+    cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
+    register_savevm("pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s);
+
+    cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
+
+    s->mm_base = 0x48000000;
+    s->mm_regs[MDMRS >> 2] = 0x00020002;
+    s->mm_regs[MDREFR >> 2] = 0x03ca4000;
+    s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn,
+                    pxa2xx_mm_writefn, s);
+    cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
+    register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s);
+
+    s->pm_base = 0x40f00000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn,
+                    pxa2xx_pm_writefn, s);
+    cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
+    register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s);
+
+    for (i = 0; pxa27x_ssp[i].io_base; i ++);
+    s->ssp = (struct pxa2xx_ssp_s **)
+            qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i);
+    ssp = (struct pxa2xx_ssp_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i);
+    for (i = 0; pxa27x_ssp[i].io_base; i ++) {
+        s->ssp[i] = &ssp[i];
+        ssp[i].base = pxa27x_ssp[i].io_base;
+        ssp[i].irq = s->pic[pxa27x_ssp[i].irqn];
+
+        iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn,
+                        pxa2xx_ssp_writefn, &ssp[i]);
+        cpu_register_physical_memory(ssp[i].base, 0x1000, iomemtype);
+        register_savevm("pxa2xx_ssp", i, 0,
+                        pxa2xx_ssp_save, pxa2xx_ssp_load, s);
+    }
+
+    if (usb_enabled) {
+        usb_ohci_init_pxa(0x4c000000, 3, -1, s->pic[PXA2XX_PIC_USBH1]);
+    }
+
+    s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
+    s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
+
+    s->rtc_base = 0x40900000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn,
+                    pxa2xx_rtc_writefn, s);
+    cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype);
+    pxa2xx_rtc_init(s);
+    register_savevm("pxa2xx_rtc", 0, 0, pxa2xx_rtc_save, pxa2xx_rtc_load, s);
+
+    s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 0xffff);
+    s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0xff);
+
+    s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
+
+    /* GPIO1 resets the processor */
+    /* The handler can be overridden by board-specific code */
+    pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s);
+    return s;
+}
+
+/* Initialise a PXA255 integrated chip (ARM based core).  */
+struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size,
+                DisplayState *ds)
+{
+    struct pxa2xx_state_s *s;
+    struct pxa2xx_ssp_s *ssp;
+    int iomemtype, i;
+    s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
+
+    s->env = cpu_init();
+    cpu_arm_set_model(s->env, "pxa255");
+    register_savevm("cpu", 0, 0, cpu_save, cpu_load, s->env);
+
+    /* SDRAM & Internal Memory Storage */
+    cpu_register_physical_memory(PXA2XX_SDRAM_BASE, sdram_size,
+                    qemu_ram_alloc(sdram_size) | IO_MEM_RAM);
+    cpu_register_physical_memory(PXA2XX_INTERNAL_BASE, PXA2XX_INTERNAL_SIZE,
+                    qemu_ram_alloc(PXA2XX_INTERNAL_SIZE) | IO_MEM_RAM);
+
+    s->pic = pxa2xx_pic_init(0x40d00000, s->env);
+
+    s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
+
+    pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0]);
+
+    s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85);
+
+    s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma);
+
+    for (i = 0; pxa255_serial[i].io_base; i ++)
+        if (serial_hds[i])
+            serial_mm_init(pxa255_serial[i].io_base, 2,
+                            s->pic[pxa255_serial[i].irqn], serial_hds[i], 1);
+        else
+            break;
+    if (serial_hds[i])
+        s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
+                        s->dma, serial_hds[i]);
+
+    if (ds)
+        s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds);
+
+    s->cm_base = 0x41300000;
+    s->cm_regs[CCCR >> 2] = 0x02000210;	/* 416.0 MHz */
+    s->clkcfg = 0x00000009;		/* Turbo mode active */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn,
+                    pxa2xx_cm_writefn, s);
+    cpu_register_physical_memory(s->cm_base, 0x1000, iomemtype);
+    register_savevm("pxa2xx_cm", 0, 0, pxa2xx_cm_save, pxa2xx_cm_load, s);
+
+    cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
+
+    s->mm_base = 0x48000000;
+    s->mm_regs[MDMRS >> 2] = 0x00020002;
+    s->mm_regs[MDREFR >> 2] = 0x03ca4000;
+    s->mm_regs[MECR >> 2] = 0x00000001;	/* Two PC Card sockets */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn,
+                    pxa2xx_mm_writefn, s);
+    cpu_register_physical_memory(s->mm_base, 0x1000, iomemtype);
+    register_savevm("pxa2xx_mm", 0, 0, pxa2xx_mm_save, pxa2xx_mm_load, s);
+
+    s->pm_base = 0x40f00000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn,
+                    pxa2xx_pm_writefn, s);
+    cpu_register_physical_memory(s->pm_base, 0x100, iomemtype);
+    register_savevm("pxa2xx_pm", 0, 0, pxa2xx_pm_save, pxa2xx_pm_load, s);
+
+    for (i = 0; pxa255_ssp[i].io_base; i ++);
+    s->ssp = (struct pxa2xx_ssp_s **)
+            qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i);
+    ssp = (struct pxa2xx_ssp_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i);
+    for (i = 0; pxa255_ssp[i].io_base; i ++) {
+        s->ssp[i] = &ssp[i];
+        ssp[i].base = pxa255_ssp[i].io_base;
+        ssp[i].irq = s->pic[pxa255_ssp[i].irqn];
+
+        iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn,
+                        pxa2xx_ssp_writefn, &ssp[i]);
+        cpu_register_physical_memory(ssp[i].base, 0x1000, iomemtype);
+        register_savevm("pxa2xx_ssp", i, 0,
+                        pxa2xx_ssp_save, pxa2xx_ssp_load, s);
+    }
+
+    if (usb_enabled) {
+        usb_ohci_init_pxa(0x4c000000, 3, -1, s->pic[PXA2XX_PIC_USBH1]);
+    }
+
+    s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
+    s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
+
+    s->rtc_base = 0x40900000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn,
+                    pxa2xx_rtc_writefn, s);
+    cpu_register_physical_memory(s->rtc_base, 0x1000, iomemtype);
+    pxa2xx_rtc_init(s);
+    register_savevm("pxa2xx_rtc", 0, 0, pxa2xx_rtc_save, pxa2xx_rtc_load, s);
+
+    s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 0xffff);
+    s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0xff);
+
+    s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
+
+    /* GPIO1 resets the processor */
+    /* The handler can be overridden by board-specific code */
+    pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s);
+    return s;
+}
diff --git a/hw/pxa2xx_dma.c b/hw/pxa2xx_dma.c
new file mode 100644
index 0000000..53bce2e
--- /dev/null
+++ b/hw/pxa2xx_dma.c
@@ -0,0 +1,553 @@
+/*
+ * Intel XScale PXA255/270 DMA controller.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+
+struct pxa2xx_dma_channel_s {
+    target_phys_addr_t descr;
+    target_phys_addr_t src;
+    target_phys_addr_t dest;
+    uint32_t cmd;
+    uint32_t state;
+    int request;
+};
+
+/* Allow the DMA to be used as a PIC.  */
+typedef void (*pxa2xx_dma_handler_t)(void *opaque, int irq, int level);
+
+struct pxa2xx_dma_state_s {
+    pxa2xx_dma_handler_t handler;
+    target_phys_addr_t base;
+    qemu_irq irq;
+
+    uint32_t stopintr;
+    uint32_t eorintr;
+    uint32_t rasintr;
+    uint32_t startintr;
+    uint32_t endintr;
+
+    uint32_t align;
+    uint32_t pio;
+
+    int channels;
+    struct pxa2xx_dma_channel_s *chan;
+
+    uint8_t *req;
+
+    /* Flag to avoid recursive DMA invocations.  */
+    int running;
+};
+
+#define PXA255_DMA_NUM_CHANNELS	16
+#define PXA27X_DMA_NUM_CHANNELS	32
+
+#define PXA2XX_DMA_NUM_REQUESTS	75
+
+#define DCSR0	0x0000	/* DMA Control / Status register for Channel 0 */
+#define DCSR31	0x007c	/* DMA Control / Status register for Channel 31 */
+#define DALGN	0x00a0	/* DMA Alignment register */
+#define DPCSR	0x00a4	/* DMA Programmed I/O Control Status register */
+#define DRQSR0	0x00e0	/* DMA DREQ<0> Status register */
+#define DRQSR1	0x00e4	/* DMA DREQ<1> Status register */
+#define DRQSR2	0x00e8	/* DMA DREQ<2> Status register */
+#define DINT	0x00f0	/* DMA Interrupt register */
+#define DRCMR0	0x0100	/* Request to Channel Map register 0 */
+#define DRCMR63	0x01fc	/* Request to Channel Map register 63 */
+#define D_CH0	0x0200	/* Channel 0 Descriptor start */
+#define DRCMR64	0x1100	/* Request to Channel Map register 64 */
+#define DRCMR74	0x1128	/* Request to Channel Map register 74 */
+
+/* Per-channel register */
+#define DDADR	0x00
+#define DSADR	0x01
+#define DTADR	0x02
+#define DCMD	0x03
+
+/* Bit-field masks */
+#define DRCMR_CHLNUM		0x1f
+#define DRCMR_MAPVLD		(1 << 7)
+#define DDADR_STOP		(1 << 0)
+#define DDADR_BREN		(1 << 1)
+#define DCMD_LEN		0x1fff
+#define DCMD_WIDTH(x)		(1 << ((((x) >> 14) & 3) - 1))
+#define DCMD_SIZE(x)		(4 << (((x) >> 16) & 3))
+#define DCMD_FLYBYT		(1 << 19)
+#define DCMD_FLYBYS		(1 << 20)
+#define DCMD_ENDIRQEN		(1 << 21)
+#define DCMD_STARTIRQEN		(1 << 22)
+#define DCMD_CMPEN		(1 << 25)
+#define DCMD_FLOWTRG		(1 << 28)
+#define DCMD_FLOWSRC		(1 << 29)
+#define DCMD_INCTRGADDR		(1 << 30)
+#define DCMD_INCSRCADDR		(1 << 31)
+#define DCSR_BUSERRINTR		(1 << 0)
+#define DCSR_STARTINTR		(1 << 1)
+#define DCSR_ENDINTR		(1 << 2)
+#define DCSR_STOPINTR		(1 << 3)
+#define DCSR_RASINTR		(1 << 4)
+#define DCSR_REQPEND		(1 << 8)
+#define DCSR_EORINT		(1 << 9)
+#define DCSR_CMPST		(1 << 10)
+#define DCSR_MASKRUN		(1 << 22)
+#define DCSR_RASIRQEN		(1 << 23)
+#define DCSR_CLRCMPST		(1 << 24)
+#define DCSR_SETCMPST		(1 << 25)
+#define DCSR_EORSTOPEN		(1 << 26)
+#define DCSR_EORJMPEN		(1 << 27)
+#define DCSR_EORIRQEN		(1 << 28)
+#define DCSR_STOPIRQEN		(1 << 29)
+#define DCSR_NODESCFETCH	(1 << 30)
+#define DCSR_RUN		(1 << 31)
+
+static inline void pxa2xx_dma_update(struct pxa2xx_dma_state_s *s, int ch)
+{
+    if (ch >= 0) {
+        if ((s->chan[ch].state & DCSR_STOPIRQEN) &&
+                (s->chan[ch].state & DCSR_STOPINTR))
+            s->stopintr |= 1 << ch;
+        else
+            s->stopintr &= ~(1 << ch);
+
+        if ((s->chan[ch].state & DCSR_EORIRQEN) &&
+                (s->chan[ch].state & DCSR_EORINT))
+            s->eorintr |= 1 << ch;
+        else
+            s->eorintr &= ~(1 << ch);
+
+        if ((s->chan[ch].state & DCSR_RASIRQEN) &&
+                (s->chan[ch].state & DCSR_RASINTR))
+            s->rasintr |= 1 << ch;
+        else
+            s->rasintr &= ~(1 << ch);
+
+        if (s->chan[ch].state & DCSR_STARTINTR)
+            s->startintr |= 1 << ch;
+        else
+            s->startintr &= ~(1 << ch);
+
+        if (s->chan[ch].state & DCSR_ENDINTR)
+            s->endintr |= 1 << ch;
+        else
+            s->endintr &= ~(1 << ch);
+    }
+
+    if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
+        qemu_irq_raise(s->irq);
+    else
+        qemu_irq_lower(s->irq);
+}
+
+static inline void pxa2xx_dma_descriptor_fetch(
+                struct pxa2xx_dma_state_s *s, int ch)
+{
+    uint32_t desc[4];
+    target_phys_addr_t daddr = s->chan[ch].descr & ~0xf;
+    if ((s->chan[ch].descr & DDADR_BREN) && (s->chan[ch].state & DCSR_CMPST))
+        daddr += 32;
+
+    cpu_physical_memory_read(daddr, (uint8_t *) desc, 16);
+    s->chan[ch].descr = desc[DDADR];
+    s->chan[ch].src = desc[DSADR];
+    s->chan[ch].dest = desc[DTADR];
+    s->chan[ch].cmd = desc[DCMD];
+
+    if (s->chan[ch].cmd & DCMD_FLOWSRC)
+        s->chan[ch].src &= ~3;
+    if (s->chan[ch].cmd & DCMD_FLOWTRG)
+        s->chan[ch].dest &= ~3;
+
+    if (s->chan[ch].cmd & (DCMD_CMPEN | DCMD_FLYBYS | DCMD_FLYBYT))
+        printf("%s: unsupported mode in channel %i\n", __FUNCTION__, ch);
+
+    if (s->chan[ch].cmd & DCMD_STARTIRQEN)
+        s->chan[ch].state |= DCSR_STARTINTR;
+}
+
+static void pxa2xx_dma_run(struct pxa2xx_dma_state_s *s)
+{
+    int c, srcinc, destinc;
+    uint32_t n, size;
+    uint32_t width;
+    uint32_t length;
+    char buffer[32];
+    struct pxa2xx_dma_channel_s *ch;
+
+    if (s->running ++)
+        return;
+
+    while (s->running) {
+        s->running = 1;
+        for (c = 0; c < s->channels; c ++) {
+            ch = &s->chan[c];
+
+            while ((ch->state & DCSR_RUN) && !(ch->state & DCSR_STOPINTR)) {
+                /* Test for pending requests */
+                if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) && !ch->request)
+                    break;
+
+                length = ch->cmd & DCMD_LEN;
+                size = DCMD_SIZE(ch->cmd);
+                width = DCMD_WIDTH(ch->cmd);
+
+                srcinc = (ch->cmd & DCMD_INCSRCADDR) ? width : 0;
+                destinc = (ch->cmd & DCMD_INCTRGADDR) ? width : 0;
+
+                while (length) {
+                    size = MIN(length, size);
+
+                    for (n = 0; n < size; n += width) {
+                        cpu_physical_memory_read(ch->src, buffer + n, width);
+                        ch->src += srcinc;
+                    }
+
+                    for (n = 0; n < size; n += width) {
+                        cpu_physical_memory_write(ch->dest, buffer + n, width);
+                        ch->dest += destinc;
+                    }
+
+                    length -= size;
+
+                    if ((ch->cmd & (DCMD_FLOWSRC | DCMD_FLOWTRG)) &&
+                            !ch->request) {
+                        ch->state |= DCSR_EORINT;
+                        if (ch->state & DCSR_EORSTOPEN)
+                            ch->state |= DCSR_STOPINTR;
+                        if ((ch->state & DCSR_EORJMPEN) &&
+                                        !(ch->state & DCSR_NODESCFETCH))
+                            pxa2xx_dma_descriptor_fetch(s, c);
+                        break;
+		    }
+                }
+
+                ch->cmd = (ch->cmd & ~DCMD_LEN) | length;
+
+                /* Is the transfer complete now? */
+                if (!length) {
+                    if (ch->cmd & DCMD_ENDIRQEN)
+                        ch->state |= DCSR_ENDINTR;
+
+                    if ((ch->state & DCSR_NODESCFETCH) ||
+                                (ch->descr & DDADR_STOP) ||
+                                (ch->state & DCSR_EORSTOPEN)) {
+                        ch->state |= DCSR_STOPINTR;
+                        ch->state &= ~DCSR_RUN;
+
+                        break;
+                    }
+
+                    ch->state |= DCSR_STOPINTR;
+                    break;
+                }
+            }
+        }
+
+        s->running --;
+    }
+}
+
+static uint32_t pxa2xx_dma_read(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
+    unsigned int channel;
+    offset -= s->base;
+
+    switch (offset) {
+    case DRCMR64 ... DRCMR74:
+        offset -= DRCMR64 - DRCMR0 - (64 << 2);
+        /* Fall through */
+    case DRCMR0 ... DRCMR63:
+        channel = (offset - DRCMR0) >> 2;
+        return s->req[channel];
+
+    case DRQSR0:
+    case DRQSR1:
+    case DRQSR2:
+        return 0;
+
+    case DCSR0 ... DCSR31:
+        channel = offset >> 2;
+	if (s->chan[channel].request)
+            return s->chan[channel].state | DCSR_REQPEND;
+        return s->chan[channel].state;
+
+    case DINT:
+        return s->stopintr | s->eorintr | s->rasintr |
+                s->startintr | s->endintr;
+
+    case DALGN:
+        return s->align;
+
+    case DPCSR:
+        return s->pio;
+    }
+
+    if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
+        channel = (offset - D_CH0) >> 4;
+        switch ((offset & 0x0f) >> 2) {
+        case DDADR:
+            return s->chan[channel].descr;
+        case DSADR:
+            return s->chan[channel].src;
+        case DTADR:
+            return s->chan[channel].dest;
+        case DCMD:
+            return s->chan[channel].cmd;
+        }
+    }
+
+    cpu_abort(cpu_single_env,
+                    "%s: Bad offset 0x%04lx\n", __FUNCTION__, offset);
+    return 7;
+}
+
+static void pxa2xx_dma_write(void *opaque,
+                 target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
+    unsigned int channel;
+    offset -= s->base;
+
+    switch (offset) {
+    case DRCMR64 ... DRCMR74:
+        offset -= DRCMR64 - DRCMR0 - (64 << 2);
+        /* Fall through */
+    case DRCMR0 ... DRCMR63:
+        channel = (offset - DRCMR0) >> 2;
+
+        if (value & DRCMR_MAPVLD)
+            if ((value & DRCMR_CHLNUM) > s->channels)
+                cpu_abort(cpu_single_env, "%s: Bad DMA channel %i\n",
+                        __FUNCTION__, value & DRCMR_CHLNUM);
+
+        s->req[channel] = value;
+        break;
+
+    case DRQSR0:
+    case DRQSR1:
+    case DRQSR2:
+        /* Nothing to do */
+        break;
+
+    case DCSR0 ... DCSR31:
+        channel = offset >> 2;
+        s->chan[channel].state &= 0x0000071f & ~(value &
+                        (DCSR_EORINT | DCSR_ENDINTR |
+                         DCSR_STARTINTR | DCSR_BUSERRINTR));
+        s->chan[channel].state |= value & 0xfc800000;
+
+        if (s->chan[channel].state & DCSR_STOPIRQEN)
+            s->chan[channel].state &= ~DCSR_STOPINTR;
+
+        if (value & DCSR_NODESCFETCH) {
+            /* No-descriptor-fetch mode */
+            if (value & DCSR_RUN)
+                pxa2xx_dma_run(s);
+        } else {
+            /* Descriptor-fetch mode */
+            if (value & DCSR_RUN) {
+                s->chan[channel].state &= ~DCSR_STOPINTR;
+                pxa2xx_dma_descriptor_fetch(s, channel);
+                pxa2xx_dma_run(s);
+            }
+        }
+
+        /* Shouldn't matter as our DMA is synchronous.  */
+        if (!(value & (DCSR_RUN | DCSR_MASKRUN)))
+            s->chan[channel].state |= DCSR_STOPINTR;
+
+        if (value & DCSR_CLRCMPST)
+            s->chan[channel].state &= ~DCSR_CMPST;
+        if (value & DCSR_SETCMPST)
+            s->chan[channel].state |= DCSR_CMPST;
+
+        pxa2xx_dma_update(s, channel);
+        break;
+
+    case DALGN:
+        s->align = value;
+        break;
+
+    case DPCSR:
+        s->pio = value & 0x80000001;
+        break;
+
+    default:
+        if (offset >= D_CH0 && offset < D_CH0 + (s->channels << 4)) {
+            channel = (offset - D_CH0) >> 4;
+            switch ((offset & 0x0f) >> 2) {
+            case DDADR:
+                s->chan[channel].descr = value;
+                break;
+            case DSADR:
+                s->chan[channel].src = value;
+                break;
+            case DTADR:
+                s->chan[channel].dest = value;
+                break;
+            case DCMD:
+                s->chan[channel].cmd = value;
+                break;
+            default:
+                goto fail;
+            }
+
+            break;
+        }
+    fail:
+        cpu_abort(cpu_single_env, "%s: Bad offset 0x%04lx\n",
+                __FUNCTION__, offset);
+    }
+}
+
+static uint32_t pxa2xx_dma_readbad(void *opaque, target_phys_addr_t offset)
+{
+    cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__);
+    return 5;
+}
+
+static void pxa2xx_dma_writebad(void *opaque,
+                 target_phys_addr_t offset, uint32_t value)
+{
+    cpu_abort(cpu_single_env, "%s: Bad access width\n", __FUNCTION__);
+}
+
+static CPUReadMemoryFunc *pxa2xx_dma_readfn[] = {
+    pxa2xx_dma_readbad,
+    pxa2xx_dma_readbad,
+    pxa2xx_dma_read
+};
+
+static CPUWriteMemoryFunc *pxa2xx_dma_writefn[] = {
+    pxa2xx_dma_writebad,
+    pxa2xx_dma_writebad,
+    pxa2xx_dma_write
+};
+
+static void pxa2xx_dma_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
+    int i;
+
+    qemu_put_be32(f, s->channels);
+
+    qemu_put_be32s(f, &s->stopintr);
+    qemu_put_be32s(f, &s->eorintr);
+    qemu_put_be32s(f, &s->rasintr);
+    qemu_put_be32s(f, &s->startintr);
+    qemu_put_be32s(f, &s->endintr);
+    qemu_put_be32s(f, &s->align);
+    qemu_put_be32s(f, &s->pio);
+
+    qemu_put_buffer(f, s->req, PXA2XX_DMA_NUM_REQUESTS);
+    for (i = 0; i < s->channels; i ++) {
+        qemu_put_betl(f, s->chan[i].descr);
+        qemu_put_betl(f, s->chan[i].src);
+        qemu_put_betl(f, s->chan[i].dest);
+        qemu_put_be32s(f, &s->chan[i].cmd);
+        qemu_put_be32s(f, &s->chan[i].state);
+        qemu_put_be32(f, s->chan[i].request);
+    };
+}
+
+static int pxa2xx_dma_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_dma_state_s *s = (struct pxa2xx_dma_state_s *) opaque;
+    int i;
+
+    if (qemu_get_be32(f) != s->channels)
+        return -EINVAL;
+
+    qemu_get_be32s(f, &s->stopintr);
+    qemu_get_be32s(f, &s->eorintr);
+    qemu_get_be32s(f, &s->rasintr);
+    qemu_get_be32s(f, &s->startintr);
+    qemu_get_be32s(f, &s->endintr);
+    qemu_get_be32s(f, &s->align);
+    qemu_get_be32s(f, &s->pio);
+
+    qemu_get_buffer(f, s->req, PXA2XX_DMA_NUM_REQUESTS);
+    for (i = 0; i < s->channels; i ++) {
+        s->chan[i].descr = qemu_get_betl(f);
+        s->chan[i].src = qemu_get_betl(f);
+        s->chan[i].dest = qemu_get_betl(f);
+        qemu_get_be32s(f, &s->chan[i].cmd);
+        qemu_get_be32s(f, &s->chan[i].state);
+        s->chan[i].request = qemu_get_be32(f);
+    };
+
+    return 0;
+}
+
+static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base,
+                qemu_irq irq, int channels)
+{
+    int i, iomemtype;
+    struct pxa2xx_dma_state_s *s;
+    s = (struct pxa2xx_dma_state_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_dma_state_s));
+
+    s->channels = channels;
+    s->chan = qemu_mallocz(sizeof(struct pxa2xx_dma_channel_s) * s->channels);
+    s->base = base;
+    s->irq = irq;
+    s->handler = (pxa2xx_dma_handler_t) pxa2xx_dma_request;
+    s->req = qemu_mallocz(sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
+
+    memset(s->chan, 0, sizeof(struct pxa2xx_dma_channel_s) * s->channels);
+    for (i = 0; i < s->channels; i ++)
+        s->chan[i].state = DCSR_STOPINTR;
+
+    memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_dma_readfn,
+                    pxa2xx_dma_writefn, s);
+    cpu_register_physical_memory(base, 0x00010000, iomemtype);
+
+    register_savevm("pxa2xx_dma", 0, 0, pxa2xx_dma_save, pxa2xx_dma_load, s);
+
+    return s;
+}
+
+struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
+                qemu_irq irq)
+{
+    return pxa2xx_dma_init(base, irq, PXA27X_DMA_NUM_CHANNELS);
+}
+
+struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
+                qemu_irq irq)
+{
+    return pxa2xx_dma_init(base, irq, PXA255_DMA_NUM_CHANNELS);
+}
+
+void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on)
+{
+    int ch;
+    if (req_num < 0 || req_num >= PXA2XX_DMA_NUM_REQUESTS)
+        cpu_abort(cpu_single_env,
+              "%s: Bad DMA request %i\n", __FUNCTION__, req_num);
+
+    if (!(s->req[req_num] & DRCMR_MAPVLD))
+        return;
+    ch = s->req[req_num] & DRCMR_CHLNUM;
+
+    if (!s->chan[ch].request && on)
+        s->chan[ch].state |= DCSR_RASINTR;
+    else
+        s->chan[ch].state &= ~DCSR_RASINTR;
+    if (s->chan[ch].request && !on)
+        s->chan[ch].state |= DCSR_EORINT;
+
+    s->chan[ch].request = on;
+    if (on) {
+        pxa2xx_dma_run(s);
+        pxa2xx_dma_update(s, ch);
+    }
+}
diff --git a/hw/pxa2xx_gpio.c b/hw/pxa2xx_gpio.c
new file mode 100644
index 0000000..85aeb50
--- /dev/null
+++ b/hw/pxa2xx_gpio.c
@@ -0,0 +1,338 @@
+/*
+ * Intel XScale PXA255/270 GPIO controller emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPL.
+ */
+
+#include "vl.h"
+
+#define PXA2XX_GPIO_BANKS	4
+
+struct pxa2xx_gpio_info_s {
+    target_phys_addr_t base;
+    qemu_irq *pic;
+    int lines;
+    CPUState *cpu_env;
+
+    /* XXX: GNU C vectors are more suitable */
+    uint32_t ilevel[PXA2XX_GPIO_BANKS];
+    uint32_t olevel[PXA2XX_GPIO_BANKS];
+    uint32_t dir[PXA2XX_GPIO_BANKS];
+    uint32_t rising[PXA2XX_GPIO_BANKS];
+    uint32_t falling[PXA2XX_GPIO_BANKS];
+    uint32_t status[PXA2XX_GPIO_BANKS];
+    uint32_t gafr[PXA2XX_GPIO_BANKS * 2];
+
+    uint32_t prev_level[PXA2XX_GPIO_BANKS];
+    struct {
+        gpio_handler_t fn;
+        void *opaque;
+    } handler[PXA2XX_GPIO_BANKS * 32];
+
+    void (*read_notify)(void *opaque);
+    void *opaque;
+};
+
+static struct {
+    enum {
+        GPIO_NONE,
+        GPLR,
+        GPSR,
+        GPCR,
+        GPDR,
+        GRER,
+        GFER,
+        GEDR,
+        GAFR_L,
+        GAFR_U,
+    } reg;
+    int bank;
+} pxa2xx_gpio_regs[0x200] = {
+    [0 ... 0x1ff] = { GPIO_NONE, 0 },
+#define PXA2XX_REG(reg, a0, a1, a2, a3)	\
+    [a0] = { reg, 0 }, [a1] = { reg, 1 }, [a2] = { reg, 2 }, [a3] = { reg, 3 },
+
+    PXA2XX_REG(GPLR, 0x000, 0x004, 0x008, 0x100)
+    PXA2XX_REG(GPSR, 0x018, 0x01c, 0x020, 0x118)
+    PXA2XX_REG(GPCR, 0x024, 0x028, 0x02c, 0x124)
+    PXA2XX_REG(GPDR, 0x00c, 0x010, 0x014, 0x10c)
+    PXA2XX_REG(GRER, 0x030, 0x034, 0x038, 0x130)
+    PXA2XX_REG(GFER, 0x03c, 0x040, 0x044, 0x13c)
+    PXA2XX_REG(GEDR, 0x048, 0x04c, 0x050, 0x148)
+    PXA2XX_REG(GAFR_L, 0x054, 0x05c, 0x064, 0x06c)
+    PXA2XX_REG(GAFR_U, 0x058, 0x060, 0x068, 0x070)
+};
+
+static void pxa2xx_gpio_irq_update(struct pxa2xx_gpio_info_s *s)
+{
+    if (s->status[0] & (1 << 0))
+        qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_0]);
+    else
+        qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_0]);
+
+    if (s->status[0] & (1 << 1))
+        qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_1]);
+    else
+        qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_1]);
+
+    if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
+        qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_X]);
+    else
+        qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_X]);
+}
+
+/* Bitmap of pins used as standby and sleep wake-up sources.  */
+const int pxa2xx_gpio_wake[PXA2XX_GPIO_BANKS] = {
+    0x8003fe1b, 0x002001fc, 0xec080000, 0x0012007f,
+};
+
+void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level)
+{
+    int bank;
+    uint32_t mask;
+
+    if (line >= s->lines) {
+        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    bank = line >> 5;
+    mask = 1 << (line & 31);
+
+    if (level) {
+        s->status[bank] |= s->rising[bank] & mask &
+                ~s->ilevel[bank] & ~s->dir[bank];
+        s->ilevel[bank] |= mask;
+    } else {
+        s->status[bank] |= s->falling[bank] & mask &
+                s->ilevel[bank] & ~s->dir[bank];
+        s->ilevel[bank] &= ~mask;
+    }
+
+    if (s->status[bank] & mask)
+        pxa2xx_gpio_irq_update(s);
+
+    /* Wake-up GPIOs */
+    if (s->cpu_env->halted && (mask & ~s->dir[bank] & pxa2xx_gpio_wake[bank]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
+}
+
+static void pxa2xx_gpio_handler_update(struct pxa2xx_gpio_info_s *s) {
+    uint32_t level, diff;
+    int i, bit, line;
+    for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
+        level = s->olevel[i] & s->dir[i];
+
+        for (diff = s->prev_level[i] ^ level; diff; diff ^= 1 << bit) {
+            bit = ffs(diff) - 1;
+            line = bit + 32 * i;
+            if (s->handler[line].fn)
+                s->handler[line].fn(line, (level >> bit) & 1,
+                                s->handler[line].opaque);
+        }
+
+        s->prev_level[i] = level;
+    }
+}
+
+static uint32_t pxa2xx_gpio_read(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
+    uint32_t ret;
+    int bank;
+    offset -= s->base;
+    if (offset >= 0x200)
+        return 0;
+
+    bank = pxa2xx_gpio_regs[offset].bank;
+    switch (pxa2xx_gpio_regs[offset].reg) {
+    case GPDR:		/* GPIO Pin-Direction registers */
+        return s->dir[bank];
+
+    case GRER:		/* GPIO Rising-Edge Detect Enable registers */
+        return s->rising[bank];
+
+    case GFER:		/* GPIO Falling-Edge Detect Enable registers */
+        return s->falling[bank];
+
+    case GAFR_L:	/* GPIO Alternate Function registers */
+        return s->gafr[bank * 2];
+
+    case GAFR_U:	/* GPIO Alternate Function registers */
+        return s->gafr[bank * 2 + 1];
+
+    case GPLR:		/* GPIO Pin-Level registers */
+        ret = (s->olevel[bank] & s->dir[bank]) |
+                (s->ilevel[bank] & ~s->dir[bank]);
+        if (s->read_notify)
+            s->read_notify(s->opaque);
+        return ret;
+
+    case GEDR:		/* GPIO Edge Detect Status registers */
+        return s->status[bank];
+
+    default:
+        cpu_abort(cpu_single_env,
+                "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_gpio_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
+    int bank;
+    offset -= s->base;
+    if (offset >= 0x200)
+        return;
+
+    bank = pxa2xx_gpio_regs[offset].bank;
+    switch (pxa2xx_gpio_regs[offset].reg) {
+    case GPDR:		/* GPIO Pin-Direction registers */
+        s->dir[bank] = value;
+        pxa2xx_gpio_handler_update(s);
+        break;
+
+    case GPSR:		/* GPIO Pin-Output Set registers */
+        s->olevel[bank] |= value;
+        pxa2xx_gpio_handler_update(s);
+        break;
+
+    case GPCR:		/* GPIO Pin-Output Clear registers */
+        s->olevel[bank] &= ~value;
+        pxa2xx_gpio_handler_update(s);
+        break;
+
+    case GRER:		/* GPIO Rising-Edge Detect Enable registers */
+        s->rising[bank] = value;
+        break;
+
+    case GFER:		/* GPIO Falling-Edge Detect Enable registers */
+        s->falling[bank] = value;
+        break;
+
+    case GAFR_L:	/* GPIO Alternate Function registers */
+        s->gafr[bank * 2] = value;
+        break;
+
+    case GAFR_U:	/* GPIO Alternate Function registers */
+        s->gafr[bank * 2 + 1] = value;
+        break;
+
+    case GEDR:		/* GPIO Edge Detect Status registers */
+        s->status[bank] &= ~value;
+        pxa2xx_gpio_irq_update(s);
+        break;
+
+    default:
+        cpu_abort(cpu_single_env,
+                "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_gpio_readfn[] = {
+    pxa2xx_gpio_read,
+    pxa2xx_gpio_read,
+    pxa2xx_gpio_read
+};
+
+static CPUWriteMemoryFunc *pxa2xx_gpio_writefn[] = {
+    pxa2xx_gpio_write,
+    pxa2xx_gpio_write,
+    pxa2xx_gpio_write
+};
+
+static void pxa2xx_gpio_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
+    int i;
+
+    qemu_put_be32(f, s->lines);
+
+    for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
+        qemu_put_be32s(f, &s->ilevel[i]);
+        qemu_put_be32s(f, &s->olevel[i]);
+        qemu_put_be32s(f, &s->dir[i]);
+        qemu_put_be32s(f, &s->rising[i]);
+        qemu_put_be32s(f, &s->falling[i]);
+        qemu_put_be32s(f, &s->status[i]);
+        qemu_put_be32s(f, &s->gafr[i * 2 + 0]);
+        qemu_put_be32s(f, &s->gafr[i * 2 + 1]);
+
+        qemu_put_be32s(f, &s->prev_level[i]);
+    }
+}
+
+static int pxa2xx_gpio_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_gpio_info_s *s = (struct pxa2xx_gpio_info_s *) opaque;
+    int i;
+
+    if (qemu_get_be32(f) != s->lines)
+        return -EINVAL;
+
+    for (i = 0; i < PXA2XX_GPIO_BANKS; i ++) {
+        qemu_get_be32s(f, &s->ilevel[i]);
+        qemu_get_be32s(f, &s->olevel[i]);
+        qemu_get_be32s(f, &s->dir[i]);
+        qemu_get_be32s(f, &s->rising[i]);
+        qemu_get_be32s(f, &s->falling[i]);
+        qemu_get_be32s(f, &s->status[i]);
+        qemu_get_be32s(f, &s->gafr[i * 2 + 0]);
+        qemu_get_be32s(f, &s->gafr[i * 2 + 1]);
+
+        qemu_get_be32s(f, &s->prev_level[i]);
+    }
+
+    return 0;
+}
+
+struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
+                CPUState *env, qemu_irq *pic, int lines)
+{
+    int iomemtype;
+    struct pxa2xx_gpio_info_s *s;
+
+    s = (struct pxa2xx_gpio_info_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_gpio_info_s));
+    memset(s, 0, sizeof(struct pxa2xx_gpio_info_s));
+    s->base = base;
+    s->pic = pic;
+    s->lines = lines;
+    s->cpu_env = env;
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_gpio_readfn,
+                    pxa2xx_gpio_writefn, s);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+
+    register_savevm("pxa2xx_gpio", 0, 0,
+                    pxa2xx_gpio_save, pxa2xx_gpio_load, s);
+
+    return s;
+}
+
+void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line,
+                gpio_handler_t handler, void *opaque) {
+    if (line >= s->lines) {
+        printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
+        return;
+    }
+
+    s->handler[line].fn = handler;
+    s->handler[line].opaque = opaque;
+}
+
+/*
+ * Registers a callback to notify on GPLR reads.  This normally
+ * shouldn't be needed but it is used for the hack on Spitz machines.
+ */
+void pxa2xx_gpio_read_notifier(struct pxa2xx_gpio_info_s *s,
+                void (*handler)(void *opaque), void *opaque) {
+    s->read_notify = handler;
+    s->opaque = opaque;
+}
diff --git a/hw/pxa2xx_lcd.c b/hw/pxa2xx_lcd.c
new file mode 100644
index 0000000..2c10963
--- /dev/null
+++ b/hw/pxa2xx_lcd.c
@@ -0,0 +1,1049 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "vl.h"
+#include "pixel_ops.h"
+
+typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int, int);
+
+struct pxa2xx_lcdc_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    int irqlevel;
+
+    int invalidated;
+    DisplayState *ds;
+    drawfn *line_fn[2];
+    int dest_width;
+    int xres, yres;
+    int pal_for;
+    int transp;
+    enum {
+        pxa_lcdc_2bpp = 1,
+        pxa_lcdc_4bpp = 2,
+        pxa_lcdc_8bpp = 3,
+        pxa_lcdc_16bpp = 4,
+        pxa_lcdc_18bpp = 5,
+        pxa_lcdc_18pbpp = 6,
+        pxa_lcdc_19bpp = 7,
+        pxa_lcdc_19pbpp = 8,
+        pxa_lcdc_24bpp = 9,
+        pxa_lcdc_25bpp = 10,
+    } bpp;
+
+    uint32_t control[6];
+    uint32_t status[2];
+    uint32_t ovl1c[2];
+    uint32_t ovl2c[2];
+    uint32_t ccr;
+    uint32_t cmdcr;
+    uint32_t trgbr;
+    uint32_t tcr;
+    uint32_t liidr;
+    uint8_t bscntr;
+
+    struct {
+        target_phys_addr_t branch;
+        int up;
+        uint8_t palette[1024];
+        uint8_t pbuffer[1024];
+        void (*redraw)(struct pxa2xx_lcdc_s *s, uint8_t *fb,
+                        int *miny, int *maxy);
+
+        target_phys_addr_t descriptor;
+        target_phys_addr_t source;
+        uint32_t id;
+        uint32_t command;
+    } dma_ch[7];
+
+    void (*vsync_cb)(void *opaque);
+    void *opaque;
+    int orientation;
+};
+
+struct __attribute__ ((__packed__)) pxa_frame_descriptor_s {
+    uint32_t fdaddr;
+    uint32_t fsaddr;
+    uint32_t fidr;
+    uint32_t ldcmd;
+};
+
+#define LCCR0	0x000	/* LCD Controller Control register 0 */
+#define LCCR1	0x004	/* LCD Controller Control register 1 */
+#define LCCR2	0x008	/* LCD Controller Control register 2 */
+#define LCCR3	0x00c	/* LCD Controller Control register 3 */
+#define LCCR4	0x010	/* LCD Controller Control register 4 */
+#define LCCR5	0x014	/* LCD Controller Control register 5 */
+
+#define FBR0	0x020	/* DMA Channel 0 Frame Branch register */
+#define FBR1	0x024	/* DMA Channel 1 Frame Branch register */
+#define FBR2	0x028	/* DMA Channel 2 Frame Branch register */
+#define FBR3	0x02c	/* DMA Channel 3 Frame Branch register */
+#define FBR4	0x030	/* DMA Channel 4 Frame Branch register */
+#define FBR5	0x110	/* DMA Channel 5 Frame Branch register */
+#define FBR6	0x114	/* DMA Channel 6 Frame Branch register */
+
+#define LCSR1	0x034	/* LCD Controller Status register 1 */
+#define LCSR0	0x038	/* LCD Controller Status register 0 */
+#define LIIDR	0x03c	/* LCD Controller Interrupt ID register */
+
+#define TRGBR	0x040	/* TMED RGB Seed register */
+#define TCR	0x044	/* TMED Control register */
+
+#define OVL1C1	0x050	/* Overlay 1 Control register 1 */
+#define OVL1C2	0x060	/* Overlay 1 Control register 2 */
+#define OVL2C1	0x070	/* Overlay 2 Control register 1 */
+#define OVL2C2	0x080	/* Overlay 2 Control register 2 */
+#define CCR	0x090	/* Cursor Control register */
+
+#define CMDCR	0x100	/* Command Control register */
+#define PRSR	0x104	/* Panel Read Status register */
+
+#define PXA_LCDDMA_CHANS	7
+#define DMA_FDADR		0x00	/* Frame Descriptor Address register */
+#define DMA_FSADR		0x04	/* Frame Source Address register */
+#define DMA_FIDR		0x08	/* Frame ID register */
+#define DMA_LDCMD		0x0c	/* Command register */
+
+/* LCD Buffer Strength Control register */
+#define BSCNTR	0x04000054
+
+/* Bitfield masks */
+#define LCCR0_ENB	(1 << 0)
+#define LCCR0_CMS	(1 << 1)
+#define LCCR0_SDS	(1 << 2)
+#define LCCR0_LDM	(1 << 3)
+#define LCCR0_SOFM0	(1 << 4)
+#define LCCR0_IUM	(1 << 5)
+#define LCCR0_EOFM0	(1 << 6)
+#define LCCR0_PAS	(1 << 7)
+#define LCCR0_DPD	(1 << 9)
+#define LCCR0_DIS	(1 << 10)
+#define LCCR0_QDM	(1 << 11)
+#define LCCR0_PDD	(0xff << 12)
+#define LCCR0_BSM0	(1 << 20)
+#define LCCR0_OUM	(1 << 21)
+#define LCCR0_LCDT	(1 << 22)
+#define LCCR0_RDSTM	(1 << 23)
+#define LCCR0_CMDIM	(1 << 24)
+#define LCCR0_OUC	(1 << 25)
+#define LCCR0_LDDALT	(1 << 26)
+#define LCCR1_PPL(x)	((x) & 0x3ff)
+#define LCCR2_LPP(x)	((x) & 0x3ff)
+#define LCCR3_API	(15 << 16)
+#define LCCR3_BPP(x)	((((x) >> 24) & 7) | (((x) >> 26) & 8))
+#define LCCR3_PDFOR(x)	(((x) >> 30) & 3)
+#define LCCR4_K1(x)	(((x) >> 0) & 7)
+#define LCCR4_K2(x)	(((x) >> 3) & 7)
+#define LCCR4_K3(x)	(((x) >> 6) & 7)
+#define LCCR4_PALFOR(x)	(((x) >> 15) & 3)
+#define LCCR5_SOFM(ch)	(1 << (ch - 1))
+#define LCCR5_EOFM(ch)	(1 << (ch + 7))
+#define LCCR5_BSM(ch)	(1 << (ch + 15))
+#define LCCR5_IUM(ch)	(1 << (ch + 23))
+#define OVLC1_EN	(1 << 31)
+#define CCR_CEN		(1 << 31)
+#define FBR_BRA		(1 << 0)
+#define FBR_BINT	(1 << 1)
+#define FBR_SRCADDR	(0xfffffff << 4)
+#define LCSR0_LDD	(1 << 0)
+#define LCSR0_SOF0	(1 << 1)
+#define LCSR0_BER	(1 << 2)
+#define LCSR0_ABC	(1 << 3)
+#define LCSR0_IU0	(1 << 4)
+#define LCSR0_IU1	(1 << 5)
+#define LCSR0_OU	(1 << 6)
+#define LCSR0_QD	(1 << 7)
+#define LCSR0_EOF0	(1 << 8)
+#define LCSR0_BS0	(1 << 9)
+#define LCSR0_SINT	(1 << 10)
+#define LCSR0_RDST	(1 << 11)
+#define LCSR0_CMDINT	(1 << 12)
+#define LCSR0_BERCH(x)	(((x) & 7) << 28)
+#define LCSR1_SOF(ch)	(1 << (ch - 1))
+#define LCSR1_EOF(ch)	(1 << (ch + 7))
+#define LCSR1_BS(ch)	(1 << (ch + 15))
+#define LCSR1_IU(ch)	(1 << (ch + 23))
+#define LDCMD_LENGTH(x)	((x) & 0x001ffffc)
+#define LDCMD_EOFINT	(1 << 21)
+#define LDCMD_SOFINT	(1 << 22)
+#define LDCMD_PAL	(1 << 26)
+
+/* Route internal interrupt lines to the global IC */
+static void pxa2xx_lcdc_int_update(struct pxa2xx_lcdc_s *s)
+{
+    int level = 0;
+    level |= (s->status[0] & LCSR0_LDD)    && !(s->control[0] & LCCR0_LDM);
+    level |= (s->status[0] & LCSR0_SOF0)   && !(s->control[0] & LCCR0_SOFM0);
+    level |= (s->status[0] & LCSR0_IU0)    && !(s->control[0] & LCCR0_IUM);
+    level |= (s->status[0] & LCSR0_IU1)    && !(s->control[5] & LCCR5_IUM(1));
+    level |= (s->status[0] & LCSR0_OU)     && !(s->control[0] & LCCR0_OUM);
+    level |= (s->status[0] & LCSR0_QD)     && !(s->control[0] & LCCR0_QDM);
+    level |= (s->status[0] & LCSR0_EOF0)   && !(s->control[0] & LCCR0_EOFM0);
+    level |= (s->status[0] & LCSR0_BS0)    && !(s->control[0] & LCCR0_BSM0);
+    level |= (s->status[0] & LCSR0_RDST)   && !(s->control[0] & LCCR0_RDSTM);
+    level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
+    level |= (s->status[1] & ~s->control[5]);
+
+    qemu_set_irq(s->irq, !!level);
+    s->irqlevel = level;
+}
+
+/* Set Branch Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_bs_set(struct pxa2xx_lcdc_s *s, int ch)
+{
+    int unmasked;
+    if (ch == 0) {
+        s->status[0] |= LCSR0_BS0;
+        unmasked = !(s->control[0] & LCCR0_BSM0);
+    } else {
+        s->status[1] |= LCSR1_BS(ch);
+        unmasked = !(s->control[5] & LCCR5_BSM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set Start Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_sof_set(struct pxa2xx_lcdc_s *s, int ch)
+{
+    int unmasked;
+    if (!(s->dma_ch[ch].command & LDCMD_SOFINT))
+        return;
+
+    if (ch == 0) {
+        s->status[0] |= LCSR0_SOF0;
+        unmasked = !(s->control[0] & LCCR0_SOFM0);
+    } else {
+        s->status[1] |= LCSR1_SOF(ch);
+        unmasked = !(s->control[5] & LCCR5_SOFM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set End Of Frame Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_eof_set(struct pxa2xx_lcdc_s *s, int ch)
+{
+    int unmasked;
+    if (!(s->dma_ch[ch].command & LDCMD_EOFINT))
+        return;
+
+    if (ch == 0) {
+        s->status[0] |= LCSR0_EOF0;
+        unmasked = !(s->control[0] & LCCR0_EOFM0);
+    } else {
+        s->status[1] |= LCSR1_EOF(ch);
+        unmasked = !(s->control[5] & LCCR5_EOFM(ch));
+    }
+
+    if (unmasked) {
+        if (s->irqlevel)
+            s->status[0] |= LCSR0_SINT;
+        else
+            s->liidr = s->dma_ch[ch].id;
+    }
+}
+
+/* Set Bus Error Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_ber_set(struct pxa2xx_lcdc_s *s, int ch)
+{
+    s->status[0] |= LCSR0_BERCH(ch) | LCSR0_BER;
+    if (s->irqlevel)
+        s->status[0] |= LCSR0_SINT;
+    else
+        s->liidr = s->dma_ch[ch].id;
+}
+
+/* Set Read Status interrupt high and poke associated registers */
+static inline void pxa2xx_dma_rdst_set(struct pxa2xx_lcdc_s *s)
+{
+    s->status[0] |= LCSR0_RDST;
+    if (s->irqlevel && !(s->control[0] & LCCR0_RDSTM))
+        s->status[0] |= LCSR0_SINT;
+}
+
+/* Load new Frame Descriptors from DMA */
+static void pxa2xx_descriptor_load(struct pxa2xx_lcdc_s *s)
+{
+    struct pxa_frame_descriptor_s *desc[PXA_LCDDMA_CHANS];
+    target_phys_addr_t descptr;
+    int i;
+
+    for (i = 0; i < PXA_LCDDMA_CHANS; i ++) {
+        desc[i] = 0;
+        s->dma_ch[i].source = 0;
+
+        if (!s->dma_ch[i].up)
+            continue;
+
+        if (s->dma_ch[i].branch & FBR_BRA) {
+            descptr = s->dma_ch[i].branch & FBR_SRCADDR;
+            if (s->dma_ch[i].branch & FBR_BINT)
+                pxa2xx_dma_bs_set(s, i);
+            s->dma_ch[i].branch &= ~FBR_BRA;
+        } else
+            descptr = s->dma_ch[i].descriptor;
+
+        if (!(descptr >= PXA2XX_SDRAM_BASE && descptr +
+                    sizeof(*desc[i]) <= PXA2XX_SDRAM_BASE + phys_ram_size))
+            continue;
+
+        descptr -= PXA2XX_SDRAM_BASE;
+        desc[i] = (struct pxa_frame_descriptor_s *) (phys_ram_base + descptr);
+        s->dma_ch[i].descriptor = desc[i]->fdaddr;
+        s->dma_ch[i].source = desc[i]->fsaddr;
+        s->dma_ch[i].id = desc[i]->fidr;
+        s->dma_ch[i].command = desc[i]->ldcmd;
+    }
+}
+
+static uint32_t pxa2xx_lcdc_read(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    int ch;
+    offset -= s->base;
+
+    switch (offset) {
+    case LCCR0:
+        return s->control[0];
+    case LCCR1:
+        return s->control[1];
+    case LCCR2:
+        return s->control[2];
+    case LCCR3:
+        return s->control[3];
+    case LCCR4:
+        return s->control[4];
+    case LCCR5:
+        return s->control[5];
+
+    case OVL1C1:
+        return s->ovl1c[0];
+    case OVL1C2:
+        return s->ovl1c[1];
+    case OVL2C1:
+        return s->ovl2c[0];
+    case OVL2C2:
+        return s->ovl2c[1];
+
+    case CCR:
+        return s->ccr;
+
+    case CMDCR:
+        return s->cmdcr;
+
+    case TRGBR:
+        return s->trgbr;
+    case TCR:
+        return s->tcr;
+
+    case 0x200 ... 0x1000:	/* DMA per-channel registers */
+        ch = (offset - 0x200) >> 4;
+        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+            goto fail;
+
+        switch (offset & 0xf) {
+        case DMA_FDADR:
+            return s->dma_ch[ch].descriptor;
+        case DMA_FSADR:
+            return s->dma_ch[ch].source;
+        case DMA_FIDR:
+            return s->dma_ch[ch].id;
+        case DMA_LDCMD:
+            return s->dma_ch[ch].command;
+        default:
+            goto fail;
+        }
+
+    case FBR0:
+        return s->dma_ch[0].branch;
+    case FBR1:
+        return s->dma_ch[1].branch;
+    case FBR2:
+        return s->dma_ch[2].branch;
+    case FBR3:
+        return s->dma_ch[3].branch;
+    case FBR4:
+        return s->dma_ch[4].branch;
+    case FBR5:
+        return s->dma_ch[5].branch;
+    case FBR6:
+        return s->dma_ch[6].branch;
+
+    case BSCNTR:
+        return s->bscntr;
+
+    case PRSR:
+        return 0;
+
+    case LCSR0:
+        return s->status[0];
+    case LCSR1:
+        return s->status[1];
+    case LIIDR:
+        return s->liidr;
+
+    default:
+    fail:
+        cpu_abort(cpu_single_env,
+                "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_lcdc_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    int ch;
+    offset -= s->base;
+
+    switch (offset) {
+    case LCCR0:
+        /* ACK Quick Disable done */
+        if ((s->control[0] & LCCR0_ENB) && !(value & LCCR0_ENB))
+            s->status[0] |= LCSR0_QD;
+
+        if (!(s->control[0] & LCCR0_LCDT) && (value & LCCR0_LCDT))
+            printf("%s: internal frame buffer unsupported\n", __FUNCTION__);
+
+        if ((s->control[3] & LCCR3_API) &&
+                (value & LCCR0_ENB) && !(value & LCCR0_LCDT))
+            s->status[0] |= LCSR0_ABC;
+
+        s->control[0] = value & 0x07ffffff;
+        pxa2xx_lcdc_int_update(s);
+
+        s->dma_ch[0].up = !!(value & LCCR0_ENB);
+        s->dma_ch[1].up = (s->ovl1c[0] & OVLC1_EN) || (value & LCCR0_SDS);
+        break;
+
+    case LCCR1:
+        s->control[1] = value;
+        break;
+
+    case LCCR2:
+        s->control[2] = value;
+        break;
+
+    case LCCR3:
+        s->control[3] = value & 0xefffffff;
+        s->bpp = LCCR3_BPP(value);
+        break;
+
+    case LCCR4:
+        s->control[4] = value & 0x83ff81ff;
+        break;
+
+    case LCCR5:
+        s->control[5] = value & 0x3f3f3f3f;
+        break;
+
+    case OVL1C1:
+        if (!(s->ovl1c[0] & OVLC1_EN) && (value & OVLC1_EN))
+            printf("%s: Overlay 1 not supported\n", __FUNCTION__);
+
+        s->ovl1c[0] = value & 0x80ffffff;
+        s->dma_ch[1].up = (value & OVLC1_EN) || (s->control[0] & LCCR0_SDS);
+        break;
+
+    case OVL1C2:
+        s->ovl1c[1] = value & 0x000fffff;
+        break;
+
+    case OVL2C1:
+        if (!(s->ovl2c[0] & OVLC1_EN) && (value & OVLC1_EN))
+            printf("%s: Overlay 2 not supported\n", __FUNCTION__);
+
+        s->ovl2c[0] = value & 0x80ffffff;
+        s->dma_ch[2].up = !!(value & OVLC1_EN);
+        s->dma_ch[3].up = !!(value & OVLC1_EN);
+        s->dma_ch[4].up = !!(value & OVLC1_EN);
+        break;
+
+    case OVL2C2:
+        s->ovl2c[1] = value & 0x007fffff;
+        break;
+
+    case CCR:
+        if (!(s->ccr & CCR_CEN) && (value & CCR_CEN))
+            printf("%s: Hardware cursor unimplemented\n", __FUNCTION__);
+
+        s->ccr = value & 0x81ffffe7;
+        s->dma_ch[5].up = !!(value & CCR_CEN);
+        break;
+
+    case CMDCR:
+        s->cmdcr = value & 0xff;
+        break;
+
+    case TRGBR:
+        s->trgbr = value & 0x00ffffff;
+        break;
+
+    case TCR:
+        s->tcr = value & 0x7fff;
+        break;
+
+    case 0x200 ... 0x1000:	/* DMA per-channel registers */
+        ch = (offset - 0x200) >> 4;
+        if (!(ch >= 0 && ch < PXA_LCDDMA_CHANS))
+            goto fail;
+
+        switch (offset & 0xf) {
+        case DMA_FDADR:
+            s->dma_ch[ch].descriptor = value & 0xfffffff0;
+            break;
+
+        default:
+            goto fail;
+        }
+        break;
+
+    case FBR0:
+        s->dma_ch[0].branch = value & 0xfffffff3;
+        break;
+    case FBR1:
+        s->dma_ch[1].branch = value & 0xfffffff3;
+        break;
+    case FBR2:
+        s->dma_ch[2].branch = value & 0xfffffff3;
+        break;
+    case FBR3:
+        s->dma_ch[3].branch = value & 0xfffffff3;
+        break;
+    case FBR4:
+        s->dma_ch[4].branch = value & 0xfffffff3;
+        break;
+    case FBR5:
+        s->dma_ch[5].branch = value & 0xfffffff3;
+        break;
+    case FBR6:
+        s->dma_ch[6].branch = value & 0xfffffff3;
+        break;
+
+    case BSCNTR:
+        s->bscntr = value & 0xf;
+        break;
+
+    case PRSR:
+        break;
+
+    case LCSR0:
+        s->status[0] &= ~(value & 0xfff);
+        if (value & LCSR0_BER)
+            s->status[0] &= ~LCSR0_BERCH(7);
+        break;
+
+    case LCSR1:
+        s->status[1] &= ~(value & 0x3e3f3f);
+        break;
+
+    default:
+    fail:
+        cpu_abort(cpu_single_env,
+                "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_lcdc_readfn[] = {
+    pxa2xx_lcdc_read,
+    pxa2xx_lcdc_read,
+    pxa2xx_lcdc_read
+};
+
+static CPUWriteMemoryFunc *pxa2xx_lcdc_writefn[] = {
+    pxa2xx_lcdc_write,
+    pxa2xx_lcdc_write,
+    pxa2xx_lcdc_write
+};
+
+/* Load new palette for a given DMA channel, convert to internal format */
+static void pxa2xx_palette_parse(struct pxa2xx_lcdc_s *s, int ch, int bpp)
+{
+    int i, n, format, r, g, b, alpha;
+    uint32_t *dest, *src;
+    s->pal_for = LCCR4_PALFOR(s->control[4]);
+    format = s->pal_for;
+
+    switch (bpp) {
+    case pxa_lcdc_2bpp:
+        n = 4;
+        break;
+    case pxa_lcdc_4bpp:
+        n = 16;
+        break;
+    case pxa_lcdc_8bpp:
+        n = 256;
+        break;
+    default:
+        format = 0;
+        return;
+    }
+
+    src = (uint32_t *) s->dma_ch[ch].pbuffer;
+    dest = (uint32_t *) s->dma_ch[ch].palette;
+    alpha = r = g = b = 0;
+
+    for (i = 0; i < n; i ++) {
+        switch (format) {
+        case 0: /* 16 bpp, no transparency */
+            alpha = 0;
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *src & 0xff;
+            else {
+                r = (*src & 0xf800) >> 8;
+                g = (*src & 0x07e0) >> 3;
+                b = (*src & 0x001f) << 3;
+            }
+            break;
+        case 1: /* 16 bpp plus transparency */
+            alpha = *src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *src & 0xff;
+            else {
+                r = (*src & 0xf800) >> 8;
+                g = (*src & 0x07e0) >> 3;
+                b = (*src & 0x001f) << 3;
+            }
+            break;
+        case 2: /* 18 bpp plus transparency */
+            alpha = *src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *src & 0xff;
+            else {
+                r = (*src & 0xf80000) >> 16;
+                g = (*src & 0x00fc00) >> 8;
+                b = (*src & 0x0000f8);
+            }
+            break;
+        case 3: /* 24 bpp plus transparency */
+            alpha = *src & (1 << 24);
+            if (s->control[0] & LCCR0_CMS)
+                r = g = b = *src & 0xff;
+            else {
+                r = (*src & 0xff0000) >> 16;
+                g = (*src & 0x00ff00) >> 8;
+                b = (*src & 0x0000ff);
+            }
+            break;
+        }
+        switch (s->ds->depth) {
+        case 8:
+            *dest = rgb_to_pixel8(r, g, b) | alpha;
+            break;
+        case 15:
+            *dest = rgb_to_pixel15(r, g, b) | alpha;
+            break;
+        case 16:
+            *dest = rgb_to_pixel16(r, g, b) | alpha;
+            break;
+        case 24:
+            *dest = rgb_to_pixel24(r, g, b) | alpha;
+            break;
+        case 32:
+            *dest = rgb_to_pixel32(r, g, b) | alpha;
+            break;
+        }
+        src ++;
+        dest ++;
+    }
+}
+
+static void pxa2xx_lcdc_dma0_redraw_horiz(struct pxa2xx_lcdc_s *s,
+                uint8_t *fb, int *miny, int *maxy)
+{
+    int y, src_width, dest_width, dirty[2];
+    uint8_t *src, *dest;
+    ram_addr_t x, addr, new_addr, start, end;
+    drawfn fn = 0;
+    if (s->dest_width)
+        fn = s->line_fn[s->transp][s->bpp];
+    if (!fn)
+        return;
+
+    src = fb;
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
+        src_width *= 3;
+    else if (s->bpp > pxa_lcdc_16bpp)
+        src_width *= 4;
+    else if (s->bpp > pxa_lcdc_8bpp)
+        src_width *= 2;
+
+    dest = s->ds->data;
+    dest_width = s->xres * s->dest_width;
+
+    addr = (ram_addr_t) (fb - phys_ram_base);
+    start = addr + s->yres * src_width;
+    end = addr;
+    dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
+    for (y = 0; y < s->yres; y ++) {
+        new_addr = addr + src_width;
+        for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
+                        x += TARGET_PAGE_SIZE) {
+            dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
+            dirty[0] |= dirty[1];
+        }
+        if (dirty[0] || s->invalidated) {
+            fn((uint32_t *) s->dma_ch[0].palette,
+                            dest, src, s->xres, s->dest_width);
+            if (addr < start)
+                start = addr;
+            end = new_addr;
+            if (y < *miny)
+                *miny = y;
+            if (y >= *maxy)
+                *maxy = y + 1;
+        }
+        addr = new_addr;
+        dirty[0] = dirty[1];
+        src += src_width;
+        dest += dest_width;
+    }
+
+    if (end > start)
+        cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+}
+
+static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s,
+                uint8_t *fb, int *miny, int *maxy)
+{
+    int y, src_width, dest_width, dirty[2];
+    uint8_t *src, *dest;
+    ram_addr_t x, addr, new_addr, start, end;
+    drawfn fn = 0;
+    if (s->dest_width)
+        fn = s->line_fn[s->transp][s->bpp];
+    if (!fn)
+        return;
+
+    src = fb;
+    src_width = (s->xres + 3) & ~3;     /* Pad to a 4 pixels multiple */
+    if (s->bpp == pxa_lcdc_19pbpp || s->bpp == pxa_lcdc_18pbpp)
+        src_width *= 3;
+    else if (s->bpp > pxa_lcdc_16bpp)
+        src_width *= 4;
+    else if (s->bpp > pxa_lcdc_8bpp)
+        src_width *= 2;
+
+    dest_width = s->yres * s->dest_width;
+    dest = s->ds->data + dest_width * (s->xres - 1);
+
+    addr = (ram_addr_t) (fb - phys_ram_base);
+    start = addr + s->yres * src_width;
+    end = addr;
+    dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
+    for (y = 0; y < s->yres; y ++) {
+        new_addr = addr + src_width;
+        for (x = addr + TARGET_PAGE_SIZE; x < new_addr;
+                        x += TARGET_PAGE_SIZE) {
+            dirty[1] = cpu_physical_memory_get_dirty(x, VGA_DIRTY_FLAG);
+            dirty[0] |= dirty[1];
+        }
+        if (dirty[0] || s->invalidated) {
+            fn((uint32_t *) s->dma_ch[0].palette,
+                            dest, src, s->xres, -dest_width);
+            if (addr < start)
+                start = addr;
+            end = new_addr;
+            if (y < *miny)
+                *miny = y;
+            if (y >= *maxy)
+                *maxy = y + 1;
+        }
+        addr = new_addr;
+        dirty[0] = dirty[1];
+        src += src_width;
+        dest += s->dest_width;
+    }
+
+    if (end > start)
+        cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+}
+
+static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
+{
+    int width, height;
+    if (!(s->control[0] & LCCR0_ENB))
+        return;
+
+    width = LCCR1_PPL(s->control[1]) + 1;
+    height = LCCR2_LPP(s->control[2]) + 1;
+
+    if (width != s->xres || height != s->yres) {
+        if (s->orientation)
+            dpy_resize(s->ds, height, width);
+        else
+            dpy_resize(s->ds, width, height);
+        s->invalidated = 1;
+        s->xres = width;
+        s->yres = height;
+    }
+}
+
+static void pxa2xx_update_display(void *opaque)
+{
+    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    uint8_t *fb;
+    target_phys_addr_t fbptr;
+    int miny, maxy;
+    int ch;
+    if (!(s->control[0] & LCCR0_ENB))
+        return;
+
+    pxa2xx_descriptor_load(s);
+
+    pxa2xx_lcdc_resize(s);
+    miny = s->yres;
+    maxy = 0;
+    s->transp = s->dma_ch[2].up || s->dma_ch[3].up;
+    /* Note: With overlay planes the order depends on LCCR0 bit 25.  */
+    for (ch = 0; ch < PXA_LCDDMA_CHANS; ch ++)
+        if (s->dma_ch[ch].up) {
+            if (!s->dma_ch[ch].source) {
+                pxa2xx_dma_ber_set(s, ch);
+                continue;
+            }
+            fbptr = s->dma_ch[ch].source;
+            if (!(fbptr >= PXA2XX_SDRAM_BASE &&
+                    fbptr <= PXA2XX_SDRAM_BASE + phys_ram_size)) {
+                pxa2xx_dma_ber_set(s, ch);
+                continue;
+            }
+            fbptr -= PXA2XX_SDRAM_BASE;
+            fb = phys_ram_base + fbptr;
+
+            if (s->dma_ch[ch].command & LDCMD_PAL) {
+                memcpy(s->dma_ch[ch].pbuffer, fb,
+                                MAX(LDCMD_LENGTH(s->dma_ch[ch].command),
+                                sizeof(s->dma_ch[ch].pbuffer)));
+                pxa2xx_palette_parse(s, ch, s->bpp);
+            } else {
+                /* Do we need to reparse palette */
+                if (LCCR4_PALFOR(s->control[4]) != s->pal_for)
+                    pxa2xx_palette_parse(s, ch, s->bpp);
+
+                /* ACK frame start */
+                pxa2xx_dma_sof_set(s, ch);
+
+                s->dma_ch[ch].redraw(s, fb, &miny, &maxy);
+                s->invalidated = 0;
+
+                /* ACK frame completed */
+                pxa2xx_dma_eof_set(s, ch);
+            }
+        }
+
+    if (s->control[0] & LCCR0_DIS) {
+        /* ACK last frame completed */
+        s->control[0] &= ~LCCR0_ENB;
+        s->status[0] |= LCSR0_LDD;
+    }
+
+    if (s->orientation)
+        dpy_update(s->ds, miny, 0, maxy, s->xres);
+    else
+        dpy_update(s->ds, 0, miny, s->xres, maxy);
+    pxa2xx_lcdc_int_update(s);
+
+    if (s->vsync_cb)
+        s->vsync_cb(s->opaque);
+}
+
+static void pxa2xx_invalidate_display(void *opaque)
+{
+    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    s->invalidated = 1;
+}
+
+static void pxa2xx_screen_dump(void *opaque, const char *filename)
+{
+    /* TODO */
+}
+
+void pxa2xx_lcdc_orientation(void *opaque, int angle)
+{
+    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+
+    if (angle) {
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_vert;
+    } else {
+        s->dma_ch[0].redraw = pxa2xx_lcdc_dma0_redraw_horiz;
+    }
+
+    s->orientation = angle;
+    s->xres = s->yres = -1;
+    pxa2xx_lcdc_resize(s);
+}
+
+static void pxa2xx_lcdc_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    int i;
+
+    qemu_put_be32(f, s->irqlevel);
+    qemu_put_be32(f, s->transp);
+
+    for (i = 0; i < 6; i ++)
+        qemu_put_be32s(f, &s->control[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_be32s(f, &s->status[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_be32s(f, &s->ovl1c[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_be32s(f, &s->ovl2c[i]);
+    qemu_put_be32s(f, &s->ccr);
+    qemu_put_be32s(f, &s->cmdcr);
+    qemu_put_be32s(f, &s->trgbr);
+    qemu_put_be32s(f, &s->tcr);
+    qemu_put_be32s(f, &s->liidr);
+    qemu_put_8s(f, &s->bscntr);
+
+    for (i = 0; i < 7; i ++) {
+        qemu_put_betl(f, s->dma_ch[i].branch);
+        qemu_put_byte(f, s->dma_ch[i].up);
+        qemu_put_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer));
+
+        qemu_put_betl(f, s->dma_ch[i].descriptor);
+        qemu_put_betl(f, s->dma_ch[i].source);
+        qemu_put_be32s(f, &s->dma_ch[i].id);
+        qemu_put_be32s(f, &s->dma_ch[i].command);
+    }
+}
+
+static int pxa2xx_lcdc_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_lcdc_s *s = (struct pxa2xx_lcdc_s *) opaque;
+    int i;
+
+    s->irqlevel = qemu_get_be32(f);
+    s->transp = qemu_get_be32(f);
+
+    for (i = 0; i < 6; i ++)
+        qemu_get_be32s(f, &s->control[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_be32s(f, &s->status[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_be32s(f, &s->ovl1c[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_be32s(f, &s->ovl2c[i]);
+    qemu_get_be32s(f, &s->ccr);
+    qemu_get_be32s(f, &s->cmdcr);
+    qemu_get_be32s(f, &s->trgbr);
+    qemu_get_be32s(f, &s->tcr);
+    qemu_get_be32s(f, &s->liidr);
+    qemu_get_8s(f, &s->bscntr);
+
+    for (i = 0; i < 7; i ++) {
+        s->dma_ch[i].branch = qemu_get_betl(f);
+        s->dma_ch[i].up = qemu_get_byte(f);
+        qemu_get_buffer(f, s->dma_ch[i].pbuffer, sizeof(s->dma_ch[i].pbuffer));
+
+        s->dma_ch[i].descriptor = qemu_get_betl(f);
+        s->dma_ch[i].source = qemu_get_betl(f);
+        qemu_get_be32s(f, &s->dma_ch[i].id);
+        qemu_get_be32s(f, &s->dma_ch[i].command);
+    }
+
+    s->bpp = LCCR3_BPP(s->control[3]);
+    s->xres = s->yres = s->pal_for = -1;
+
+    return 0;
+}
+
+#define BITS 8
+#include "pxa2xx_template.h"
+#define BITS 15
+#include "pxa2xx_template.h"
+#define BITS 16
+#include "pxa2xx_template.h"
+#define BITS 24
+#include "pxa2xx_template.h"
+#define BITS 32
+#include "pxa2xx_template.h"
+
+struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq,
+                DisplayState *ds)
+{
+    int iomemtype;
+    struct pxa2xx_lcdc_s *s;
+
+    s = (struct pxa2xx_lcdc_s *) qemu_mallocz(sizeof(struct pxa2xx_lcdc_s));
+    s->base = base;
+    s->invalidated = 1;
+    s->irq = irq;
+    s->ds = ds;
+
+    pxa2xx_lcdc_orientation(s, graphic_rotate);
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_lcdc_readfn,
+                    pxa2xx_lcdc_writefn, s);
+    cpu_register_physical_memory(base, 0x00100000, iomemtype);
+
+    graphic_console_init(ds, pxa2xx_update_display,
+                    pxa2xx_invalidate_display, pxa2xx_screen_dump, s);
+
+    switch (s->ds->depth) {
+    case 0:
+        s->dest_width = 0;
+        break;
+    case 8:
+        s->line_fn[0] = pxa2xx_draw_fn_8;
+        s->line_fn[1] = pxa2xx_draw_fn_8t;
+        s->dest_width = 1;
+        break;
+    case 15:
+        s->line_fn[0] = pxa2xx_draw_fn_15;
+        s->line_fn[1] = pxa2xx_draw_fn_15t;
+        s->dest_width = 2;
+        break;
+    case 16:
+        s->line_fn[0] = pxa2xx_draw_fn_16;
+        s->line_fn[1] = pxa2xx_draw_fn_16t;
+        s->dest_width = 2;
+        break;
+    case 24:
+        s->line_fn[0] = pxa2xx_draw_fn_24;
+        s->line_fn[1] = pxa2xx_draw_fn_24t;
+        s->dest_width = 3;
+        break;
+    case 32:
+        s->line_fn[0] = pxa2xx_draw_fn_32;
+        s->line_fn[1] = pxa2xx_draw_fn_32t;
+        s->dest_width = 4;
+        break;
+    default:
+        fprintf(stderr, "%s: Bad color depth\n", __FUNCTION__);
+        exit(1);
+    }
+
+    register_savevm("pxa2xx_lcdc", 0, 0,
+                    pxa2xx_lcdc_save, pxa2xx_lcdc_load, s);
+
+    return s;
+}
+
+void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s,
+                void (*cb)(void *opaque), void *opaque) {
+    s->vsync_cb = cb;
+    s->opaque = opaque;
+}
diff --git a/hw/pxa2xx_mmci.c b/hw/pxa2xx_mmci.c
new file mode 100644
index 0000000..ed548db
--- /dev/null
+++ b/hw/pxa2xx_mmci.c
@@ -0,0 +1,553 @@
+/*
+ * Intel XScale PXA255/270 MultiMediaCard/SD/SDIO Controller emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "vl.h"
+#include "sd.h"
+
+struct pxa2xx_mmci_s {
+    target_phys_addr_t base;
+    qemu_irq irq;
+    void *dma;
+
+    SDState *card;
+
+    uint32_t status;
+    uint32_t clkrt;
+    uint32_t spi;
+    uint32_t cmdat;
+    uint32_t resp_tout;
+    uint32_t read_tout;
+    int blklen;
+    int numblk;
+    uint32_t intmask;
+    uint32_t intreq;
+    int cmd;
+    uint32_t arg;
+
+    int active;
+    int bytesleft;
+    uint8_t tx_fifo[64];
+    int tx_start;
+    int tx_len;
+    uint8_t rx_fifo[32];
+    int rx_start;
+    int rx_len;
+    uint16_t resp_fifo[9];
+    int resp_len;
+
+    int cmdreq;
+    int ac_width;
+};
+
+#define MMC_STRPCL	0x00	/* MMC Clock Start/Stop register */
+#define MMC_STAT	0x04	/* MMC Status register */
+#define MMC_CLKRT	0x08	/* MMC Clock Rate register */
+#define MMC_SPI		0x0c	/* MMC SPI Mode register */
+#define MMC_CMDAT	0x10	/* MMC Command/Data register */
+#define MMC_RESTO	0x14	/* MMC Response Time-Out register */
+#define MMC_RDTO	0x18	/* MMC Read Time-Out register */
+#define MMC_BLKLEN	0x1c	/* MMC Block Length register */
+#define MMC_NUMBLK	0x20	/* MMC Number of Blocks register */
+#define MMC_PRTBUF	0x24	/* MMC Buffer Partly Full register */
+#define MMC_I_MASK	0x28	/* MMC Interrupt Mask register */
+#define MMC_I_REG	0x2c	/* MMC Interrupt Request register */
+#define MMC_CMD		0x30	/* MMC Command register */
+#define MMC_ARGH	0x34	/* MMC Argument High register */
+#define MMC_ARGL	0x38	/* MMC Argument Low register */
+#define MMC_RES		0x3c	/* MMC Response FIFO */
+#define MMC_RXFIFO	0x40	/* MMC Receive FIFO */
+#define MMC_TXFIFO	0x44	/* MMC Transmit FIFO */
+#define MMC_RDWAIT	0x48	/* MMC RD_WAIT register */
+#define MMC_BLKS_REM	0x4c	/* MMC Blocks Remaining register */
+
+/* Bitfield masks */
+#define STRPCL_STOP_CLK	(1 << 0)
+#define STRPCL_STRT_CLK	(1 << 1)
+#define STAT_TOUT_RES	(1 << 1)
+#define STAT_CLK_EN	(1 << 8)
+#define STAT_DATA_DONE	(1 << 11)
+#define STAT_PRG_DONE	(1 << 12)
+#define STAT_END_CMDRES	(1 << 13)
+#define SPI_SPI_MODE	(1 << 0)
+#define CMDAT_RES_TYPE	(3 << 0)
+#define CMDAT_DATA_EN	(1 << 2)
+#define CMDAT_WR_RD	(1 << 3)
+#define CMDAT_DMA_EN	(1 << 7)
+#define CMDAT_STOP_TRAN	(1 << 10)
+#define INT_DATA_DONE	(1 << 0)
+#define INT_PRG_DONE	(1 << 1)
+#define INT_END_CMD	(1 << 2)
+#define INT_STOP_CMD	(1 << 3)
+#define INT_CLK_OFF	(1 << 4)
+#define INT_RXFIFO_REQ	(1 << 5)
+#define INT_TXFIFO_REQ	(1 << 6)
+#define INT_TINT	(1 << 7)
+#define INT_DAT_ERR	(1 << 8)
+#define INT_RES_ERR	(1 << 9)
+#define INT_RD_STALLED	(1 << 10)
+#define INT_SDIO_INT	(1 << 11)
+#define INT_SDIO_SACK	(1 << 12)
+#define PRTBUF_PRT_BUF	(1 << 0)
+
+/* Route internal interrupt lines to the global IC and DMA */
+static void pxa2xx_mmci_int_update(struct pxa2xx_mmci_s *s)
+{
+    uint32_t mask = s->intmask;
+    if (s->cmdat & CMDAT_DMA_EN) {
+        mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
+
+        pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma,
+                        PXA2XX_RX_RQ_MMCI, !!(s->intreq & INT_RXFIFO_REQ));
+        pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma,
+                        PXA2XX_TX_RQ_MMCI, !!(s->intreq & INT_TXFIFO_REQ));
+    }
+
+    qemu_set_irq(s->irq, !!(s->intreq & ~mask));
+}
+
+static void pxa2xx_mmci_fifo_update(struct pxa2xx_mmci_s *s)
+{
+    if (!s->active)
+        return;
+
+    if (s->cmdat & CMDAT_WR_RD) {
+        while (s->bytesleft && s->tx_len) {
+            sd_write_data(s->card, s->tx_fifo[s->tx_start ++]);
+            s->tx_start &= 0x1f;
+            s->tx_len --;
+            s->bytesleft --;
+        }
+        if (s->bytesleft)
+            s->intreq |= INT_TXFIFO_REQ;
+    } else
+        while (s->bytesleft && s->rx_len < 32) {
+            s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
+                sd_read_data(s->card);
+            s->bytesleft --;
+            s->intreq |= INT_RXFIFO_REQ;
+        }
+
+    if (!s->bytesleft) {
+        s->active = 0;
+        s->intreq |= INT_DATA_DONE;
+        s->status |= STAT_DATA_DONE;
+
+        if (s->cmdat & CMDAT_WR_RD) {
+            s->intreq |= INT_PRG_DONE;
+            s->status |= STAT_PRG_DONE;
+        }
+    }
+
+    pxa2xx_mmci_int_update(s);
+}
+
+static void pxa2xx_mmci_wakequeues(struct pxa2xx_mmci_s *s)
+{
+    int rsplen, i;
+    struct sd_request_s request;
+    uint8_t response[16];
+
+    s->active = 1;
+    s->rx_len = 0;
+    s->tx_len = 0;
+    s->cmdreq = 0;
+
+    request.cmd = s->cmd;
+    request.arg = s->arg;
+    request.crc = 0;	/* FIXME */
+
+    rsplen = sd_do_command(s->card, &request, response);
+    s->intreq |= INT_END_CMD;
+
+    memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
+    switch (s->cmdat & CMDAT_RES_TYPE) {
+#define PXAMMCI_RESP(wd, value0, value1)	\
+        s->resp_fifo[(wd) + 0] |= (value0);	\
+        s->resp_fifo[(wd) + 1] |= (value1) << 8;
+    case 0:	/* No response */
+        goto complete;
+
+    case 1:	/* R1, R4, R5 or R6 */
+        if (rsplen < 4)
+            goto timeout;
+        goto complete;
+
+    case 2:	/* R2 */
+        if (rsplen < 16)
+            goto timeout;
+        goto complete;
+
+    case 3:	/* R3 */
+        if (rsplen < 4)
+            goto timeout;
+        goto complete;
+
+    complete:
+        for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
+            PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
+        }
+        s->status |= STAT_END_CMDRES;
+
+        if (!(s->cmdat & CMDAT_DATA_EN))
+            s->active = 0;
+        else
+            s->bytesleft = s->numblk * s->blklen;
+
+        s->resp_len = 0;
+        break;
+
+    timeout:
+        s->active = 0;
+        s->status |= STAT_TOUT_RES;
+        break;
+    }
+
+    pxa2xx_mmci_fifo_update(s);
+}
+
+static uint32_t pxa2xx_mmci_read(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    uint32_t ret;
+    offset -= s->base;
+
+    switch (offset) {
+    case MMC_STRPCL:
+        return 0;
+    case MMC_STAT:
+        return s->status;
+    case MMC_CLKRT:
+        return s->clkrt;
+    case MMC_SPI:
+        return s->spi;
+    case MMC_CMDAT:
+        return s->cmdat;
+    case MMC_RESTO:
+        return s->resp_tout;
+    case MMC_RDTO:
+        return s->read_tout;
+    case MMC_BLKLEN:
+        return s->blklen;
+    case MMC_NUMBLK:
+        return s->numblk;
+    case MMC_PRTBUF:
+        return 0;
+    case MMC_I_MASK:
+        return s->intmask;
+    case MMC_I_REG:
+        return s->intreq;
+    case MMC_CMD:
+        return s->cmd | 0x40;
+    case MMC_ARGH:
+        return s->arg >> 16;
+    case MMC_ARGL:
+        return s->arg & 0xffff;
+    case MMC_RES:
+        if (s->resp_len < 9)
+            return s->resp_fifo[s->resp_len ++];
+        return 0;
+    case MMC_RXFIFO:
+        ret = 0;
+        while (s->ac_width -- && s->rx_len) {
+            ret |= s->rx_fifo[s->rx_start ++] << (s->ac_width << 3);
+            s->rx_start &= 0x1f;
+            s->rx_len --;
+        }
+        s->intreq &= ~INT_RXFIFO_REQ;
+        pxa2xx_mmci_fifo_update(s);
+        return ret;
+    case MMC_RDWAIT:
+        return 0;
+    case MMC_BLKS_REM:
+        return s->numblk;
+    default:
+        cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n",
+                        __FUNCTION__, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_mmci_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case MMC_STRPCL:
+        if (value & STRPCL_STRT_CLK) {
+            s->status |= STAT_CLK_EN;
+            s->intreq &= ~INT_CLK_OFF;
+
+            if (s->cmdreq && !(s->cmdat & CMDAT_STOP_TRAN)) {
+                s->status &= STAT_CLK_EN;
+                pxa2xx_mmci_wakequeues(s);
+            }
+        }
+
+        if (value & STRPCL_STOP_CLK) {
+            s->status &= ~STAT_CLK_EN;
+            s->intreq |= INT_CLK_OFF;
+            s->active = 0;
+        }
+
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_CLKRT:
+        s->clkrt = value & 7;
+        break;
+
+    case MMC_SPI:
+        s->spi = value & 0xf;
+        if (value & SPI_SPI_MODE)
+            printf("%s: attempted to use card in SPI mode\n", __FUNCTION__);
+        break;
+
+    case MMC_CMDAT:
+        s->cmdat = value & 0x3dff;
+        s->active = 0;
+        s->cmdreq = 1;
+        if (!(value & CMDAT_STOP_TRAN)) {
+            s->status &= STAT_CLK_EN;
+
+            if (s->status & STAT_CLK_EN)
+                pxa2xx_mmci_wakequeues(s);
+        }
+
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_RESTO:
+        s->resp_tout = value & 0x7f;
+        break;
+
+    case MMC_RDTO:
+        s->read_tout = value & 0xffff;
+        break;
+
+    case MMC_BLKLEN:
+        s->blklen = value & 0xfff;
+        break;
+
+    case MMC_NUMBLK:
+        s->numblk = value & 0xffff;
+        break;
+
+    case MMC_PRTBUF:
+        if (value & PRTBUF_PRT_BUF) {
+            s->tx_start ^= 32;
+            s->tx_len = 0;
+        }
+        pxa2xx_mmci_fifo_update(s);
+        break;
+
+    case MMC_I_MASK:
+        s->intmask = value & 0x1fff;
+        pxa2xx_mmci_int_update(s);
+        break;
+
+    case MMC_CMD:
+        s->cmd = value & 0x3f;
+        break;
+
+    case MMC_ARGH:
+        s->arg &= 0x0000ffff;
+        s->arg |= value << 16;
+        break;
+
+    case MMC_ARGL:
+        s->arg &= 0xffff0000;
+        s->arg |= value & 0x0000ffff;
+        break;
+
+    case MMC_TXFIFO:
+        while (s->ac_width -- && s->tx_len < 0x20)
+            s->tx_fifo[(s->tx_start + (s->tx_len ++)) & 0x1f] =
+                    (value >> (s->ac_width << 3)) & 0xff;
+        s->intreq &= ~INT_TXFIFO_REQ;
+        pxa2xx_mmci_fifo_update(s);
+        break;
+
+    case MMC_RDWAIT:
+    case MMC_BLKS_REM:
+        break;
+
+    default:
+        cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n",
+                        __FUNCTION__, offset);
+    }
+}
+
+static uint32_t pxa2xx_mmci_readb(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    s->ac_width = 1;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static uint32_t pxa2xx_mmci_readh(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    s->ac_width = 2;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static uint32_t pxa2xx_mmci_readw(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    s->ac_width = 4;
+    return pxa2xx_mmci_read(opaque, offset);
+}
+
+static CPUReadMemoryFunc *pxa2xx_mmci_readfn[] = {
+    pxa2xx_mmci_readb,
+    pxa2xx_mmci_readh,
+    pxa2xx_mmci_readw
+};
+
+static void pxa2xx_mmci_writeb(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    s->ac_width = 1;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static void pxa2xx_mmci_writeh(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    s->ac_width = 2;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static void pxa2xx_mmci_writew(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    s->ac_width = 4;
+    pxa2xx_mmci_write(opaque, offset, value);
+}
+
+static CPUWriteMemoryFunc *pxa2xx_mmci_writefn[] = {
+    pxa2xx_mmci_writeb,
+    pxa2xx_mmci_writeh,
+    pxa2xx_mmci_writew
+};
+
+static void pxa2xx_mmci_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    int i;
+
+    qemu_put_be32s(f, &s->status);
+    qemu_put_be32s(f, &s->clkrt);
+    qemu_put_be32s(f, &s->spi);
+    qemu_put_be32s(f, &s->cmdat);
+    qemu_put_be32s(f, &s->resp_tout);
+    qemu_put_be32s(f, &s->read_tout);
+    qemu_put_be32(f, s->blklen);
+    qemu_put_be32(f, s->numblk);
+    qemu_put_be32s(f, &s->intmask);
+    qemu_put_be32s(f, &s->intreq);
+    qemu_put_be32(f, s->cmd);
+    qemu_put_be32s(f, &s->arg);
+    qemu_put_be32(f, s->cmdreq);
+    qemu_put_be32(f, s->active);
+    qemu_put_be32(f, s->bytesleft);
+
+    qemu_put_byte(f, s->tx_len);
+    for (i = 0; i < s->tx_len; i ++)
+        qemu_put_byte(f, s->tx_fifo[(s->tx_start + i) & 63]);
+
+    qemu_put_byte(f, s->rx_len);
+    for (i = 0; i < s->rx_len; i ++)
+        qemu_put_byte(f, s->rx_fifo[(s->rx_start + i) & 31]);
+
+    qemu_put_byte(f, s->resp_len);
+    for (i = s->resp_len; i < 9; i ++)
+        qemu_put_be16s(f, &s->resp_fifo[i]);
+}
+
+static int pxa2xx_mmci_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_mmci_s *s = (struct pxa2xx_mmci_s *) opaque;
+    int i;
+
+    qemu_get_be32s(f, &s->status);
+    qemu_get_be32s(f, &s->clkrt);
+    qemu_get_be32s(f, &s->spi);
+    qemu_get_be32s(f, &s->cmdat);
+    qemu_get_be32s(f, &s->resp_tout);
+    qemu_get_be32s(f, &s->read_tout);
+    s->blklen = qemu_get_be32(f);
+    s->numblk = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->intmask);
+    qemu_get_be32s(f, &s->intreq);
+    s->cmd = qemu_get_be32(f);
+    qemu_get_be32s(f, &s->arg);
+    s->cmdreq = qemu_get_be32(f);
+    s->active = qemu_get_be32(f);
+    s->bytesleft = qemu_get_be32(f);
+
+    s->tx_len = qemu_get_byte(f);
+    s->tx_start = 0;
+    if (s->tx_len >= sizeof(s->tx_fifo) || s->tx_len < 0)
+        return -EINVAL;
+    for (i = 0; i < s->tx_len; i ++)
+        s->tx_fifo[i] = qemu_get_byte(f);
+
+    s->rx_len = qemu_get_byte(f);
+    s->rx_start = 0;
+    if (s->rx_len >= sizeof(s->rx_fifo) || s->rx_len < 0)
+        return -EINVAL;
+    for (i = 0; i < s->rx_len; i ++)
+        s->rx_fifo[i] = qemu_get_byte(f);
+
+    s->resp_len = qemu_get_byte(f);
+    if (s->resp_len > 9 || s->resp_len < 0)
+        return -EINVAL;
+    for (i = s->resp_len; i < 9; i ++)
+         qemu_get_be16s(f, &s->resp_fifo[i]);
+
+    return 0;
+}
+
+struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base,
+                qemu_irq irq, void *dma)
+{
+    int iomemtype;
+    struct pxa2xx_mmci_s *s;
+
+    s = (struct pxa2xx_mmci_s *) qemu_mallocz(sizeof(struct pxa2xx_mmci_s));
+    s->base = base;
+    s->irq = irq;
+    s->dma = dma;
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_mmci_readfn,
+                    pxa2xx_mmci_writefn, s);
+    cpu_register_physical_memory(base, 0x00100000, iomemtype);
+
+    /* Instantiate the actual storage */
+    s->card = sd_init(sd_bdrv);
+
+    register_savevm("pxa2xx_mmci", 0, 0,
+                    pxa2xx_mmci_save, pxa2xx_mmci_load, s);
+
+    return s;
+}
+
+void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque,
+                void (*readonly_cb)(void *, int),
+                void (*coverswitch_cb)(void *, int))
+{
+    sd_set_cb(s->card, opaque, readonly_cb, coverswitch_cb);
+}
diff --git a/hw/pxa2xx_pcmcia.c b/hw/pxa2xx_pcmcia.c
new file mode 100644
index 0000000..f1399f4
--- /dev/null
+++ b/hw/pxa2xx_pcmcia.c
@@ -0,0 +1,225 @@
+/*
+ * Intel XScale PXA255/270 PC Card and CompactFlash Interface.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ */
+
+#include "vl.h"
+
+struct pxa2xx_pcmcia_s {
+    struct pcmcia_socket_s slot;
+    struct pcmcia_card_s *card;
+    target_phys_addr_t common_base;
+    target_phys_addr_t attr_base;
+    target_phys_addr_t io_base;
+
+    qemu_irq irq;
+    qemu_irq cd_irq;
+};
+
+static uint32_t pxa2xx_pcmcia_common_read(void *opaque,
+                target_phys_addr_t offset)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+    if (s->slot.attached) {
+        offset -= s->common_base;
+        return s->card->common_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_common_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+    if (s->slot.attached) {
+        offset -= s->common_base;
+        s->card->common_write(s->card->state, offset, value);
+    }
+}
+
+static uint32_t pxa2xx_pcmcia_attr_read(void *opaque,
+                target_phys_addr_t offset)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+    if (s->slot.attached) {
+        offset -= s->attr_base;
+        return s->card->attr_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_attr_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+    if (s->slot.attached) {
+        offset -= s->attr_base;
+        s->card->attr_write(s->card->state, offset, value);
+    }
+}
+
+static uint32_t pxa2xx_pcmcia_io_read(void *opaque,
+                target_phys_addr_t offset)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+    if (s->slot.attached) {
+        offset -= s->io_base;
+        return s->card->io_read(s->card->state, offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_pcmcia_io_write(void *opaque,
+                target_phys_addr_t offset, uint32_t value)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+
+    if (s->slot.attached) {
+        offset -= s->io_base;
+        s->card->io_write(s->card->state, offset, value);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_pcmcia_common_readfn[] = {
+    pxa2xx_pcmcia_common_read,
+    pxa2xx_pcmcia_common_read,
+    pxa2xx_pcmcia_common_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pcmcia_common_writefn[] = {
+    pxa2xx_pcmcia_common_write,
+    pxa2xx_pcmcia_common_write,
+    pxa2xx_pcmcia_common_write,
+};
+
+static CPUReadMemoryFunc *pxa2xx_pcmcia_attr_readfn[] = {
+    pxa2xx_pcmcia_attr_read,
+    pxa2xx_pcmcia_attr_read,
+    pxa2xx_pcmcia_attr_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pcmcia_attr_writefn[] = {
+    pxa2xx_pcmcia_attr_write,
+    pxa2xx_pcmcia_attr_write,
+    pxa2xx_pcmcia_attr_write,
+};
+
+static CPUReadMemoryFunc *pxa2xx_pcmcia_io_readfn[] = {
+    pxa2xx_pcmcia_io_read,
+    pxa2xx_pcmcia_io_read,
+    pxa2xx_pcmcia_io_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pcmcia_io_writefn[] = {
+    pxa2xx_pcmcia_io_write,
+    pxa2xx_pcmcia_io_write,
+    pxa2xx_pcmcia_io_write,
+};
+
+static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+    if (!s->irq)
+        return;
+
+    qemu_set_irq(s->irq, level);
+}
+
+struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base)
+{
+    int iomemtype;
+    struct pxa2xx_pcmcia_s *s;
+
+    s = (struct pxa2xx_pcmcia_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_pcmcia_s));
+
+    /* Socket I/O Memory Space */
+    s->io_base = base | 0x00000000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_io_readfn,
+                    pxa2xx_pcmcia_io_writefn, s);
+    cpu_register_physical_memory(s->io_base, 0x04000000, iomemtype);
+
+    /* Then next 64 MB is reserved */
+
+    /* Socket Attribute Memory Space */
+    s->attr_base = base | 0x08000000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_attr_readfn,
+                    pxa2xx_pcmcia_attr_writefn, s);
+    cpu_register_physical_memory(s->attr_base, 0x04000000, iomemtype);
+
+    /* Socket Common Memory Space */
+    s->common_base = base | 0x0c000000;
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pcmcia_common_readfn,
+                    pxa2xx_pcmcia_common_writefn, s);
+    cpu_register_physical_memory(s->common_base, 0x04000000, iomemtype);
+
+    if (base == 0x30000000)
+        s->slot.slot_string = "PXA PC Card Socket 1";
+    else
+        s->slot.slot_string = "PXA PC Card Socket 0";
+    s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
+    pcmcia_socket_register(&s->slot);
+
+    return s;
+}
+
+/* Insert a new card into a slot */
+int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+    if (s->slot.attached)
+        return -EEXIST;
+
+    if (s->cd_irq) {
+        qemu_irq_raise(s->cd_irq);
+    }
+
+    s->card = card;
+
+    s->slot.attached = 1;
+    s->card->slot = &s->slot;
+    s->card->attach(s->card->state);
+
+    return 0;
+}
+
+/* Eject card from the slot */
+int pxa2xx_pcmcia_dettach(void *opaque)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+    if (!s->slot.attached)
+        return -ENOENT;
+
+    s->card->detach(s->card->state);
+    s->card->slot = 0;
+    s->card = 0;
+
+    s->slot.attached = 0;
+
+    if (s->irq)
+        qemu_irq_lower(s->irq);
+    if (s->cd_irq)
+        qemu_irq_lower(s->cd_irq);
+
+    return 0;
+}
+
+/* Who to notify on card events */
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
+{
+    struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
+    s->irq = irq;
+    s->cd_irq = cd_irq;
+}
diff --git a/hw/pxa2xx_pic.c b/hw/pxa2xx_pic.c
new file mode 100644
index 0000000..c9012e8
--- /dev/null
+++ b/hw/pxa2xx_pic.c
@@ -0,0 +1,317 @@
+/*
+ * Intel XScale PXA Programmable Interrupt Controller.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+
+#define ICIP	0x00	/* Interrupt Controller IRQ Pending register */
+#define ICMR	0x04	/* Interrupt Controller Mask register */
+#define ICLR	0x08	/* Interrupt Controller Level register */
+#define ICFP	0x0c	/* Interrupt Controller FIQ Pending register */
+#define ICPR	0x10	/* Interrupt Controller Pending register */
+#define ICCR	0x14	/* Interrupt Controller Control register */
+#define ICHP	0x18	/* Interrupt Controller Highest Priority register */
+#define IPR0	0x1c	/* Interrupt Controller Priority register 0 */
+#define IPR31	0x98	/* Interrupt Controller Priority register 31 */
+#define ICIP2	0x9c	/* Interrupt Controller IRQ Pending register 2 */
+#define ICMR2	0xa0	/* Interrupt Controller Mask register 2 */
+#define ICLR2	0xa4	/* Interrupt Controller Level register 2 */
+#define ICFP2	0xa8	/* Interrupt Controller FIQ Pending register 2 */
+#define ICPR2	0xac	/* Interrupt Controller Pending register 2 */
+#define IPR32	0xb0	/* Interrupt Controller Priority register 32 */
+#define IPR39	0xcc	/* Interrupt Controller Priority register 39 */
+
+#define PXA2XX_PIC_SRCS	40
+
+struct pxa2xx_pic_state_s {
+    target_phys_addr_t base;
+    CPUState *cpu_env;
+    uint32_t int_enabled[2];
+    uint32_t int_pending[2];
+    uint32_t is_fiq[2];
+    uint32_t int_idle;
+    uint32_t priority[PXA2XX_PIC_SRCS];
+};
+
+static void pxa2xx_pic_update(void *opaque)
+{
+    uint32_t mask[2];
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+
+    if (s->cpu_env->halted) {
+        mask[0] = s->int_pending[0] & (s->int_enabled[0] | s->int_idle);
+        mask[1] = s->int_pending[1] & (s->int_enabled[1] | s->int_idle);
+        if (mask[0] || mask[1])
+            cpu_interrupt(s->cpu_env, CPU_INTERRUPT_EXITTB);
+    }
+
+    mask[0] = s->int_pending[0] & s->int_enabled[0];
+    mask[1] = s->int_pending[1] & s->int_enabled[1];
+
+    if ((mask[0] & s->is_fiq[0]) || (mask[1] & s->is_fiq[1]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+    else
+        cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+
+    if ((mask[0] & ~s->is_fiq[0]) || (mask[1] & ~s->is_fiq[1]))
+        cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+    else
+        cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+}
+
+/* Note: Here level means state of the signal on a pin, not
+ * IRQ/FIQ distinction as in PXA Developer Manual.  */
+static void pxa2xx_pic_set_irq(void *opaque, int irq, int level)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    int int_set = (irq >= 32);
+    irq &= 31;
+
+    if (level)
+        s->int_pending[int_set] |= 1 << irq;
+    else
+        s->int_pending[int_set] &= ~(1 << irq);
+
+    pxa2xx_pic_update(opaque);
+}
+
+static inline uint32_t pxa2xx_pic_highest(struct pxa2xx_pic_state_s *s) {
+    int i, int_set, irq;
+    uint32_t bit, mask[2];
+    uint32_t ichp = 0x003f003f;	/* Both IDs invalid */
+
+    mask[0] = s->int_pending[0] & s->int_enabled[0];
+    mask[1] = s->int_pending[1] & s->int_enabled[1];
+
+    for (i = PXA2XX_PIC_SRCS - 1; i >= 0; i --) {
+        irq = s->priority[i] & 0x3f;
+        if ((s->priority[i] & (1 << 31)) && irq < PXA2XX_PIC_SRCS) {
+            /* Source peripheral ID is valid.  */
+            bit = 1 << (irq & 31);
+            int_set = (irq >= 32);
+
+            if (mask[int_set] & bit & s->is_fiq[int_set]) {
+                /* FIQ asserted */
+                ichp &= 0xffff0000;
+                ichp |= (1 << 15) | irq;
+            }
+
+            if (mask[int_set] & bit & ~s->is_fiq[int_set]) {
+                /* IRQ asserted */
+                ichp &= 0x0000ffff;
+                ichp |= (1 << 31) | (irq << 16);
+            }
+        }
+    }
+
+    return ichp;
+}
+
+static uint32_t pxa2xx_pic_mem_read(void *opaque, target_phys_addr_t offset)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case ICIP:	/* IRQ Pending register */
+        return s->int_pending[0] & ~s->is_fiq[0] & s->int_enabled[0];
+    case ICIP2:	/* IRQ Pending register 2 */
+        return s->int_pending[1] & ~s->is_fiq[1] & s->int_enabled[1];
+    case ICMR:	/* Mask register */
+        return s->int_enabled[0];
+    case ICMR2:	/* Mask register 2 */
+        return s->int_enabled[1];
+    case ICLR:	/* Level register */
+        return s->is_fiq[0];
+    case ICLR2:	/* Level register 2 */
+        return s->is_fiq[1];
+    case ICCR:	/* Idle mask */
+        return (s->int_idle == 0);
+    case ICFP:	/* FIQ Pending register */
+        return s->int_pending[0] & s->is_fiq[0] & s->int_enabled[0];
+    case ICFP2:	/* FIQ Pending register 2 */
+        return s->int_pending[1] & s->is_fiq[1] & s->int_enabled[1];
+    case ICPR:	/* Pending register */
+        return s->int_pending[0];
+    case ICPR2:	/* Pending register 2 */
+        return s->int_pending[1];
+    case IPR0  ... IPR31:
+        return s->priority[0  + ((offset - IPR0 ) >> 2)];
+    case IPR32 ... IPR39:
+        return s->priority[32 + ((offset - IPR32) >> 2)];
+    case ICHP:	/* Highest Priority register */
+        return pxa2xx_pic_highest(s);
+    default:
+        printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
+        return 0;
+    }
+}
+
+static void pxa2xx_pic_mem_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    offset -= s->base;
+
+    switch (offset) {
+    case ICMR:	/* Mask register */
+        s->int_enabled[0] = value;
+        break;
+    case ICMR2:	/* Mask register 2 */
+        s->int_enabled[1] = value;
+        break;
+    case ICLR:	/* Level register */
+        s->is_fiq[0] = value;
+        break;
+    case ICLR2:	/* Level register 2 */
+        s->is_fiq[1] = value;
+        break;
+    case ICCR:	/* Idle mask */
+        s->int_idle = (value & 1) ? 0 : ~0;
+        break;
+    case IPR0  ... IPR31:
+        s->priority[0  + ((offset - IPR0 ) >> 2)] = value & 0x8000003f;
+        break;
+    case IPR32 ... IPR39:
+        s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
+        break;
+    default:
+        printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
+        return;
+    }
+    pxa2xx_pic_update(opaque);
+}
+
+/* Interrupt Controller Coprocessor Space Register Mapping */
+static const int pxa2xx_cp_reg_map[0x10] = {
+    [0x0 ... 0xf] = -1,
+    [0x0] = ICIP,
+    [0x1] = ICMR,
+    [0x2] = ICLR,
+    [0x3] = ICFP,
+    [0x4] = ICPR,
+    [0x5] = ICHP,
+    [0x6] = ICIP2,
+    [0x7] = ICMR2,
+    [0x8] = ICLR2,
+    [0x9] = ICFP2,
+    [0xa] = ICPR2,
+};
+
+static uint32_t pxa2xx_pic_cp_read(void *opaque, int op2, int reg, int crm)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    target_phys_addr_t offset;
+
+    if (pxa2xx_cp_reg_map[reg] == -1) {
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        return 0;
+    }
+
+    offset = s->base + pxa2xx_cp_reg_map[reg];
+    return pxa2xx_pic_mem_read(opaque, offset);
+}
+
+static void pxa2xx_pic_cp_write(void *opaque, int op2, int reg, int crm,
+                uint32_t value)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    target_phys_addr_t offset;
+
+    if (pxa2xx_cp_reg_map[reg] == -1) {
+        printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+        return;
+    }
+
+    offset = s->base + pxa2xx_cp_reg_map[reg];
+    pxa2xx_pic_mem_write(opaque, offset, value);
+}
+
+static CPUReadMemoryFunc *pxa2xx_pic_readfn[] = {
+    pxa2xx_pic_mem_read,
+    pxa2xx_pic_mem_read,
+    pxa2xx_pic_mem_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pic_writefn[] = {
+    pxa2xx_pic_mem_write,
+    pxa2xx_pic_mem_write,
+    pxa2xx_pic_mem_write,
+};
+
+static void pxa2xx_pic_save(QEMUFile *f, void *opaque)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 2; i ++)
+        qemu_put_be32s(f, &s->int_enabled[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_be32s(f, &s->int_pending[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_be32s(f, &s->is_fiq[i]);
+    qemu_put_be32s(f, &s->int_idle);
+    for (i = 0; i < PXA2XX_PIC_SRCS; i ++)
+        qemu_put_be32s(f, &s->priority[i]);
+}
+
+static int pxa2xx_pic_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pxa2xx_pic_state_s *s = (struct pxa2xx_pic_state_s *) opaque;
+    int i;
+
+    for (i = 0; i < 2; i ++)
+        qemu_get_be32s(f, &s->int_enabled[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_be32s(f, &s->int_pending[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_be32s(f, &s->is_fiq[i]);
+    qemu_get_be32s(f, &s->int_idle);
+    for (i = 0; i < PXA2XX_PIC_SRCS; i ++)
+        qemu_get_be32s(f, &s->priority[i]);
+
+    pxa2xx_pic_update(opaque);
+    return 0;
+}
+
+qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
+{
+    struct pxa2xx_pic_state_s *s;
+    int iomemtype;
+    qemu_irq *qi;
+
+    s = (struct pxa2xx_pic_state_s *)
+            qemu_mallocz(sizeof(struct pxa2xx_pic_state_s));
+    if (!s)
+        return NULL;
+
+    s->cpu_env = env;
+    s->base = base;
+
+    s->int_pending[0] = 0;
+    s->int_pending[1] = 0;
+    s->int_enabled[0] = 0;
+    s->int_enabled[1] = 0;
+    s->is_fiq[0] = 0;
+    s->is_fiq[1] = 0;
+
+    qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS);
+
+    /* Enable IC memory-mapped registers access.  */
+    iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn,
+                    pxa2xx_pic_writefn, s);
+    cpu_register_physical_memory(base, 0x00100000, iomemtype);
+
+    /* Enable IC coprocessor access.  */
+    cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s);
+
+    register_savevm("pxa2xx_pic", 0, 0, pxa2xx_pic_save, pxa2xx_pic_load, s);
+
+    return qi;
+}
diff --git a/hw/pxa2xx_template.h b/hw/pxa2xx_template.h
new file mode 100644
index 0000000..ad3799d
--- /dev/null
+++ b/hw/pxa2xx_template.h
@@ -0,0 +1,431 @@
+/*
+ * Intel XScale PXA255/270 LCDC emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GPLv2.
+ *
+ * Framebuffer format conversion routines.
+ */
+
+# define SKIP_PIXEL(to)		to += deststep
+#if BITS == 8
+# define COPY_PIXEL(to, from)	*to = from; SKIP_PIXEL(to)
+#elif BITS == 15 || BITS == 16
+# define COPY_PIXEL(to, from)	*(uint16_t *) to = from; SKIP_PIXEL(to)
+#elif BITS == 24
+# define COPY_PIXEL(to, from)	\
+	*(uint16_t *) to = from; *(to + 2) = (from) >> 16; SKIP_PIXEL(to)
+#elif BITS == 32
+# define COPY_PIXEL(to, from)	*(uint32_t *) to = from; SKIP_PIXEL(to)
+#else
+# error unknown bit depth
+#endif
+
+#ifdef WORDS_BIGENDIAN
+# define SWAP_WORDS	1
+#endif
+
+#define FN_2(x)		FN(x + 1) FN(x)
+#define FN_4(x)		FN_2(x + 2) FN_2(x)
+
+static void glue(pxa2xx_draw_line2_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> ((x) * 2)) & 3]);
+#ifdef SWAP_WORDS
+        FN_4(12)
+        FN_4(8)
+        FN_4(4)
+        FN_4(0)
+#else
+        FN_4(0)
+        FN_4(4)
+        FN_4(8)
+        FN_4(12)
+#endif
+#undef FN
+        width -= 16;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line4_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> ((x) * 4)) & 0xf]);
+#ifdef SWAP_WORDS
+        FN_2(6)
+        FN_2(4)
+        FN_2(2)
+        FN_2(0)
+#else
+        FN_2(0)
+        FN_2(2)
+        FN_2(4)
+        FN_2(6)
+#endif
+#undef FN
+        width -= 8;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line8_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#define FN(x)		COPY_PIXEL(dest, palette[(data >> (x)) & 0xff]);
+#ifdef SWAP_WORDS
+        FN(24)
+        FN(16)
+        FN(8)
+        FN(0)
+#else
+        FN(0)
+        FN(8)
+        FN(16)
+        FN(24)
+#endif
+#undef FN
+        width -= 4;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line16_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x1f) << 3;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line16t_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        r = (data & 0x1f) << 3;
+        data >>= 5;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data >>= 1;
+        b = (data & 0x1f) << 3;
+        data >>= 5;
+        g = (data & 0x1f) << 3;
+        data >>= 5;
+        r = (data & 0x1f) << 3;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 2;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line18_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x3f) << 2;
+        data >>= 6;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x3f) << 2;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* The wicked packed format */
+static void glue(pxa2xx_draw_line18p_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data[3];
+    unsigned int r, g, b;
+    while (width > 0) {
+        data[0] = *(uint32_t *) src;
+        src += 4;
+        data[1] = *(uint32_t *) src;
+        src += 4;
+        data[2] = *(uint32_t *) src;
+        src += 4;
+#ifdef SWAP_WORDS
+        data[0] = bswap32(data[0]);
+        data[1] = bswap32(data[1]);
+        data[2] = bswap32(data[2]);
+#endif
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        r = (data[0] & 0x3f) << 2;
+        data[0] >>= 12;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+        data[1] >>= 4;
+        r = (data[1] & 0x3f) << 2;
+        data[1] >>= 12;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        g = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+        data[2] >>= 8;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        b = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        g = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        r = data[2] << 2;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line19_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x3f) << 2;
+        data >>= 6;
+        g = (data & 0x3f) << 2;
+        data >>= 6;
+        r = (data & 0x3f) << 2;
+        data >>= 6;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* The wicked packed format */
+static void glue(pxa2xx_draw_line19p_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data[3];
+    unsigned int r, g, b;
+    while (width > 0) {
+        data[0] = *(uint32_t *) src;
+        src += 4;
+        data[1] = *(uint32_t *) src;
+        src += 4;
+        data[2] = *(uint32_t *) src;
+        src += 4;
+# ifdef SWAP_WORDS
+        data[0] = bswap32(data[0]);
+        data[1] = bswap32(data[1]);
+        data[2] = bswap32(data[2]);
+# endif
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        r = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        if (data[0] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[0] >>= 6;
+        b = (data[0] & 0x3f) << 2;
+        data[0] >>= 6;
+        g = ((data[1] & 0xf) << 4) | (data[0] << 2);
+        data[1] >>= 4;
+        r = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        if (data[1] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[1] >>= 6;
+        b = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        g = (data[1] & 0x3f) << 2;
+        data[1] >>= 6;
+        r = ((data[2] & 0x3) << 6) | (data[1] << 2);
+        data[2] >>= 2;
+        if (data[2] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        data[2] >>= 6;
+        b = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        g = (data[2] & 0x3f) << 2;
+        data[2] >>= 6;
+        r = data[2] << 2;
+        data[2] >>= 6;
+        if (data[2] & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line24_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = data & 0xff;
+        data >>= 8;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line24t_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = (data & 0x7f) << 1;
+        data >>= 7;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        data >>= 8;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+static void glue(pxa2xx_draw_line25_, BITS)(uint32_t *palette,
+                uint8_t *dest, const uint8_t *src, int width, int deststep)
+{
+    uint32_t data;
+    unsigned int r, g, b;
+    while (width > 0) {
+        data = *(uint32_t *) src;
+#ifdef SWAP_WORDS
+        data = bswap32(data);
+#endif
+        b = data & 0xff;
+        data >>= 8;
+        g = data & 0xff;
+        data >>= 8;
+        r = data & 0xff;
+        data >>= 8;
+        if (data & 1)
+            SKIP_PIXEL(dest);
+        else
+            COPY_PIXEL(dest, glue(rgb_to_pixel, BITS)(r, g, b));
+        width -= 1;
+        src += 4;
+    }
+}
+
+/* Overlay planes disabled, no transparency */
+static drawfn glue(pxa2xx_draw_fn_, BITS)[16] =
+{
+    [0 ... 0xf]       = 0,
+    [pxa_lcdc_2bpp]   = glue(pxa2xx_draw_line2_, BITS),
+    [pxa_lcdc_4bpp]   = glue(pxa2xx_draw_line4_, BITS),
+    [pxa_lcdc_8bpp]   = glue(pxa2xx_draw_line8_, BITS),
+    [pxa_lcdc_16bpp]  = glue(pxa2xx_draw_line16_, BITS),
+    [pxa_lcdc_18bpp]  = glue(pxa2xx_draw_line18_, BITS),
+    [pxa_lcdc_18pbpp] = glue(pxa2xx_draw_line18p_, BITS),
+    [pxa_lcdc_24bpp]  = glue(pxa2xx_draw_line24_, BITS),
+};
+
+/* Overlay planes enabled, transparency used */
+static drawfn glue(glue(pxa2xx_draw_fn_, BITS), t)[16] =
+{
+    [0 ... 0xf]       = 0,
+    [pxa_lcdc_4bpp]   = glue(pxa2xx_draw_line4_, BITS),
+    [pxa_lcdc_8bpp]   = glue(pxa2xx_draw_line8_, BITS),
+    [pxa_lcdc_16bpp]  = glue(pxa2xx_draw_line16t_, BITS),
+    [pxa_lcdc_19bpp]  = glue(pxa2xx_draw_line19_, BITS),
+    [pxa_lcdc_19pbpp] = glue(pxa2xx_draw_line19p_, BITS),
+    [pxa_lcdc_24bpp]  = glue(pxa2xx_draw_line24t_, BITS),
+    [pxa_lcdc_25bpp]  = glue(pxa2xx_draw_line25_, BITS),
+};
+
+#undef BITS
+#undef COPY_PIXEL
+#undef SKIP_PIXEL
+
+#ifdef SWAP_WORDS
+# undef SWAP_WORDS
+#endif
diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c
new file mode 100644
index 0000000..9824205
--- /dev/null
+++ b/hw/pxa2xx_timer.c
@@ -0,0 +1,495 @@
+/*
+ * Intel XScale PXA255/270 OS Timers.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Copyright (c) 2006 Thorsten Zitterell
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+
+#define OSMR0	0x00
+#define OSMR1	0x04
+#define OSMR2	0x08
+#define OSMR3	0x0c
+#define OSMR4	0x80
+#define OSMR5	0x84
+#define OSMR6	0x88
+#define OSMR7	0x8c
+#define OSMR8	0x90
+#define OSMR9	0x94
+#define OSMR10	0x98
+#define OSMR11	0x9c
+#define OSCR	0x10	/* OS Timer Count */
+#define OSCR4	0x40
+#define OSCR5	0x44
+#define OSCR6	0x48
+#define OSCR7	0x4c
+#define OSCR8	0x50
+#define OSCR9	0x54
+#define OSCR10	0x58
+#define OSCR11	0x5c
+#define OSSR	0x14	/* Timer status register */
+#define OWER	0x18
+#define OIER	0x1c	/* Interrupt enable register  3-0 to E3-E0 */
+#define OMCR4	0xc0	/* OS Match Control registers */
+#define OMCR5	0xc4
+#define OMCR6	0xc8
+#define OMCR7	0xcc
+#define OMCR8	0xd0
+#define OMCR9	0xd4
+#define OMCR10	0xd8
+#define OMCR11	0xdc
+#define OSNR	0x20
+
+#define PXA25X_FREQ	3686400	/* 3.6864 MHz */
+#define PXA27X_FREQ	3250000	/* 3.25 MHz */
+
+static int pxa2xx_timer4_freq[8] = {
+    [0] = 0,
+    [1] = 32768,
+    [2] = 1000,
+    [3] = 1,
+    [4] = 1000000,
+    /* [5] is the "Externally supplied clock".  Assign if necessary.  */
+    [5 ... 7] = 0,
+};
+
+struct pxa2xx_timer0_s {
+    uint32_t value;
+    int level;
+    qemu_irq irq;
+    QEMUTimer *qtimer;
+    int num;
+    void *info;
+};
+
+struct pxa2xx_timer4_s {
+    struct pxa2xx_timer0_s tm;
+    int32_t oldclock;
+    int32_t clock;
+    uint64_t lastload;
+    uint32_t freq;
+    uint32_t control;
+};
+
+typedef struct {
+    target_phys_addr_t base;
+    int32_t clock;
+    int32_t oldclock;
+    uint64_t lastload;
+    uint32_t freq;
+    struct pxa2xx_timer0_s timer[4];
+    struct pxa2xx_timer4_s *tm4;
+    uint32_t events;
+    uint32_t irq_enabled;
+    uint32_t reset3;
+    uint32_t snapshot;
+} pxa2xx_timer_info;
+
+static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
+{
+    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    int i;
+    uint32_t now_vm;
+    uint64_t new_qemu;
+
+    now_vm = s->clock +
+            muldiv64(now_qemu - s->lastload, s->freq, ticks_per_sec);
+
+    for (i = 0; i < 4; i ++) {
+        new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
+                        ticks_per_sec, s->freq);
+        qemu_mod_timer(s->timer[i].qtimer, new_qemu);
+    }
+}
+
+static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
+{
+    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    uint32_t now_vm;
+    uint64_t new_qemu;
+    static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
+    int counter;
+
+    if (s->tm4[n].control & (1 << 7))
+        counter = n;
+    else
+        counter = counters[n];
+
+    if (!s->tm4[counter].freq) {
+        qemu_del_timer(s->tm4[n].tm.qtimer);
+        return;
+    }
+
+    now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
+                    s->tm4[counter].lastload,
+                    s->tm4[counter].freq, ticks_per_sec);
+
+    new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
+                    ticks_per_sec, s->tm4[counter].freq);
+    qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
+}
+
+static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
+{
+    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    int tm = 0;
+
+    offset -= s->base;
+
+    switch (offset) {
+    case OSMR3:  tm ++;
+    case OSMR2:  tm ++;
+    case OSMR1:  tm ++;
+    case OSMR0:
+        return s->timer[tm].value;
+    case OSMR11: tm ++;
+    case OSMR10: tm ++;
+    case OSMR9:  tm ++;
+    case OSMR8:  tm ++;
+    case OSMR7:  tm ++;
+    case OSMR6:  tm ++;
+    case OSMR5:  tm ++;
+    case OSMR4:
+        if (!s->tm4)
+            goto badreg;
+        return s->tm4[tm].tm.value;
+    case OSCR:
+        return s->clock + muldiv64(qemu_get_clock(vm_clock) -
+                        s->lastload, s->freq, ticks_per_sec);
+    case OSCR11: tm ++;
+    case OSCR10: tm ++;
+    case OSCR9:  tm ++;
+    case OSCR8:  tm ++;
+    case OSCR7:  tm ++;
+    case OSCR6:  tm ++;
+    case OSCR5:  tm ++;
+    case OSCR4:
+        if (!s->tm4)
+            goto badreg;
+
+        if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
+            if (s->tm4[tm - 1].freq)
+                s->snapshot = s->tm4[tm - 1].clock + muldiv64(
+                                qemu_get_clock(vm_clock) -
+                                s->tm4[tm - 1].lastload,
+                                s->tm4[tm - 1].freq, ticks_per_sec);
+            else
+                s->snapshot = s->tm4[tm - 1].clock;
+        }
+
+        if (!s->tm4[tm].freq)
+            return s->tm4[tm].clock;
+        return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) -
+                        s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec);
+    case OIER:
+        return s->irq_enabled;
+    case OSSR:	/* Status register */
+        return s->events;
+    case OWER:
+        return s->reset3;
+    case OMCR11: tm ++;
+    case OMCR10: tm ++;
+    case OMCR9:  tm ++;
+    case OMCR8:  tm ++;
+    case OMCR7:  tm ++;
+    case OMCR6:  tm ++;
+    case OMCR5:  tm ++;
+    case OMCR4:
+        if (!s->tm4)
+            goto badreg;
+        return s->tm4[tm].control;
+    case OSNR:
+        return s->snapshot;
+    default:
+    badreg:
+        cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset "
+                        REG_FMT "\n", offset);
+    }
+
+    return 0;
+}
+
+static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
+                uint32_t value)
+{
+    int i, tm = 0;
+    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+
+    offset -= s->base;
+
+    switch (offset) {
+    case OSMR3:  tm ++;
+    case OSMR2:  tm ++;
+    case OSMR1:  tm ++;
+    case OSMR0:
+        s->timer[tm].value = value;
+        pxa2xx_timer_update(s, qemu_get_clock(vm_clock));
+        break;
+    case OSMR11: tm ++;
+    case OSMR10: tm ++;
+    case OSMR9:  tm ++;
+    case OSMR8:  tm ++;
+    case OSMR7:  tm ++;
+    case OSMR6:  tm ++;
+    case OSMR5:  tm ++;
+    case OSMR4:
+        if (!s->tm4)
+            goto badreg;
+        s->tm4[tm].tm.value = value;
+        pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+        break;
+    case OSCR:
+        s->oldclock = s->clock;
+        s->lastload = qemu_get_clock(vm_clock);
+        s->clock = value;
+        pxa2xx_timer_update(s, s->lastload);
+        break;
+    case OSCR11: tm ++;
+    case OSCR10: tm ++;
+    case OSCR9:  tm ++;
+    case OSCR8:  tm ++;
+    case OSCR7:  tm ++;
+    case OSCR6:  tm ++;
+    case OSCR5:  tm ++;
+    case OSCR4:
+        if (!s->tm4)
+            goto badreg;
+        s->tm4[tm].oldclock = s->tm4[tm].clock;
+        s->tm4[tm].lastload = qemu_get_clock(vm_clock);
+        s->tm4[tm].clock = value;
+        pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
+        break;
+    case OIER:
+        s->irq_enabled = value & 0xfff;
+        break;
+    case OSSR:	/* Status register */
+        s->events &= ~value;
+        for (i = 0; i < 4; i ++, value >>= 1) {
+            if (s->timer[i].level && (value & 1)) {
+                s->timer[i].level = 0;
+                qemu_irq_lower(s->timer[i].irq);
+            }
+        }
+        if (s->tm4) {
+            for (i = 0; i < 8; i ++, value >>= 1)
+                if (s->tm4[i].tm.level && (value & 1))
+                    s->tm4[i].tm.level = 0;
+            if (!(s->events & 0xff0))
+                qemu_irq_lower(s->tm4->tm.irq);
+        }
+        break;
+    case OWER:	/* XXX: Reset on OSMR3 match? */
+        s->reset3 = value;
+        break;
+    case OMCR7:  tm ++;
+    case OMCR6:  tm ++;
+    case OMCR5:  tm ++;
+    case OMCR4:
+        if (!s->tm4)
+            goto badreg;
+        s->tm4[tm].control = value & 0x0ff;
+        /* XXX Stop if running (shouldn't happen) */
+        if ((value & (1 << 7)) || tm == 0)
+            s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
+        else {
+            s->tm4[tm].freq = 0;
+            pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+        }
+        break;
+    case OMCR11: tm ++;
+    case OMCR10: tm ++;
+    case OMCR9:  tm ++;
+    case OMCR8:  tm += 4;
+        if (!s->tm4)
+            goto badreg;
+        s->tm4[tm].control = value & 0x3ff;
+        /* XXX Stop if running (shouldn't happen) */
+        if ((value & (1 << 7)) || !(tm & 1))
+            s->tm4[tm].freq =
+                    pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
+        else {
+            s->tm4[tm].freq = 0;
+            pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+        }
+        break;
+    default:
+    badreg:
+        cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset "
+                        REG_FMT "\n", offset);
+    }
+}
+
+static CPUReadMemoryFunc *pxa2xx_timer_readfn[] = {
+    pxa2xx_timer_read,
+    pxa2xx_timer_read,
+    pxa2xx_timer_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = {
+    pxa2xx_timer_write,
+    pxa2xx_timer_write,
+    pxa2xx_timer_write,
+};
+
+static void pxa2xx_timer_tick(void *opaque)
+{
+    struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque;
+    pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info;
+
+    if (i->irq_enabled & (1 << t->num)) {
+        t->level = 1;
+        i->events |= 1 << t->num;
+        qemu_irq_raise(t->irq);
+    }
+
+    if (t->num == 3)
+        if (i->reset3 & 1) {
+            i->reset3 = 0;
+            qemu_system_reset_request();
+        }
+}
+
+static void pxa2xx_timer_tick4(void *opaque)
+{
+    struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque;
+    pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->tm.info;
+
+    pxa2xx_timer_tick(&t->tm);
+    if (t->control & (1 << 3))
+        t->clock = 0;
+    if (t->control & (1 << 6))
+        pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4);
+}
+
+static void pxa2xx_timer_save(QEMUFile *f, void *opaque)
+{
+    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    int i;
+
+    qemu_put_be32s(f, &s->clock);
+    qemu_put_be32s(f, &s->oldclock);
+    qemu_put_be64s(f, &s->lastload);
+
+    for (i = 0; i < 4; i ++) {
+        qemu_put_be32s(f, &s->timer[i].value);
+        qemu_put_be32(f, s->timer[i].level);
+    }
+    if (s->tm4)
+        for (i = 0; i < 8; i ++) {
+            qemu_put_be32s(f, &s->tm4[i].tm.value);
+            qemu_put_be32(f, s->tm4[i].tm.level);
+            qemu_put_be32s(f, &s->tm4[i].oldclock);
+            qemu_put_be32s(f, &s->tm4[i].clock);
+            qemu_put_be64s(f, &s->tm4[i].lastload);
+            qemu_put_be32s(f, &s->tm4[i].freq);
+            qemu_put_be32s(f, &s->tm4[i].control);
+        }
+
+    qemu_put_be32s(f, &s->events);
+    qemu_put_be32s(f, &s->irq_enabled);
+    qemu_put_be32s(f, &s->reset3);
+    qemu_put_be32s(f, &s->snapshot);
+}
+
+static int pxa2xx_timer_load(QEMUFile *f, void *opaque, int version_id)
+{
+    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    int64_t now;
+    int i;
+
+    qemu_get_be32s(f, &s->clock);
+    qemu_get_be32s(f, &s->oldclock);
+    qemu_get_be64s(f, &s->lastload);
+
+    now = qemu_get_clock(vm_clock);
+    for (i = 0; i < 4; i ++) {
+        qemu_get_be32s(f, &s->timer[i].value);
+        s->timer[i].level = qemu_get_be32(f);
+    }
+    pxa2xx_timer_update(s, now);
+
+    if (s->tm4)
+        for (i = 0; i < 8; i ++) {
+            qemu_get_be32s(f, &s->tm4[i].tm.value);
+            s->tm4[i].tm.level = qemu_get_be32(f);
+            qemu_get_be32s(f, &s->tm4[i].oldclock);
+            qemu_get_be32s(f, &s->tm4[i].clock);
+            qemu_get_be64s(f, &s->tm4[i].lastload);
+            qemu_get_be32s(f, &s->tm4[i].freq);
+            qemu_get_be32s(f, &s->tm4[i].control);
+            pxa2xx_timer_update4(s, now, i);
+        }
+
+    qemu_get_be32s(f, &s->events);
+    qemu_get_be32s(f, &s->irq_enabled);
+    qemu_get_be32s(f, &s->reset3);
+    qemu_get_be32s(f, &s->snapshot);
+
+    return 0;
+}
+
+static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base,
+                qemu_irq *irqs)
+{
+    int i;
+    int iomemtype;
+    pxa2xx_timer_info *s;
+
+    s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info));
+    s->base = base;
+    s->irq_enabled = 0;
+    s->oldclock = 0;
+    s->clock = 0;
+    s->lastload = qemu_get_clock(vm_clock);
+    s->reset3 = 0;
+
+    for (i = 0; i < 4; i ++) {
+        s->timer[i].value = 0;
+        s->timer[i].irq = irqs[i];
+        s->timer[i].info = s;
+        s->timer[i].num = i;
+        s->timer[i].level = 0;
+        s->timer[i].qtimer = qemu_new_timer(vm_clock,
+                        pxa2xx_timer_tick, &s->timer[i]);
+    }
+
+    iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn,
+                    pxa2xx_timer_writefn, s);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+
+    register_savevm("pxa2xx_timer", 0, 0,
+                    pxa2xx_timer_save, pxa2xx_timer_load, s);
+
+    return s;
+}
+
+void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs)
+{
+    pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs);
+    s->freq = PXA25X_FREQ;
+    s->tm4 = 0;
+}
+
+void pxa27x_timer_init(target_phys_addr_t base,
+                qemu_irq *irqs, qemu_irq irq4)
+{
+    pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs);
+    int i;
+    s->freq = PXA27X_FREQ;
+    s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 *
+                    sizeof(struct pxa2xx_timer4_s));
+    for (i = 0; i < 8; i ++) {
+        s->tm4[i].tm.value = 0;
+        s->tm4[i].tm.irq = irq4;
+        s->tm4[i].tm.info = s;
+        s->tm4[i].tm.num = i + 4;
+        s->tm4[i].tm.level = 0;
+        s->tm4[i].freq = 0;
+        s->tm4[i].control = 0x0;
+        s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock,
+                        pxa2xx_timer_tick4, &s->tm4[i]);
+    }
+}
diff --git a/hw/r2d.c b/hw/r2d.c
new file mode 100644
index 0000000..33d03cb
--- /dev/null
+++ b/hw/r2d.c
@@ -0,0 +1,63 @@
+/*
+ * Renesas SH7751R R2D-PLUS emulation
+ *
+ * Copyright (c) 2007 Magnus Damm
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "vl.h"
+
+#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
+#define SDRAM_SIZE 0x04000000
+
+void r2d_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;
+    struct SH7750State *s;
+
+    env = cpu_init();
+
+    /* Allocate memory space */
+    cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, 0);
+    /* Register peripherals */
+    s = sh7750_init(env);
+    /* Todo: register on board registers */
+    {
+      int kernel_size;
+
+      kernel_size = load_image(kernel_filename, phys_ram_base);
+
+      if (kernel_size < 0) {
+        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
+        exit(1);
+      }
+
+      env->pc = SDRAM_BASE | 0xa0000000; /* Start from P2 area */
+    }
+}
+
+QEMUMachine r2d_machine = {
+    "r2d",
+    "r2d-plus board",
+    r2d_init
+};
diff --git a/hw/realview.c b/hw/realview.c
index ea42705..375f78a 100644
--- a/hw/realview.c
+++ b/hw/realview.c
@@ -1,7 +1,7 @@
-/* 
+/*
  * ARM RealView Baseboard System emulation.
  *
- * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2006-2007 CodeSourcery.
  * Written by Paul Brook
  *
  * This code is licenced under the GPL.
@@ -15,10 +15,10 @@
 static void realview_init(int ram_size, int vga_ram_size, int boot_device,
                      DisplayState *ds, const char **fd_filename, int snapshot,
                      const char *kernel_filename, const char *kernel_cmdline,
-                     const char *initrd_filename)
+                     const char *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
-    void *pic;
+    qemu_irq *pic;
     void *scsi_hba;
     PCIBus *pci_bus;
     NICInfo *nd;
@@ -26,8 +26,9 @@
     int done_smc = 0;
 
     env = cpu_init();
-    cpu_arm_set_model(env, ARM_CPUID_ARM926);
-    //cpu_arm_set_model(env, ARM_CPUID_ARM11MPCORE);
+    if (!cpu_model)
+        cpu_model = "arm926";
+    cpu_arm_set_model(env, cpu_model);
     /* ??? RAM shoud repeat to fill physical memory space.  */
     /* SDRAM at address zero.  */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
@@ -37,26 +38,30 @@
     /* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3
        is nIRQ (there are inconsistencies).  However Linux 2.6.17 expects
        GIC1 to be nIRQ and ignores all the others, so do that for now.  */
-    pic = arm_gic_init(0x10040000, pic, ARM_PIC_CPU_IRQ);
-    pl050_init(0x10006000, pic, 20, 0);
-    pl050_init(0x10007000, pic, 21, 1);
+    pic = arm_gic_init(0x10040000, pic[ARM_PIC_CPU_IRQ]);
+    pl050_init(0x10006000, pic[20], 0);
+    pl050_init(0x10007000, pic[21], 1);
 
-    pl011_init(0x10009000, pic, 12, serial_hds[0]);
-    pl011_init(0x1000a000, pic, 13, serial_hds[1]);
-    pl011_init(0x1000b000, pic, 14, serial_hds[2]);
-    pl011_init(0x1000c000, pic, 15, serial_hds[3]);
+    pl011_init(0x10009000, pic[12], serial_hds[0]);
+    pl011_init(0x1000a000, pic[13], serial_hds[1]);
+    pl011_init(0x1000b000, pic[14], serial_hds[2]);
+    pl011_init(0x1000c000, pic[15], serial_hds[3]);
 
     /* DMA controller is optional, apparently.  */
-    pl080_init(0x10030000, pic, 24, 2);
+    pl080_init(0x10030000, pic[24], 2);
 
-    sp804_init(0x10011000, pic, 4);
-    sp804_init(0x10012000, pic, 5);
+    sp804_init(0x10011000, pic[4]);
+    sp804_init(0x10012000, pic[5]);
 
-    pl110_init(ds, 0x10020000, pic, 23, 1);
+    pl110_init(ds, 0x10020000, pic[23], 1);
+
+    pl181_init(0x10005000, sd_bdrv, pic[17], pic[18]);
+
+    pl031_init(0x10017000, pic[10]);
 
     pci_bus = pci_vpb_init(pic, 48, 1);
     if (usb_enabled) {
-        usb_ohci_init(pci_bus, 3, -1);
+        usb_ohci_init_pci(pci_bus, 3, -1);
     }
     scsi_hba = lsi_scsi_init(pci_bus, -1);
     for (n = 0; n < MAX_DISKS; n++) {
@@ -69,7 +74,7 @@
         if (!nd->model)
             nd->model = done_smc ? "rtl8139" : "smc91c111";
         if (strcmp(nd->model, "smc91c111") == 0) {
-            smc91c111_init(nd, 0x4e000000, pic, 28);
+            smc91c111_init(nd, 0x4e000000, pic[28]);
         } else {
             pci_nic_init(pci_bus, nd, -1);
         }
@@ -99,7 +104,7 @@
     /*  0x10014000 GPIO 1.  */
     /*  0x10015000 GPIO 2.  */
     /* 0x10016000 Reserved.  */
-    /*  0x10017000 RTC.  */
+    /* 0x10017000 RTC.  */
     /*  0x10018000 DMC.  */
     /*  0x10019000 PCI controller config.  */
     /*  0x10020000 CLCD.  */
@@ -128,7 +133,7 @@
     /* 0x6c000000 PCI mem 2.  */
 
     arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
-                    initrd_filename, 0x33b);
+                    initrd_filename, 0x33b, 0x0);
 }
 
 QEMUMachine realview_machine = {
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 94fc2fc..a970eb3 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -1,8 +1,8 @@
 /**
  * QEMU RTL8139 emulation
- * 
+ *
  * Copyright (c) 2006 Igor Kovalenko
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -20,13 +20,13 @@
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
- 
+
  * Modifications:
  *  2006-Jan-28  Mark Malakanov :   TSAD and CSCR implementation (for Windows driver)
- * 
+ *
  *  2006-Apr-28  Juergen Lock   :   EEPROM emulation changes for FreeBSD driver
  *                                  HW revision ID changes for FreeBSD driver
- * 
+ *
  *  2006-Jul-01  Igor Kovalenko :   Implemented loopback mode for FreeBSD driver
  *                                  Corrected packet transfer reassembly routine for 8139C+ mode
  *                                  Rearranged debugging print statements
@@ -53,9 +53,8 @@
 /* debug RTL8139 card C+ mode only */
 //#define DEBUG_RTL8139CP 1
 
-/* RTL8139 provides frame CRC with received packet, this feature seems to be
-   ignored by most drivers, disabled by default */
-//#define RTL8139_CALCULATE_RXCRC 1
+/* Calculate CRCs properly on Rx packets */
+#define RTL8139_CALCULATE_RXCRC 1
 
 /* Uncomment to enable on-board timer interrupts */
 //#define RTL8139_ONBOARD_TIMER 1
@@ -306,11 +305,11 @@
     CSCR_LinkDownCmd = 0x0f3c0,
 */
 enum CSCRBits {
-    CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */ 
+    CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
     CSCR_LD  = 1<<9,  /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
     CSCR_HEART_BIT = 1<<8,  /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
     CSCR_JBEN = 1<<7,  /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
-    CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/ 
+    CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
     CSCR_F_Connect  = 1<<5,  /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
     CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
     CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
@@ -461,7 +460,6 @@
     uint16_t CpCmd;
     uint8_t  TxThresh;
 
-    int irq;
     PCIDevice *pci_dev;
     VLANClientState *vc;
     uint8_t macaddr[6];
@@ -685,16 +683,10 @@
     int isr;
     isr = (s->IntrStatus & s->IntrMask) & 0xffff;
 
-    DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n",
-       s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask));
+    DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n",
+       isr ? 1 : 0, s->IntrStatus, s->IntrMask));
 
-    if (s->irq == 16) {
-        /* PCI irq */
-        pci_set_irq(s->pci_dev, 0, (isr != 0));
-    } else {
-        /* ISA irq */
-        pic_set_irq(s->irq, (isr != 0));
-    }
+    qemu_set_irq(s->pci_dev->irq[0], (isr != 0));
 }
 
 #define POLYNOMIAL 0x04c11db6
@@ -754,7 +746,7 @@
         int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
 
         /* write packet data */
-        if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s))
+        if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s)))
         {
             DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped));
 
@@ -797,7 +789,7 @@
     RTL8139State *s = opaque;
     int avail;
 
-    /* Recieve (drop) packets if card is disabled.  */
+    /* Receive (drop) packets if card is disabled.  */
     if (!s->clock_enabled)
       return 1;
     if (!rtl8139_receiver_enabled(s))
@@ -821,7 +813,7 @@
     uint32_t packet_header = 0;
 
     uint8_t buf1[60];
-    static const uint8_t broadcast_macaddr[6] = 
+    static const uint8_t broadcast_macaddr[6] =
         { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
     DEBUG_PRINT((">>> RTL8139: received len=%d\n", size));
@@ -898,10 +890,10 @@
             ++s->tally_counters.RxOkMul;
 
         } else if (s->phys[0] == buf[0] &&
-                   s->phys[1] == buf[1] &&                   
-                   s->phys[2] == buf[2] &&            
-                   s->phys[3] == buf[3] &&            
-                   s->phys[4] == buf[4] &&            
+                   s->phys[1] == buf[1] &&
+                   s->phys[2] == buf[2] &&
+                   s->phys[3] == buf[3] &&
+                   s->phys[4] == buf[4] &&
                    s->phys[5] == buf[5]) {
             /* match */
             if (!(s->RxConfig & AcceptMyPhys))
@@ -1030,7 +1022,7 @@
 
         /* write checksum */
 #if defined (RTL8139_CALCULATE_RXCRC)
-        val = cpu_to_le32(crc32(~0, buf, size));
+        val = cpu_to_le32(crc32(0, buf, size));
 #else
         val = 0;
 #endif
@@ -1136,7 +1128,7 @@
 
         /* write checksum */
 #if defined (RTL8139_CALCULATE_RXCRC)
-        val = cpu_to_le32(crc32(~0, buf, size));
+        val = cpu_to_le32(crc32(0, buf, size));
 #else
         val = 0;
 #endif
@@ -1192,7 +1184,10 @@
     s->eeprom.contents[1] = 0x10ec;
     s->eeprom.contents[2] = 0x8139;
 #endif
-    memcpy(&s->eeprom.contents[7], s->macaddr, 6);
+
+    s->eeprom.contents[7] = s->macaddr[0] | s->macaddr[1] << 8;
+    s->eeprom.contents[8] = s->macaddr[2] | s->macaddr[3] << 8;
+    s->eeprom.contents[9] = s->macaddr[4] | s->macaddr[5] << 8;
 
     /* mark all status registers as owned by host */
     for (i = 0; i < 4; ++i)
@@ -1230,7 +1225,7 @@
     s->Config3 = 0x1; /* fast back-to-back compatible */
     s->Config5 = 0x0;
 
-    s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD; 
+    s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
 
     s->CpCmd   = 0x0; /* reset C+ mode */
 
@@ -2425,17 +2420,17 @@
          |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0)
          |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0)
          |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0)
-         
+
          |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0)
          |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0)
          |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0)
          |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0)
-         
+
          |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0)
          |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0)
          |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0)
          |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
-       
+
 
     DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret));
 
@@ -2455,12 +2450,12 @@
 {
     DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val));
 
-    s->TxAddr[txAddrOffset/4] = le32_to_cpu(val);
+    s->TxAddr[txAddrOffset/4] = val;
 }
 
 static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
 {
-    uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]);
+    uint32_t ret = s->TxAddr[txAddrOffset/4];
 
     DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret));
 
@@ -3170,7 +3165,8 @@
     qemu_put_be16s(f, &s->CpCmd);
     qemu_put_8s(f, &s->TxThresh);
 
-    qemu_put_be32s(f, &s->irq);
+    i = 0;
+    qemu_put_be32s(f, &i); /* unused.  */
     qemu_put_buffer(f, s->macaddr, 6);
     qemu_put_be32s(f, &s->rtl8139_mmio_io_addr);
 
@@ -3264,7 +3260,7 @@
     qemu_get_be16s(f, &s->CpCmd);
     qemu_get_8s(f, &s->TxThresh);
 
-    qemu_get_be32s(f, &s->irq);
+    qemu_get_be32s(f, &i); /* unused.  */
     qemu_get_buffer(f, s->macaddr, 6);
     qemu_get_be32s(f, &s->rtl8139_mmio_io_addr);
 
@@ -3319,7 +3315,7 @@
     RTL8139State rtl8139;
 } PCIRTL8139State;
 
-static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num, 
+static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
                        uint32_t addr, uint32_t size, int type)
 {
     PCIRTL8139State *d = (PCIRTL8139State *)pci_dev;
@@ -3328,7 +3324,7 @@
     cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr);
 }
 
-static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num, 
+static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
                        uint32_t addr, uint32_t size, int type)
 {
     PCIRTL8139State *d = (PCIRTL8139State *)pci_dev;
@@ -3358,7 +3354,7 @@
 
 static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time)
 {
-    int64_t next_time = current_time + 
+    int64_t next_time = current_time +
         muldiv64(1, ticks_per_sec, PCI_FREQUENCY);
     if (next_time <= current_time)
         next_time = current_time + 1;
@@ -3404,7 +3400,7 @@
         rtl8139_update_irq(s);
     }
 
-    qemu_mod_timer(s->timer, 
+    qemu_mod_timer(s->timer,
         rtl8139_get_next_tctr_time(s,curr_time));
 }
 #endif /* RTL8139_ONBOARD_TIMER */
@@ -3414,10 +3410,10 @@
     PCIRTL8139State *d;
     RTL8139State *s;
     uint8_t *pci_conf;
-    
+
     d = (PCIRTL8139State *)pci_register_device(bus,
                                               "RTL8139", sizeof(PCIRTL8139State),
-                                              devfn, 
+                                              devfn,
                                               NULL, NULL);
     pci_conf = d->dev.config;
     pci_conf[0x00] = 0xec; /* Realtek 8139 */
@@ -3438,13 +3434,12 @@
     s->rtl8139_mmio_io_addr =
     cpu_register_io_memory(0, rtl8139_mmio_read, rtl8139_mmio_write, s);
 
-    pci_register_io_region(&d->dev, 0, 0x100, 
+    pci_register_io_region(&d->dev, 0, 0x100,
                            PCI_ADDRESS_SPACE_IO,  rtl8139_ioport_map);
 
-    pci_register_io_region(&d->dev, 1, 0x100, 
+    pci_register_io_region(&d->dev, 1, 0x100,
                            PCI_ADDRESS_SPACE_MEM, rtl8139_mmio_map);
 
-    s->irq = 16; /* PCI interrupt */
     s->pci_dev = (PCIDevice *)d;
     memcpy(s->macaddr, nd->macaddr, 6);
     rtl8139_reset(s);
@@ -3463,14 +3458,14 @@
     s->cplus_txbuffer = NULL;
     s->cplus_txbuffer_len = 0;
     s->cplus_txbuffer_offset = 0;
-             
+
     /* XXX: instance number ? */
     register_savevm("rtl8139", 0, 3, rtl8139_save, rtl8139_load, s);
 
 #if RTL8139_ONBOARD_TIMER
     s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
 
-    qemu_mod_timer(s->timer, 
+    qemu_mod_timer(s->timer,
         rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
 #endif /* RTL8139_ONBOARD_TIMER */
 }
diff --git a/hw/sb16.c b/hw/sb16.c
index 04325ac..1610b32 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -54,6 +54,7 @@
 
 typedef struct SB16State {
     QEMUSoundCard card;
+    qemu_irq *pic;
     int irq;
     int dma;
     int hdma;
@@ -187,7 +188,7 @@
 {
     SB16State *s = opaque;
     s->can_write = 1;
-    pic_set_irq (s->irq, 1);
+    qemu_irq_raise (s->pic[s->irq]);
 }
 
 #define DMA8_AUTO 1
@@ -595,7 +596,7 @@
         case 0xf3:
             dsp_out_data (s, 0xaa);
             s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
-            pic_set_irq (s->irq, 1);
+            qemu_irq_raise (s->pic[s->irq]);
             break;
 
         case 0xf9:
@@ -763,7 +764,7 @@
                 bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
                 ticks = (bytes * ticks_per_sec) / freq;
                 if (ticks < ticks_per_sec / 1024) {
-                    pic_set_irq (s->irq, 1);
+                    qemu_irq_raise (s->pic[s->irq]);
                 }
                 else {
                     if (s->aux_ts) {
@@ -855,10 +856,10 @@
 
 static void reset (SB16State *s)
 {
-    pic_set_irq (s->irq, 0);
+    qemu_irq_lower (s->pic[s->irq]);
     if (s->dma_auto) {
-        pic_set_irq (s->irq, 1);
-        pic_set_irq (s->irq, 0);
+        qemu_irq_raise (s->pic[s->irq]);
+        qemu_irq_lower (s->pic[s->irq]);
     }
 
     s->mixer_regs[0x82] = 0;
@@ -894,7 +895,7 @@
             if (s->v2x6 == 1) {
                 if (0 && s->highspeed) {
                     s->highspeed = 0;
-                    pic_set_irq (s->irq, 0);
+                    qemu_irq_lower (s->pic[s->irq]);
                     control (s, 0);
                 }
                 else {
@@ -1005,7 +1006,7 @@
         if (s->mixer_regs[0x82] & 1) {
             ack = 1;
             s->mixer_regs[0x82] &= 1;
-            pic_set_irq (s->irq, 0);
+            qemu_irq_lower (s->pic[s->irq]);
         }
         break;
 
@@ -1014,7 +1015,7 @@
         if (s->mixer_regs[0x82] & 2) {
             ack = 1;
             s->mixer_regs[0x82] &= 2;
-            pic_set_irq (s->irq, 0);
+            qemu_irq_lower (s->pic[s->irq]);
         }
         break;
 
@@ -1222,7 +1223,7 @@
 
     if (s->left_till_irq <= 0) {
         s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
-        pic_set_irq (s->irq, 1);
+        qemu_irq_raise (s->pic[s->irq]);
         if (0 == s->dma_auto) {
             control (s, 0);
             speaker (s, 0);
@@ -1389,7 +1390,7 @@
     return 0;
 }
 
-int SB16_init (AudioState *audio)
+int SB16_init (AudioState *audio, qemu_irq *pic)
 {
     SB16State *s;
     int i;
@@ -1409,6 +1410,7 @@
     }
 
     s->cmd = -1;
+    s->pic = pic;
     s->irq = conf.irq;
     s->dma = conf.dma;
     s->hdma = conf.hdma;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index c6280fd..384c098 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -345,7 +345,7 @@
         DPRINTF("Request Sense (len %d)\n", len);
         if (len < 4)
             goto fail;
-        memset(buf, 0, 4);
+        memset(outbuf, 0, 4);
         outbuf[0] = 0xf0;
         outbuf[1] = 0;
         outbuf[2] = s->sense;
@@ -371,7 +371,7 @@
            Some later commands are also implemented. */
 	outbuf[2] = 3;
 	outbuf[3] = 2; /* Format 2 */
-	outbuf[4] = 32;
+	outbuf[4] = 31;
         /* Sync data transfer and TCQ.  */
         outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0);
 	r->buf_len = 36;
@@ -404,10 +404,11 @@
             p += 4;
             if ((page == 8 || page == 0x3f)) {
                 /* Caching page.  */
+                memset(p,0,20);
                 p[0] = 8;
                 p[1] = 0x12;
                 p[2] = 4; /* WCE */
-                p += 19;
+                p += 20;
             }
             if ((page == 0x3f || page == 0x2a)
                     && (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
@@ -437,7 +438,7 @@
                 p[19] = (16 * 176) & 0xff;
                 p[20] = (16 * 176) >> 8; // 16x write speed current
                 p[21] = (16 * 176) & 0xff;
-                p += 21;
+                p += 22;
             }
             r->buf_len = p - outbuf;
             outbuf[0] = r->buf_len - 4;
@@ -488,7 +489,7 @@
         is_write = 1;
         break;
     case 0x35:
-        DPRINTF("Syncronise cache (sector %d, count %d)\n", lba, len);
+        DPRINTF("Synchronise cache (sector %d, count %d)\n", lba, len);
         bdrv_flush(s->bdrv);
         break;
     case 0x43:
diff --git a/hw/sd.c b/hw/sd.c
new file mode 100644
index 0000000..d59c4bf
--- /dev/null
+++ b/hw/sd.c
@@ -0,0 +1,1509 @@
+/*
+ * SD Memory Card emulation as defined in the "SD Memory Card Physical
+ * layer specification, Version 1.10."
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ * Copyright (c) 2007 CodeSourcery
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "sd.h"
+
+//#define DEBUG_SD 1
+
+#ifdef DEBUG_SD
+#define DPRINTF(fmt, args...) \
+do { printf("SD: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+typedef enum {
+    sd_r0 = 0,    /* no response */
+    sd_r1,        /* normal response command */
+    sd_r2_i,      /* CID register */
+    sd_r2_s,      /* CSD register */
+    sd_r3,        /* OCR register */
+    sd_r6 = 6,    /* Published RCA response */
+    sd_r1b = -1,
+} sd_rsp_type_t;
+
+struct SDState {
+    enum {
+        sd_inactive,
+        sd_card_identification_mode,
+        sd_data_transfer_mode,
+    } mode;
+    enum {
+        sd_inactive_state = -1,
+        sd_idle_state = 0,
+        sd_ready_state,
+        sd_identification_state,
+        sd_standby_state,
+        sd_transfer_state,
+        sd_sendingdata_state,
+        sd_receivingdata_state,
+        sd_programming_state,
+        sd_disconnect_state,
+    } state;
+    uint32_t ocr;
+    uint8_t scr[8];
+    uint8_t cid[16];
+    uint8_t csd[16];
+    uint16_t rca;
+    uint32_t card_status;
+    uint8_t sd_status[64];
+    int wp_switch;
+    int *wp_groups;
+    uint32_t size;
+    int blk_len;
+    uint32_t erase_start;
+    uint32_t erase_end;
+    uint8_t pwd[16];
+    int pwd_len;
+    int function_group[6];
+
+    int current_cmd;
+    int blk_written;
+    uint32_t data_start;
+    uint32_t data_offset;
+    uint8_t data[512];
+    void (*readonly_cb)(void *, int);
+    void (*inserted_cb)(void *, int);
+    void *opaque;
+    BlockDriverState *bdrv;
+};
+
+static void sd_set_status(SDState *sd)
+{
+    switch (sd->state) {
+    case sd_inactive_state:
+        sd->mode = sd_inactive;
+        break;
+
+    case sd_idle_state:
+    case sd_ready_state:
+    case sd_identification_state:
+        sd->mode = sd_card_identification_mode;
+        break;
+
+    case sd_standby_state:
+    case sd_transfer_state:
+    case sd_sendingdata_state:
+    case sd_receivingdata_state:
+    case sd_programming_state:
+    case sd_disconnect_state:
+        sd->mode = sd_data_transfer_mode;
+        break;
+    }
+
+    sd->card_status &= ~CURRENT_STATE;
+    sd->card_status |= sd->state << 9;
+}
+
+const sd_cmd_type_t sd_cmd_type[64] = {
+    sd_bc,   sd_none, sd_bcr,  sd_bcr,  sd_none, sd_none, sd_none, sd_ac,
+    sd_none, sd_ac,   sd_ac,   sd_adtc, sd_ac,   sd_ac,   sd_none, sd_ac,
+    sd_ac,   sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac,   sd_ac,   sd_adtc, sd_none,
+    sd_ac,   sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
+    sd_none, sd_none, sd_bc,   sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,
+    sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+};
+
+const sd_cmd_type_t sd_acmd_type[64] = {
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_ac,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_bcr,  sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+};
+
+static const int sd_cmd_class[64] = {
+    0,  0,  0,  0,  0,  9, 10,  0,  0,  0,  0,  1,  0,  0,  0,  0,
+    2,  2,  2,  2,  3,  3,  3,  3,  4,  4,  4,  4,  6,  6,  6,  6,
+    5,  5, 10, 10, 10, 10,  5,  9,  9,  9,  7,  7,  7,  7,  7,  7,
+    7,  7, 10,  7,  9,  9,  9,  8,  8, 10,  8,  8,  8,  8,  8,  8,
+};
+
+static uint8_t sd_crc7(void *message, size_t width)
+{
+    int i, bit;
+    uint8_t shift_reg = 0x00;
+    uint8_t *msg = (uint8_t *) message;
+
+    for (i = 0; i < width; i ++, msg ++)
+        for (bit = 7; bit >= 0; bit --) {
+            shift_reg <<= 1;
+            if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
+                shift_reg ^= 0x89;
+        }
+
+    return shift_reg;
+}
+
+static uint16_t sd_crc16(void *message, size_t width)
+{
+    int i, bit;
+    uint16_t shift_reg = 0x0000;
+    uint16_t *msg = (uint16_t *) message;
+    width <<= 1;
+
+    for (i = 0; i < width; i ++, msg ++)
+        for (bit = 15; bit >= 0; bit --) {
+            shift_reg <<= 1;
+            if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
+                shift_reg ^= 0x1011;
+        }
+
+    return shift_reg;
+}
+
+static void sd_set_ocr(SDState *sd)
+{
+    sd->ocr = 0x80fffff0;
+}
+
+static void sd_set_scr(SDState *sd)
+{
+    sd->scr[0] = 0x00;		/* SCR Structure */
+    sd->scr[1] = 0x2f;		/* SD Security Support */
+    sd->scr[2] = 0x00;
+    sd->scr[3] = 0x00;
+    sd->scr[4] = 0x00;
+    sd->scr[5] = 0x00;
+    sd->scr[6] = 0x00;
+    sd->scr[7] = 0x00;
+}
+
+#define MID	0xaa
+#define OID	"XY"
+#define PNM	"QEMU!"
+#define PRV	0x01
+#define MDT_YR	2006
+#define MDT_MON	2
+
+static void sd_set_cid(SDState *sd)
+{
+    sd->cid[0] = MID;		/* Fake card manufacturer ID (MID) */
+    sd->cid[1] = OID[0];	/* OEM/Application ID (OID) */
+    sd->cid[2] = OID[1];
+    sd->cid[3] = PNM[0];	/* Fake product name (PNM) */
+    sd->cid[4] = PNM[1];
+    sd->cid[5] = PNM[2];
+    sd->cid[6] = PNM[3];
+    sd->cid[7] = PNM[4];
+    sd->cid[8] = PRV;		/* Fake product revision (PRV) */
+    sd->cid[9] = 0xde;		/* Fake serial number (PSN) */
+    sd->cid[10] = 0xad;
+    sd->cid[11] = 0xbe;
+    sd->cid[12] = 0xef;
+    sd->cid[13] = 0x00 |	/* Manufacture date (MDT) */
+        ((MDT_YR - 2000) / 10);
+    sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
+    sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1;
+}
+
+#define HWBLOCK_SHIFT	9			/* 512 bytes */
+#define SECTOR_SHIFT	5			/* 16 kilobytes */
+#define WPGROUP_SHIFT	7			/* 2 megs */
+#define CMULT_SHIFT	9			/* 512 times HWBLOCK_SIZE */
+#define BLOCK_SIZE	(1 << (HWBLOCK_SHIFT))
+#define SECTOR_SIZE	(1 << (HWBLOCK_SHIFT + SECTOR_SHIFT))
+#define WPGROUP_SIZE	(1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT))
+
+static const uint8_t sd_csd_rw_mask[16] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe,
+};
+
+static void sd_set_csd(SDState *sd, uint32_t size)
+{
+    uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1;
+    uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
+    uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
+
+    sd->csd[0] = 0x00;		/* CSD structure */
+    sd->csd[1] = 0x26;		/* Data read access-time-1 */
+    sd->csd[2] = 0x00;		/* Data read access-time-2 */
+    sd->csd[3] = 0x5a;		/* Max. data transfer rate */
+    sd->csd[4] = 0x5f;		/* Card Command Classes */
+    sd->csd[5] = 0x50 |		/* Max. read data block length */
+        HWBLOCK_SHIFT;
+    sd->csd[6] = 0xe0 |		/* Partial block for read allowed */
+        ((csize >> 10) & 0x03);
+    sd->csd[7] = 0x00 |		/* Device size */
+        ((csize >> 2) & 0xff);
+    sd->csd[8] = 0x3f |		/* Max. read current */
+        ((csize << 6) & 0xc0);
+    sd->csd[9] = 0xfc |		/* Max. write current */
+        ((CMULT_SHIFT - 2) >> 1);
+    sd->csd[10] = 0x40 |	/* Erase sector size */
+        (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1);
+    sd->csd[11] = 0x00 |	/* Write protect group size */
+        ((sectsize << 7) & 0x80) | wpsize;
+    sd->csd[12] = 0x90 |	/* Write speed factor */
+        (HWBLOCK_SHIFT >> 2);
+    sd->csd[13] = 0x20 |	/* Max. write data block length */
+        ((HWBLOCK_SHIFT << 6) & 0xc0);
+    sd->csd[14] = 0x00;		/* File format group */
+    sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1;
+}
+
+static void sd_set_rca(SDState *sd)
+{
+    sd->rca += 0x4567;
+}
+
+#define CARD_STATUS_A	0x02004100
+#define CARD_STATUS_B	0x00c01e00
+#define CARD_STATUS_C	0xfd39a028
+
+static void sd_set_cardstatus(SDState *sd)
+{
+    sd->card_status = 0x00000100;
+}
+
+static void sd_set_sdstatus(SDState *sd)
+{
+    memset(sd->sd_status, 0, 64);
+}
+
+static int sd_req_crc_validate(struct sd_request_s *req)
+{
+    uint8_t buffer[5];
+    buffer[0] = 0x40 | req->cmd;
+    buffer[1] = (req->arg >> 24) & 0xff;
+    buffer[2] = (req->arg >> 16) & 0xff;
+    buffer[3] = (req->arg >> 8) & 0xff;
+    buffer[4] = (req->arg >> 0) & 0xff;
+    return 0;
+    return sd_crc7(buffer, 5) != req->crc;	/* TODO */
+}
+
+void sd_response_r1_make(SDState *sd,
+                         uint8_t *response, uint32_t last_status)
+{
+    uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND;
+    uint32_t status;
+
+    status = (sd->card_status & ~mask) | (last_status & mask);
+    sd->card_status &= ~CARD_STATUS_C | APP_CMD;
+
+    response[0] = (status >> 24) & 0xff;
+    response[1] = (status >> 16) & 0xff;
+    response[2] = (status >> 8) & 0xff;
+    response[3] = (status >> 0) & 0xff;
+}
+
+void sd_response_r3_make(SDState *sd, uint8_t *response)
+{
+    response[0] = (sd->ocr >> 24) & 0xff;
+    response[1] = (sd->ocr >> 16) & 0xff;
+    response[2] = (sd->ocr >> 8) & 0xff;
+    response[3] = (sd->ocr >> 0) & 0xff;
+}
+
+void sd_response_r6_make(SDState *sd, uint8_t *response)
+{
+    uint16_t arg;
+    uint16_t status;
+
+    arg = sd->rca;
+    status = ((sd->card_status >> 8) & 0xc000) |
+             ((sd->card_status >> 6) & 0x2000) |
+              (sd->card_status & 0x1fff);
+
+    response[0] = (arg >> 8) & 0xff;
+    response[1] = arg & 0xff;
+    response[2] = (status >> 8) & 0xff;
+    response[3] = status & 0xff;
+}
+
+static void sd_reset(SDState *sd, BlockDriverState *bdrv)
+{
+    uint32_t size;
+    uint64_t sect;
+
+    bdrv_get_geometry(bdrv, &sect);
+    sect <<= 9;
+
+    if (sect > 0x40000000)
+        size = 0x40000000;	/* 1 gig */
+    else
+        size = sect + 1;
+
+    sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+
+    sd->state = sd_idle_state;
+    sd->rca = 0x0000;
+    sd_set_ocr(sd);
+    sd_set_scr(sd);
+    sd_set_cid(sd);
+    sd_set_csd(sd, size);
+    sd_set_cardstatus(sd);
+    sd_set_sdstatus(sd);
+
+    sd->bdrv = bdrv;
+
+    sd->wp_switch = bdrv_is_read_only(bdrv);
+    sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect);
+    memset(sd->wp_groups, 0, sizeof(int) * sect);
+    memset(sd->function_group, 0, sizeof(int) * 6);
+    sd->erase_start = 0;
+    sd->erase_end = 0;
+    sd->size = size;
+    sd->blk_len = 0x200;
+    sd->pwd_len = 0;
+}
+
+static void sd_cardchange(void *opaque)
+{
+    SDState *sd = opaque;
+    if (sd->inserted_cb)
+        sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv));
+    if (bdrv_is_inserted(sd->bdrv)) {
+        sd_reset(sd, sd->bdrv);
+        if (sd->readonly_cb)
+            sd->readonly_cb(sd->opaque, sd->wp_switch);
+    }
+}
+
+SDState *sd_init(BlockDriverState *bs)
+{
+    SDState *sd;
+
+    sd = (SDState *) qemu_mallocz(sizeof(SDState));
+    sd_reset(sd, bs);
+    return sd;
+}
+
+void sd_set_cb(SDState *sd, void *opaque,
+                void (*readonly_cb)(void *, int),
+                void (*inserted_cb)(void *, int))
+{
+    sd->opaque = opaque;
+    sd->readonly_cb = readonly_cb;
+    sd->inserted_cb = inserted_cb;
+    if (sd->readonly_cb)
+        sd->readonly_cb(sd->opaque, bdrv_is_read_only(sd->bdrv));
+    if (sd->inserted_cb)
+        sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv));
+    bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
+}
+
+static void sd_erase(SDState *sd)
+{
+    int i, start, end;
+    if (!sd->erase_start || !sd->erase_end) {
+        sd->card_status |= ERASE_SEQ_ERROR;
+        return;
+    }
+
+    start = sd->erase_start >>
+            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+    end = sd->erase_end >>
+            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+    sd->erase_start = 0;
+    sd->erase_end = 0;
+    sd->csd[14] |= 0x40;
+
+    for (i = start; i <= end; i ++)
+        if (sd->wp_groups[i])
+            sd->card_status |= WP_ERASE_SKIP;
+}
+
+static uint32_t sd_wpbits(SDState *sd, uint32_t addr)
+{
+    uint32_t i, wpnum;
+    uint32_t ret = 0;
+
+    wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+
+    for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE)
+        if (addr < sd->size && sd->wp_groups[wpnum])
+            ret |= (1 << i);
+
+    return ret;
+}
+
+static void sd_function_switch(SDState *sd, uint32_t arg)
+{
+    int i, mode, new_func, crc;
+    mode = !!(arg & 0x80000000);
+
+    sd->data[0] = 0x00;		/* Maximum current consumption */
+    sd->data[1] = 0x01;
+    sd->data[2] = 0x80;		/* Supported group 6 functions */
+    sd->data[3] = 0x01;
+    sd->data[4] = 0x80;		/* Supported group 5 functions */
+    sd->data[5] = 0x01;
+    sd->data[6] = 0x80;		/* Supported group 4 functions */
+    sd->data[7] = 0x01;
+    sd->data[8] = 0x80;		/* Supported group 3 functions */
+    sd->data[9] = 0x01;
+    sd->data[10] = 0x80;	/* Supported group 2 functions */
+    sd->data[11] = 0x43;
+    sd->data[12] = 0x80;	/* Supported group 1 functions */
+    sd->data[13] = 0x03;
+    for (i = 0; i < 6; i ++) {
+        new_func = (arg >> (i * 4)) & 0x0f;
+        if (mode && new_func != 0x0f)
+            sd->function_group[i] = new_func;
+        sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4);
+    }
+    memset(&sd->data[17], 0, 47);
+    crc = sd_crc16(sd->data, 64);
+    sd->data[65] = crc >> 8;
+    sd->data[66] = crc & 0xff;
+}
+
+static inline int sd_wp_addr(SDState *sd, uint32_t addr)
+{
+    return sd->wp_groups[addr >>
+            (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
+}
+
+static void sd_lock_command(SDState *sd)
+{
+    int erase, lock, clr_pwd, set_pwd, pwd_len;
+    erase = !!(sd->data[0] & 0x08);
+    lock = sd->data[0] & 0x04;
+    clr_pwd = sd->data[0] & 0x02;
+    set_pwd = sd->data[0] & 0x01;
+
+    if (sd->blk_len > 1)
+        pwd_len = sd->data[1];
+    else
+        pwd_len = 0;
+
+    if (erase) {
+        if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 ||
+                        set_pwd || clr_pwd || lock || sd->wp_switch ||
+                        (sd->csd[14] & 0x20)) {
+            sd->card_status |= LOCK_UNLOCK_FAILED;
+            return;
+        }
+        memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
+                        (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
+        sd->csd[14] &= ~0x10;
+        sd->card_status &= ~CARD_IS_LOCKED;
+        sd->pwd_len = 0;
+        /* Erasing the entire card here! */
+        printf("SD: Card force-erased by CMD42\n");
+        return;
+    }
+
+    if (sd->blk_len < 2 + pwd_len ||
+                    pwd_len <= sd->pwd_len ||
+                    pwd_len > sd->pwd_len + 16) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    pwd_len -= sd->pwd_len;
+    if ((pwd_len && !set_pwd) ||
+                    (clr_pwd && (set_pwd || lock)) ||
+                    (lock && !sd->pwd_len && !set_pwd) ||
+                    (!set_pwd && !clr_pwd &&
+                     (((sd->card_status & CARD_IS_LOCKED) && lock) ||
+                      (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) {
+        sd->card_status |= LOCK_UNLOCK_FAILED;
+        return;
+    }
+
+    if (set_pwd) {
+        memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len);
+        sd->pwd_len = pwd_len;
+    }
+
+    if (clr_pwd) {
+        sd->pwd_len = 0;
+    }
+
+    if (lock)
+        sd->card_status |= CARD_IS_LOCKED;
+    else
+        sd->card_status &= ~CARD_IS_LOCKED;
+}
+
+static sd_rsp_type_t sd_normal_command(SDState *sd,
+                                       struct sd_request_s req)
+{
+    uint32_t rca = 0x0000;
+
+    if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
+        rca = req.arg >> 16;
+
+    DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
+    switch (req.cmd) {
+    /* Basic commands (Class 0 and Class 1) */
+    case 0:	/* CMD0:   GO_IDLE_STATE */
+        switch (sd->state) {
+        case sd_inactive_state:
+            return sd_r0;
+
+        default:
+            sd->state = sd_idle_state;
+            sd_reset(sd, sd->bdrv);
+            return sd_r0;
+        }
+        break;
+
+    case 2:	/* CMD2:   ALL_SEND_CID */
+        switch (sd->state) {
+        case sd_ready_state:
+            sd->state = sd_identification_state;
+            return sd_r2_i;
+
+        default:
+            break;
+        }
+        break;
+
+    case 3:	/* CMD3:   SEND_RELATIVE_ADDR */
+        switch (sd->state) {
+        case sd_identification_state:
+        case sd_standby_state:
+            sd->state = sd_standby_state;
+            sd_set_rca(sd);
+            return sd_r6;
+
+        default:
+            break;
+        }
+        break;
+
+    case 4:	/* CMD4:   SEND_DSR */
+        switch (sd->state) {
+        case sd_standby_state:
+            break;
+
+        default:
+            break;
+        }
+        break;
+
+    case 6:	/* CMD6:   SWITCH_FUNCTION */
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            sd_function_switch(sd, req.arg);
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 7:	/* CMD7:   SELECT/DESELECT_CARD */
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        case sd_transfer_state:
+        case sd_sendingdata_state:
+            if (sd->rca == rca)
+                break;
+
+            sd->state = sd_standby_state;
+            return sd_r1b;
+
+        case sd_disconnect_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_programming_state;
+            return sd_r1b;
+
+        case sd_programming_state:
+            if (sd->rca == rca)
+                break;
+
+            sd->state = sd_disconnect_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 9:	/* CMD9:   SEND_CSD */
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r2_s;
+
+        default:
+            break;
+        }
+        break;
+
+    case 10:	/* CMD10:  SEND_CID */
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r2_i;
+
+        default:
+            break;
+        }
+        break;
+
+    case 11:	/* CMD11:  READ_DAT_UNTIL_STOP */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = req.arg;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r0;
+
+        default:
+            break;
+        }
+        break;
+
+    case 12:	/* CMD12:  STOP_TRANSMISSION */
+        switch (sd->state) {
+        case sd_sendingdata_state:
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        case sd_receivingdata_state:
+            sd->state = sd_programming_state;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 13:	/* CMD13:  SEND_STATUS */
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 15:	/* CMD15:  GO_INACTIVE_STATE */
+        switch (sd->mode) {
+        case sd_data_transfer_mode:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_inactive_state;
+            return sd_r0;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Block read commands (Classs 2) */
+    case 16:	/* CMD16:  SET_BLOCKLEN */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (req.arg > (1 << HWBLOCK_SHIFT))
+                sd->card_status |= BLOCK_LEN_ERROR;
+            else
+                sd->blk_len = req.arg;
+
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 17:	/* CMD17:  READ_SINGLE_BLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = req.arg;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 18:	/* CMD18:  READ_MULTIPLE_BLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = req.arg;
+            sd->data_offset = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Block write commands (Class 4) */
+    case 24:	/* CMD24:  WRITE_SINGLE_BLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = req.arg;
+            sd->data_offset = 0;
+            sd->blk_written = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            if (sd_wp_addr(sd, sd->data_start))
+                sd->card_status |= WP_VIOLATION;
+            if (sd->csd[14] & 0x30)
+                sd->card_status |= WP_VIOLATION;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 25:	/* CMD25:  WRITE_MULTIPLE_BLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = req.arg;
+            sd->data_offset = 0;
+            sd->blk_written = 0;
+
+            if (sd->data_start + sd->blk_len > sd->size)
+                sd->card_status |= ADDRESS_ERROR;
+            if (sd_wp_addr(sd, sd->data_start))
+                sd->card_status |= WP_VIOLATION;
+            if (sd->csd[14] & 0x30)
+                sd->card_status |= WP_VIOLATION;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 26:	/* CMD26:  PROGRAM_CID */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 27:	/* CMD27:  PROGRAM_CSD */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Write protection (Class 6) */
+    case 28:	/* CMD28:  SET_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (req.arg >= sd->size) {
+                sd->card_status = ADDRESS_ERROR;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            sd->wp_groups[req.arg >> (HWBLOCK_SHIFT +
+                            SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 29:	/* CMD29:  CLR_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (req.arg >= sd->size) {
+                sd->card_status = ADDRESS_ERROR;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            sd->wp_groups[req.arg >> (HWBLOCK_SHIFT +
+                            SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 30:	/* CMD30:  SEND_WRITE_PROT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
+            sd->data_start = req.arg;
+            sd->data_offset = 0;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Erase commands (Class 5) */
+    case 32:	/* CMD32:  ERASE_WR_BLK_START */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->erase_start = req.arg;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 33:	/* CMD33:  ERASE_WR_BLK_END */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->erase_end = req.arg;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 38:	/* CMD38:  ERASE */
+        switch (sd->state) {
+        case sd_transfer_state:
+            if (sd->csd[14] & 0x30) {
+                sd->card_status |= WP_VIOLATION;
+                return sd_r1b;
+            }
+
+            sd->state = sd_programming_state;
+            sd_erase(sd);
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Lock card commands (Class 7) */
+    case 42:	/* CMD42:  LOCK_UNLOCK */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_receivingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Application specific commands (Class 8) */
+    case 55:	/* CMD55:  APP_CMD */
+        if (sd->rca != rca)
+            return sd_r0;
+
+        sd->card_status |= APP_CMD;
+        return sd_r1;
+
+    case 56:	/* CMD56:  GEN_CMD */
+        printf("SD: GEN_CMD 0x%08x\n", req.arg);
+
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->data_offset = 0;
+            if (req.arg & 1)
+                sd->state = sd_sendingdata_state;
+            else
+                sd->state = sd_receivingdata_state;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    default:
+        sd->card_status |= ILLEGAL_COMMAND;
+
+        printf("SD: Unknown CMD%i\n", req.cmd);
+        return sd_r0;
+    }
+
+    sd->card_status |= ILLEGAL_COMMAND;
+    printf("SD: CMD%i in a wrong state\n", req.cmd);
+    return sd_r0;
+}
+
+static sd_rsp_type_t sd_app_command(SDState *sd,
+                                    struct sd_request_s req) {
+    uint32_t rca;
+
+    if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
+        rca = req.arg >> 16;
+
+    DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg);
+    switch (req.cmd) {
+    case 6:	/* ACMD6:  SET_BUS_WIDTH */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->sd_status[0] &= 0x3f;
+            sd->sd_status[0] |= (req.arg & 0x03) << 6;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 13:	/* ACMD13: SD_STATUS */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 22:	/* ACMD22: SEND_NUM_WR_BLOCKS */
+        switch (sd->state) {
+        case sd_transfer_state:
+            *(uint32_t *) sd->data = sd->blk_written;
+
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 23:	/* ACMD23: SET_WR_BLK_ERASE_COUNT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 41:	/* ACMD41: SD_APP_OP_COND */
+        switch (sd->state) {
+        case sd_idle_state:
+            /* We accept any voltage.  10000 V is nothing.  */
+            if (req.arg)
+                sd->state = sd_ready_state;
+
+            return sd_r3;
+
+        default:
+            break;
+        }
+        break;
+
+    case 42:	/* ACMD42: SET_CLR_CARD_DETECT */
+        switch (sd->state) {
+        case sd_transfer_state:
+            /* Bringing in the 50KOhm pull-up resistor... Done.  */
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    case 51:	/* ACMD51: SEND_SCR */
+        switch (sd->state) {
+        case sd_transfer_state:
+            sd->state = sd_sendingdata_state;
+            sd->data_start = 0;
+            sd->data_offset = 0;
+            return sd_r1;
+
+        default:
+            break;
+        }
+        break;
+
+    default:
+        /* Fall back to standard commands.  */
+        sd->card_status &= ~APP_CMD;
+        return sd_normal_command(sd, req);
+    }
+
+    printf("SD: ACMD%i in a wrong state\n", req.cmd);
+    return sd_r0;
+}
+
+int sd_do_command(SDState *sd, struct sd_request_s *req,
+                  uint8_t *response) {
+    uint32_t last_status = sd->card_status;
+    sd_rsp_type_t rtype;
+    int rsplen;
+
+    if (!bdrv_is_inserted(sd->bdrv)) {
+        return 0;
+    }
+
+    if (sd_req_crc_validate(req)) {
+        sd->card_status &= ~COM_CRC_ERROR;
+        return 0;
+    }
+
+    sd->card_status &= ~CARD_STATUS_B;
+    sd_set_status(sd);
+
+    if (last_status & CARD_IS_LOCKED)
+        if (((last_status & APP_CMD) &&
+                                 req->cmd == 41) ||
+                        (!(last_status & APP_CMD) &&
+                         (sd_cmd_class[req->cmd] == 0 ||
+                          sd_cmd_class[req->cmd] == 7 ||
+                          req->cmd == 16 || req->cmd == 55))) {
+            sd->card_status |= ILLEGAL_COMMAND;
+            printf("SD: Card is locked\n");
+            return 0;
+        }
+
+    if (last_status & APP_CMD) {
+        rtype = sd_app_command(sd, *req);
+        sd->card_status &= ~APP_CMD;
+    } else
+        rtype = sd_normal_command(sd, *req);
+
+    sd->current_cmd = req->cmd;
+
+    switch (rtype) {
+    case sd_r1:
+    case sd_r1b:
+        sd_response_r1_make(sd, response, last_status);
+        rsplen = 4;
+        break;
+
+    case sd_r2_i:
+        memcpy(response, sd->cid, sizeof(sd->cid));
+        response[7] |= 1;
+        rsplen = 16;
+        break;
+
+    case sd_r2_s:
+        memcpy(response, sd->csd, sizeof(sd->csd));
+        response[7] |= 1;
+        rsplen = 16;
+        break;
+
+    case sd_r3:
+        sd_response_r3_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r6:
+        sd_response_r6_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r0:
+    default:
+        rsplen = 0;
+        break;
+    }
+
+    if (sd->card_status & ILLEGAL_COMMAND)
+        rsplen = 0;
+
+#ifdef DEBUG_SD
+    if (rsplen) {
+        int i;
+        DPRINTF("Response:");
+        for (i = 0; i < rsplen; i++)
+            printf(" %02x", response[i]);
+        printf(" state %d\n", sd->state);
+    } else {
+        DPRINTF("No response %d\n", sd->state);
+    }
+#endif
+
+    return rsplen;
+}
+
+/* No real need for 64 bit addresses here */
+static void sd_blk_read(BlockDriverState *bdrv,
+                void *data, uint32_t addr, uint32_t len)
+{
+    uint8_t buf[512];
+    uint32_t end = addr + len;
+
+    if (!bdrv || bdrv_read(bdrv, addr >> 9, buf, 1) == -1) {
+        printf("sd_blk_read: read error on host side\n");
+        return;
+    }
+
+    if (end > (addr & ~511) + 512) {
+        memcpy(data, buf + (addr & 511), 512 - (addr & 511));
+
+        if (bdrv_read(bdrv, end >> 9, buf, 1) == -1) {
+            printf("sd_blk_read: read error on host side\n");
+            return;
+        }
+        memcpy(data + 512 - (addr & 511), buf, end & 511);
+    } else
+        memcpy(data, buf + (addr & 511), len);
+}
+
+static void sd_blk_write(BlockDriverState *bdrv,
+                void *data, uint32_t addr, uint32_t len)
+{
+    uint8_t buf[512];
+    uint32_t end = addr + len;
+
+    if ((addr & 511) || len < 512)
+        if (!bdrv || bdrv_read(bdrv, addr >> 9, buf, 1) == -1) {
+            printf("sd_blk_write: read error on host side\n");
+            return;
+        }
+
+    if (end > (addr & ~511) + 512) {
+        memcpy(buf + (addr & 511), data, 512 - (addr & 511));
+        if (bdrv_write(bdrv, addr >> 9, buf, 1) == -1) {
+            printf("sd_blk_write: write error on host side\n");
+            return;
+        }
+
+        if (bdrv_read(bdrv, end >> 9, buf, 1) == -1) {
+            printf("sd_blk_write: read error on host side\n");
+            return;
+        }
+        memcpy(buf, data + 512 - (addr & 511), end & 511);
+        if (bdrv_write(bdrv, end >> 9, buf, 1) == -1)
+            printf("sd_blk_write: write error on host side\n");
+    } else {
+        memcpy(buf + (addr & 511), data, len);
+        if (!bdrv || bdrv_write(bdrv, addr >> 9, buf, 1) == -1)
+            printf("sd_blk_write: write error on host side\n");
+    }
+}
+
+#define BLK_READ_BLOCK(a, len)	sd_blk_read(sd->bdrv, sd->data, a, len)
+#define BLK_WRITE_BLOCK(a, len)	sd_blk_write(sd->bdrv, sd->data, a, len)
+#define APP_READ_BLOCK(a, len)	memset(sd->data, 0xec, len)
+#define APP_WRITE_BLOCK(a, len)
+
+void sd_write_data(SDState *sd, uint8_t value)
+{
+    int i;
+
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv))
+        return;
+
+    if (sd->state != sd_receivingdata_state) {
+        printf("sd_write_data: not in Receiving-Data state\n");
+        return;
+    }
+
+    if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
+        return;
+
+    switch (sd->current_cmd) {
+    case 24:	/* CMD24:  WRITE_SINGLE_BLOCK */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->blk_written ++;
+            sd->csd[14] |= 0x40;
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 25:	/* CMD25:  WRITE_MULTIPLE_BLOCK */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->blk_written ++;
+            sd->data_start += sd->blk_len;
+            sd->data_offset = 0;
+            if (sd->data_start + sd->blk_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+            if (sd_wp_addr(sd, sd->data_start)) {
+                sd->card_status |= WP_VIOLATION;
+                break;
+            }
+            sd->csd[14] |= 0x40;
+
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_receivingdata_state;
+        }
+        break;
+
+    case 26:	/* CMD26:  PROGRAM_CID */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sizeof(sd->cid)) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            for (i = 0; i < sizeof(sd->cid); i ++)
+                if ((sd->cid[i] | 0x00) != sd->data[i])
+                    sd->card_status |= CID_CSD_OVERWRITE;
+
+            if (!(sd->card_status & CID_CSD_OVERWRITE))
+                for (i = 0; i < sizeof(sd->cid); i ++) {
+                    sd->cid[i] |= 0x00;
+                    sd->cid[i] &= sd->data[i];
+                }
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 27:	/* CMD27:  PROGRAM_CSD */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sizeof(sd->csd)) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            for (i = 0; i < sizeof(sd->csd); i ++)
+                if ((sd->csd[i] | sd_csd_rw_mask[i]) !=
+                    (sd->data[i] | sd_csd_rw_mask[i]))
+                    sd->card_status |= CID_CSD_OVERWRITE;
+
+            /* Copy flag (OTP) & Permanent write protect */
+            if (sd->csd[14] & ~sd->data[14] & 0x60)
+                sd->card_status |= CID_CSD_OVERWRITE;
+
+            if (!(sd->card_status & CID_CSD_OVERWRITE))
+                for (i = 0; i < sizeof(sd->csd); i ++) {
+                    sd->csd[i] |= sd_csd_rw_mask[i];
+                    sd->csd[i] &= sd->data[i];
+                }
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 42:	/* CMD42:  LOCK_UNLOCK */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->state = sd_programming_state;
+            sd_lock_command(sd);
+            /* Bzzzzzzztt .... Operation complete.  */
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    case 56:	/* CMD56:  GEN_CMD */
+        sd->data[sd->data_offset ++] = value;
+        if (sd->data_offset >= sd->blk_len) {
+            APP_WRITE_BLOCK(sd->data_start, sd->data_offset);
+            sd->state = sd_transfer_state;
+        }
+        break;
+
+    default:
+        printf("sd_write_data: unknown command\n");
+        break;
+    }
+}
+
+uint8_t sd_read_data(SDState *sd)
+{
+    /* TODO: Append CRCs */
+    uint8_t ret;
+
+    if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv))
+        return 0x00;
+
+    if (sd->state != sd_sendingdata_state) {
+        printf("sd_read_data: not in Sending-Data state\n");
+        return 0x00;
+    }
+
+    if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
+        return 0x00;
+
+    switch (sd->current_cmd) {
+    case 6:	/* CMD6:   SWITCH_FUNCTION */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 64)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 11:	/* CMD11:  READ_DAT_UNTIL_STOP */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, sd->blk_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= sd->blk_len) {
+            sd->data_start += sd->blk_len;
+            sd->data_offset = 0;
+            if (sd->data_start + sd->blk_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+        }
+        break;
+
+    case 13:	/* ACMD13: SD_STATUS */
+        ret = sd->sd_status[sd->data_offset ++];
+
+        if (sd->data_offset >= sizeof(sd->sd_status))
+            sd->state = sd_transfer_state;
+        break;
+
+    case 17:	/* CMD17:  READ_SINGLE_BLOCK */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, sd->blk_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= sd->blk_len)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 18:	/* CMD18:  READ_MULTIPLE_BLOCK */
+        if (sd->data_offset == 0)
+            BLK_READ_BLOCK(sd->data_start, sd->blk_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= sd->blk_len) {
+            sd->data_start += sd->blk_len;
+            sd->data_offset = 0;
+            if (sd->data_start + sd->blk_len > sd->size) {
+                sd->card_status |= ADDRESS_ERROR;
+                break;
+            }
+        }
+        break;
+
+    case 22:	/* ACMD22: SEND_NUM_WR_BLOCKS */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 4)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 30:	/* CMD30:  SEND_WRITE_PROT */
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= 4)
+            sd->state = sd_transfer_state;
+        break;
+
+    case 51:	/* ACMD51: SEND_SCR */
+        ret = sd->scr[sd->data_offset ++];
+
+        if (sd->data_offset >= sizeof(sd->scr))
+            sd->state = sd_transfer_state;
+        break;
+
+    case 56:	/* CMD56:  GEN_CMD */
+        if (sd->data_offset == 0)
+            APP_READ_BLOCK(sd->data_start, sd->blk_len);
+        ret = sd->data[sd->data_offset ++];
+
+        if (sd->data_offset >= sd->blk_len)
+            sd->state = sd_transfer_state;
+        break;
+
+    default:
+        printf("sd_read_data: unknown command\n");
+        return 0x00;
+    }
+
+    return ret;
+}
+
+int sd_data_ready(SDState *sd)
+{
+    return sd->state == sd_sendingdata_state;
+}
diff --git a/hw/sd.h b/hw/sd.h
new file mode 100644
index 0000000..ab20064
--- /dev/null
+++ b/hw/sd.h
@@ -0,0 +1,82 @@
+/*
+ * SD Memory Card emulation.  Mostly correct for MMC too.
+ *
+ * Copyright (c) 2006 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef __hw_sd_h
+#define __hw_sd_h		1
+
+#include <vl.h>
+
+#define OUT_OF_RANGE		(1 << 31)
+#define ADDRESS_ERROR		(1 << 30)
+#define BLOCK_LEN_ERROR		(1 << 29)
+#define ERASE_SEQ_ERROR		(1 << 28)
+#define ERASE_PARAM		(1 << 27)
+#define WP_VIOLATION		(1 << 26)
+#define CARD_IS_LOCKED		(1 << 25)
+#define LOCK_UNLOCK_FAILED	(1 << 24)
+#define COM_CRC_ERROR		(1 << 23)
+#define ILLEGAL_COMMAND		(1 << 22)
+#define CARD_ECC_FAILED		(1 << 21)
+#define CC_ERROR		(1 << 20)
+#define SD_ERROR		(1 << 19)
+#define CID_CSD_OVERWRITE	(1 << 16)
+#define WP_ERASE_SKIP		(1 << 15)
+#define CARD_ECC_DISABLED	(1 << 14)
+#define ERASE_RESET		(1 << 13)
+#define CURRENT_STATE		(7 << 9)
+#define READY_FOR_DATA		(1 << 8)
+#define APP_CMD			(1 << 5)
+#define AKE_SEQ_ERROR		(1 << 3)
+
+typedef enum {
+    sd_none = -1,
+    sd_bc = 0,	/* broadcast -- no response */
+    sd_bcr,	/* broadcast with response */
+    sd_ac,	/* addressed -- no data transfer */
+    sd_adtc,	/* addressed with data transfer */
+} sd_cmd_type_t;
+
+struct sd_request_s {
+    uint8_t cmd;
+    uint32_t arg;
+    uint8_t crc;
+};
+
+typedef struct SDState SDState;
+
+SDState *sd_init(BlockDriverState *bs);
+int sd_do_command(SDState *sd, struct sd_request_s *req,
+                  uint8_t *response);
+void sd_write_data(SDState *sd, uint8_t value);
+uint8_t sd_read_data(SDState *sd);
+void sd_set_cb(SDState *sd, void *opaque,
+               void (*readonly_cb)(void *, int),
+               void (*inserted_cb)(void *, int));
+int sd_data_ready(SDState *sd);
+
+#endif	/* __hw_sd_h */
diff --git a/hw/serial.c b/hw/serial.c
index a88aec1..36a7cc4 100644
--- a/hw/serial.c
+++ b/hw/serial.c
@@ -1,8 +1,8 @@
 /*
  * QEMU 16450 UART emulation
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -83,12 +83,10 @@
     /* NOTE: this hidden state is necessary for tx irq generation as
        it can be reset while reading iir */
     int thr_ipending;
-    SetIRQFunc *set_irq;
-    void *irq_opaque;
-    int irq;
+    qemu_irq irq;
     CharDriverState *chr;
     int last_break_enable;
-    target_ulong base;
+    target_phys_addr_t base;
     int it_shift;
 };
 
@@ -102,9 +100,9 @@
         s->iir = UART_IIR_NO_INT;
     }
     if (s->iir != UART_IIR_NO_INT) {
-        s->set_irq(s->irq_opaque, s->irq, 1);
+        qemu_irq_raise(s->irq);
     } else {
-        s->set_irq(s->irq_opaque, s->irq, 0);
+        qemu_irq_lower(s->irq);
     }
 }
 
@@ -121,7 +119,7 @@
     } else {
             parity = 'N';
     }
-    if (s->lcr & 0x04) 
+    if (s->lcr & 0x04)
         stop_bits = 2;
     else
         stop_bits = 1;
@@ -135,7 +133,7 @@
     ssp.stop_bits = stop_bits;
     qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
 #if 0
-    printf("speed=%d parity=%c data=%d stop=%d\n", 
+    printf("speed=%d parity=%c data=%d stop=%d\n",
            speed, parity, data_bits, stop_bits);
 #endif
 }
@@ -144,7 +142,7 @@
 {
     SerialState *s = opaque;
     unsigned char ch;
-    
+
     addr &= 7;
 #ifdef DEBUG_SERIAL
     printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
@@ -189,7 +187,7 @@
             break_enable = (val >> 6) & 1;
             if (break_enable != s->last_break_enable) {
                 s->last_break_enable = break_enable;
-                qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, 
+                qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
                                &break_enable);
             }
         }
@@ -217,7 +215,7 @@
     default:
     case 0:
         if (s->lcr & UART_LCR_DLAB) {
-            ret = s->divider & 0xff; 
+            ret = s->divider & 0xff;
         } else {
             ret = s->rbr;
             s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
@@ -345,16 +343,13 @@
 }
 
 /* If fd is zero, it means that the serial device uses the console */
-SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
-                         int base, int irq, CharDriverState *chr)
+SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr)
 {
     SerialState *s;
 
     s = qemu_mallocz(sizeof(SerialState));
     if (!s)
         return NULL;
-    s->set_irq = set_irq;
-    s->irq_opaque = opaque;
     s->irq = irq;
     s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
     s->iir = UART_IIR_NO_INT;
@@ -371,48 +366,62 @@
 }
 
 /* Memory mapped interface */
-static uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
+uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
 {
     SerialState *s = opaque;
 
     return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
 }
 
-static void serial_mm_writeb (void *opaque,
-                              target_phys_addr_t addr, uint32_t value)
+void serial_mm_writeb (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
 {
     SerialState *s = opaque;
 
     serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
 }
 
-static uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
+uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
 {
     SerialState *s = opaque;
+    uint32_t val;
 
-    return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
+    val = serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap16(val);
+#endif
+    return val;
 }
 
-static void serial_mm_writew (void *opaque,
-                              target_phys_addr_t addr, uint32_t value)
+void serial_mm_writew (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
 {
     SerialState *s = opaque;
-
+#ifdef TARGET_WORDS_BIGENDIAN
+    value = bswap16(value);
+#endif
     serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
 }
 
-static uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
+uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
 {
     SerialState *s = opaque;
+    uint32_t val;
 
-    return serial_ioport_read(s, (addr - s->base) >> s->it_shift);
+    val = serial_ioport_read(s, (addr - s->base) >> s->it_shift);
+#ifdef TARGET_WORDS_BIGENDIAN
+    val = bswap32(val);
+#endif
+    return val;
 }
 
-static void serial_mm_writel (void *opaque,
-                              target_phys_addr_t addr, uint32_t value)
+void serial_mm_writel (void *opaque,
+                       target_phys_addr_t addr, uint32_t value)
 {
     SerialState *s = opaque;
-
+#ifdef TARGET_WORDS_BIGENDIAN
+    value = bswap32(value);
+#endif
     serial_ioport_write(s, (addr - s->base) >> s->it_shift, value);
 }
 
@@ -428,9 +437,9 @@
     &serial_mm_writel,
 };
 
-SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
-                             target_ulong base, int it_shift,
-                             int irq, CharDriverState *chr)
+SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
+                             qemu_irq irq, CharDriverState *chr,
+                             int ioregister)
 {
     SerialState *s;
     int s_io_memory;
@@ -438,8 +447,6 @@
     s = qemu_mallocz(sizeof(SerialState));
     if (!s)
         return NULL;
-    s->set_irq = set_irq;
-    s->irq_opaque = opaque;
     s->irq = irq;
     s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
     s->iir = UART_IIR_NO_INT;
@@ -449,9 +456,11 @@
 
     register_savevm("serial", base, 2, serial_save, serial_load, s);
 
-    s_io_memory = cpu_register_io_memory(0, serial_mm_read,
-                                         serial_mm_write, s);
-    cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+    if (ioregister) {
+        s_io_memory = cpu_register_io_memory(0, serial_mm_read,
+                                             serial_mm_write, s);
+        cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+    }
     s->chr = chr;
     qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1,
                           serial_event, s);
diff --git a/hw/sh7750.c b/hw/sh7750.c
index 164ce71..bd3d31e 100644
--- a/hw/sh7750.c
+++ b/hw/sh7750.c
@@ -1,8 +1,8 @@
 /*
  * SH7750 device
- * 
+ *
  * Copyright (c) 2005 Samuel Tardieu
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -27,13 +27,6 @@
 #include "sh7750_regs.h"
 #include "sh7750_regnames.h"
 
-typedef struct {
-    uint8_t data[16];
-    uint8_t length;		/* Number of characters in the FIFO */
-    uint8_t write_idx;		/* Index of first character to write */
-    uint8_t read_idx;		/* Index of first character to read */
-} fifo;
-
 #define NB_DEVICES 4
 
 typedef struct SH7750State {
@@ -43,34 +36,6 @@
     uint32_t periph_freq;
     /* SDRAM controller */
     uint16_t rfcr;
-    /* First serial port */
-    CharDriverState *serial1;
-    uint8_t scscr1;
-    uint8_t scsmr1;
-    uint8_t scbrr1;
-    uint8_t scssr1;
-    uint8_t scssr1_read;
-    uint8_t sctsr1;
-    uint8_t sctsr1_loaded;
-    uint8_t sctdr1;
-    uint8_t scrdr1;
-    /* Second serial port */
-    CharDriverState *serial2;
-    uint16_t sclsr2;
-    uint16_t scscr2;
-    uint16_t scfcr2;
-    uint16_t scfsr2;
-    uint16_t scsmr2;
-    uint8_t scbrr2;
-    fifo serial2_receive_fifo;
-    fifo serial2_transmit_fifo;
-    /* Timers */
-    uint8_t tstr;
-    /* Timer 0 */
-    QEMUTimer *timer0;
-    uint16_t tcr0;
-    uint32_t tcor0;
-    uint32_t tcnt0;
     /* IO ports */
     uint16_t gpioic;
     uint32_t pctra;
@@ -86,343 +51,19 @@
     uint16_t periph_pdtrb;	/* Imposed by the peripherals */
     uint16_t periph_portdirb;	/* Direction seen from the peripherals */
     sh7750_io_device *devices[NB_DEVICES];	/* External peripherals */
+
+    uint16_t icr;
+    uint16_t ipra;
+    uint16_t iprb;
+    uint16_t iprc;
+    uint16_t iprd;
+    uint32_t intpri00;
+    uint32_t intmsk00;
     /* Cache */
     uint32_t ccr;
+
 } SH7750State;
 
-/**********************************************************************
- Timers
-**********************************************************************/
-
-/* XXXXX At this time, timer0 works in underflow only mode, that is
-   the value of tcnt0 is read at alarm computation time and cannot
-   be read back by the guest OS */
-
-static void start_timer0(SH7750State * s)
-{
-    uint64_t now, next, prescaler;
-
-    if ((s->tcr0 & 6) == 6) {
-	fprintf(stderr, "rtc clock for timer 0 not supported\n");
-	assert(0);
-    }
-
-    if ((s->tcr0 & 7) == 5) {
-	fprintf(stderr, "timer 0 configuration not supported\n");
-	assert(0);
-    }
-
-    if ((s->tcr0 & 4) == 4)
-	prescaler = 1024;
-    else
-	prescaler = 4 << (s->tcr0 & 3);
-
-    now = qemu_get_clock(vm_clock);
-    /* XXXXX */
-    next =
-	now + muldiv64(prescaler * s->tcnt0, ticks_per_sec,
-		       s->periph_freq);
-    if (next == now)
-	next = now + 1;
-    fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next);
-    fprintf(stderr, "timer will underflow in %f seconds\n",
-	    (float) (next - now) / (float) ticks_per_sec);
-
-    qemu_mod_timer(s->timer0, next);
-}
-
-static void timer_start_changed(SH7750State * s)
-{
-    if (s->tstr & SH7750_TSTR_STR0) {
-	start_timer0(s);
-    } else {
-	fprintf(stderr, "timer 0 is stopped\n");
-	qemu_del_timer(s->timer0);
-    }
-}
-
-static void timer0_cb(void *opaque)
-{
-    SH7750State *s = opaque;
-
-    s->tcnt0 = (uint32_t) 0;	/* XXXXX */
-    if (--s->tcnt0 == (uint32_t) - 1) {
-	fprintf(stderr, "timer 0 underflow\n");
-	s->tcnt0 = s->tcor0;
-	s->tcr0 |= SH7750_TCR_UNF;
-	if (s->tcr0 & SH7750_TCR_UNIE) {
-	    fprintf(stderr,
-		    "interrupt generation for timer 0 not supported\n");
-	    assert(0);
-	}
-    }
-    start_timer0(s);
-}
-
-static void init_timers(SH7750State * s)
-{
-    s->tcor0 = 0xffffffff;
-    s->tcnt0 = 0xffffffff;
-    s->timer0 = qemu_new_timer(vm_clock, &timer0_cb, s);
-}
-
-/**********************************************************************
- First serial port
-**********************************************************************/
-
-static int serial1_can_receive(void *opaque)
-{
-    SH7750State *s = opaque;
-
-    return s->scscr1 & SH7750_SCSCR_RE;
-}
-
-static void serial1_receive_char(SH7750State * s, uint8_t c)
-{
-    if (s->scssr1 & SH7750_SCSSR1_RDRF) {
-	s->scssr1 |= SH7750_SCSSR1_ORER;
-	return;
-    }
-
-    s->scrdr1 = c;
-    s->scssr1 |= SH7750_SCSSR1_RDRF;
-}
-
-static void serial1_receive(void *opaque, const uint8_t * buf, int size)
-{
-    SH7750State *s = opaque;
-    int i;
-
-    for (i = 0; i < size; i++) {
-	serial1_receive_char(s, buf[i]);
-    }
-}
-
-static void serial1_event(void *opaque, int event)
-{
-    assert(0);
-}
-
-static void serial1_maybe_send(SH7750State * s)
-{
-    uint8_t c;
-
-    if (s->scssr1 & SH7750_SCSSR1_TDRE)
-	return;
-    c = s->sctdr1;
-    s->scssr1 |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND;
-    if (s->scscr1 & SH7750_SCSCR_TIE) {
-	fprintf(stderr, "interrupts for serial port 1 not implemented\n");
-	assert(0);
-    }
-    /* XXXXX Check for errors in write */
-    qemu_chr_write(s->serial1, &c, 1);
-}
-
-static void serial1_change_scssr1(SH7750State * s, uint8_t mem_value)
-{
-    uint8_t new_flags;
-
-    /* If transmit disable, TDRE and TEND stays up */
-    if ((s->scscr1 & SH7750_SCSCR_TE) == 0) {
-	mem_value |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND;
-    }
-
-    /* Only clear bits which have been read before and do not set any bit
-       in the flags */
-    new_flags = s->scssr1 & ~s->scssr1_read;	/* Preserve unread flags */
-    new_flags &= mem_value | ~s->scssr1_read;	/* Clear read flags */
-
-    s->scssr1 = (new_flags & 0xf8) | (mem_value & 1);
-    s->scssr1_read &= mem_value;
-
-    /* If TDRE has been cleared, TEND will also be cleared */
-    if ((s->scssr1 & SH7750_SCSSR1_TDRE) == 0) {
-	s->scssr1 &= ~SH7750_SCSSR1_TEND;
-    }
-
-    /* Check for transmission to start */
-    serial1_maybe_send(s);
-}
-
-static void serial1_update_parameters(SH7750State * s)
-{
-    QEMUSerialSetParams ssp;
-
-    if (s->scsmr1 & SH7750_SCSMR_CHR_7)
-	ssp.data_bits = 7;
-    else
-	ssp.data_bits = 8;
-    if (s->scsmr1 & SH7750_SCSMR_PE) {
-	if (s->scsmr1 & SH7750_SCSMR_PM_ODD)
-	    ssp.parity = 'O';
-	else
-	    ssp.parity = 'E';
-    } else
-	ssp.parity = 'N';
-    if (s->scsmr1 & SH7750_SCSMR_STOP_2)
-	ssp.stop_bits = 2;
-    else
-	ssp.stop_bits = 1;
-    fprintf(stderr, "SCSMR1=%04x SCBRR1=%02x\n", s->scsmr1, s->scbrr1);
-    ssp.speed = s->periph_freq /
-	(32 * s->scbrr1 * (1 << (2 * (s->scsmr1 & 3)))) - 1;
-    fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n",
-	    ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed);
-    qemu_chr_ioctl(s->serial1, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-}
-
-static void scscr1_changed(SH7750State * s)
-{
-    if (s->scscr1 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) {
-	if (!s->serial1) {
-	    fprintf(stderr, "serial port 1 not bound to anything\n");
-	    assert(0);
-	}
-	serial1_update_parameters(s);
-    }
-    if ((s->scscr1 & SH7750_SCSCR_RE) == 0) {
-	s->scssr1 |= SH7750_SCSSR1_TDRE;
-    }
-}
-
-static void init_serial1(SH7750State * s, int serial_nb)
-{
-    CharDriverState *chr;
-
-    s->scssr1 = 0x84;
-    chr = serial_hds[serial_nb];
-    if (!chr) {
-	fprintf(stderr,
-		"no serial port associated to SH7750 first serial port\n");
-	return;
-    }
-
-    s->serial1 = chr;
-    qemu_chr_add_handlers(chr, serial1_can_receive,
-			  serial1_receive, serial1_event, s);
-}
-
-/**********************************************************************
- Second serial port
-**********************************************************************/
-
-static int serial2_can_receive(void *opaque)
-{
-    SH7750State *s = opaque;
-    static uint8_t max_fifo_size[] = { 15, 1, 4, 6, 8, 10, 12, 14 };
-
-    return s->serial2_receive_fifo.length <
-	max_fifo_size[(s->scfcr2 >> 9) & 7];
-}
-
-static void serial2_adjust_receive_flags(SH7750State * s)
-{
-    static uint8_t max_fifo_size[] = { 1, 4, 8, 14 };
-
-    /* XXXXX Add interrupt generation */
-    if (s->serial2_receive_fifo.length >=
-	max_fifo_size[(s->scfcr2 >> 7) & 3]) {
-	s->scfsr2 |= SH7750_SCFSR2_RDF;
-	s->scfsr2 &= ~SH7750_SCFSR2_DR;
-    } else {
-	s->scfsr2 &= ~SH7750_SCFSR2_RDF;
-	if (s->serial2_receive_fifo.length > 0)
-	    s->scfsr2 |= SH7750_SCFSR2_DR;
-	else
-	    s->scfsr2 &= ~SH7750_SCFSR2_DR;
-    }
-}
-
-static void serial2_append_char(SH7750State * s, uint8_t c)
-{
-    if (s->serial2_receive_fifo.length == 16) {
-	/* Overflow */
-	s->sclsr2 |= SH7750_SCLSR2_ORER;
-	return;
-    }
-
-    s->serial2_receive_fifo.data[s->serial2_receive_fifo.write_idx++] = c;
-    s->serial2_receive_fifo.length++;
-    serial2_adjust_receive_flags(s);
-}
-
-static void serial2_receive(void *opaque, const uint8_t * buf, int size)
-{
-    SH7750State *s = opaque;
-    int i;
-
-    for (i = 0; i < size; i++)
-	serial2_append_char(s, buf[i]);
-}
-
-static void serial2_event(void *opaque, int event)
-{
-    /* XXXXX */
-    assert(0);
-}
-
-static void serial2_update_parameters(SH7750State * s)
-{
-    QEMUSerialSetParams ssp;
-
-    if (s->scsmr2 & SH7750_SCSMR_CHR_7)
-	ssp.data_bits = 7;
-    else
-	ssp.data_bits = 8;
-    if (s->scsmr2 & SH7750_SCSMR_PE) {
-	if (s->scsmr2 & SH7750_SCSMR_PM_ODD)
-	    ssp.parity = 'O';
-	else
-	    ssp.parity = 'E';
-    } else
-	ssp.parity = 'N';
-    if (s->scsmr2 & SH7750_SCSMR_STOP_2)
-	ssp.stop_bits = 2;
-    else
-	ssp.stop_bits = 1;
-    fprintf(stderr, "SCSMR2=%04x SCBRR2=%02x\n", s->scsmr2, s->scbrr2);
-    ssp.speed = s->periph_freq /
-	(32 * s->scbrr2 * (1 << (2 * (s->scsmr2 & 3)))) - 1;
-    fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n",
-	    ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed);
-    qemu_chr_ioctl(s->serial2, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-}
-
-static void scscr2_changed(SH7750State * s)
-{
-    if (s->scscr2 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) {
-	if (!s->serial2) {
-	    fprintf(stderr, "serial port 2 not bound to anything\n");
-	    assert(0);
-	}
-	serial2_update_parameters(s);
-    }
-}
-
-static void init_serial2(SH7750State * s, int serial_nb)
-{
-    CharDriverState *chr;
-
-    s->scfsr2 = 0x0060;
-
-    chr = serial_hds[serial_nb];
-    if (!chr) {
-	fprintf(stderr,
-		"no serial port associated to SH7750 second serial port\n");
-	return;
-    }
-
-    s->serial2 = chr;
-    qemu_chr_add_handlers(chr, serial2_can_receive,
-			  serial2_receive, serial1_event, s);
-}
-
-static void init_serial_ports(SH7750State * s)
-{
-    init_serial1(s, 0);
-    init_serial2(s, 1);
-}
 
 /**********************************************************************
  I/O ports
@@ -554,17 +195,7 @@
 
 static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr)
 {
-    SH7750State *s = opaque;
-    uint8_t r;
-
     switch (addr) {
-    case SH7750_SCSSR1_A7:
-	r = s->scssr1;
-	s->scssr1_read |= r;
-	return s->scssr1;
-    case SH7750_SCRDR1_A7:
-	s->scssr1 &= ~SH7750_SCSSR1_RDRF;
-	return s->scrdr1;
     default:
 	error_access("byte read", addr);
 	assert(0);
@@ -574,26 +205,28 @@
 static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr)
 {
     SH7750State *s = opaque;
-    uint16_t r;
 
     switch (addr) {
+    case SH7750_FRQCR_A7:
+	return 0;
     case SH7750_RFCR_A7:
 	fprintf(stderr,
 		"Read access to refresh count register, incrementing\n");
 	return s->rfcr++;
-    case SH7750_TCR0_A7:
-	return s->tcr0;
-    case SH7750_SCLSR2_A7:
-	/* Read and clear overflow bit */
-	r = s->sclsr2;
-	s->sclsr2 = 0;
-	return r;
-    case SH7750_SCSFR2_A7:
-	return s->scfsr2;
     case SH7750_PDTRA_A7:
 	return porta_lines(s);
     case SH7750_PDTRB_A7:
 	return portb_lines(s);
+    case 0x1fd00000:
+        return s->icr;
+    case 0x1fd00004:
+        return s->ipra;
+    case 0x1fd00008:
+        return s->iprb;
+    case 0x1fd0000c:
+        return s->iprc;
+    case 0x1fd00010:
+        return s->iprd;
     default:
 	error_access("word read", addr);
 	assert(0);
@@ -629,6 +262,14 @@
 	return 0x00110000;	/* Minimum caches */
     case 0x1f000044:		/* Processor version PRR */
 	return 0x00000100;	/* SH7750R */
+    case 0x1e080000:
+        return s->intpri00;
+    case 0x1e080020:
+        return 0;
+    case 0x1e080040:
+        return s->intmsk00;
+    case 0x1e080060:
+        return 0;
     default:
 	error_access("long read", addr);
 	assert(0);
@@ -638,38 +279,12 @@
 static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr,
 			      uint32_t mem_value)
 {
-    SH7750State *s = opaque;
-
     switch (addr) {
 	/* PRECHARGE ? XXXXX */
     case SH7750_PRECHARGE0_A7:
     case SH7750_PRECHARGE1_A7:
 	ignore_access("byte write", addr);
 	return;
-    case SH7750_SCBRR2_A7:
-	s->scbrr2 = mem_value;
-	return;
-    case SH7750_TSTR_A7:
-	s->tstr = mem_value;
-	timer_start_changed(s);
-	return;
-    case SH7750_SCSCR1_A7:
-	s->scscr1 = mem_value;
-	scscr1_changed(s);
-	return;
-    case SH7750_SCSMR1_A7:
-	s->scsmr1 = mem_value;
-	return;
-    case SH7750_SCBRR1_A7:
-	s->scbrr1 = mem_value;
-	return;
-    case SH7750_SCTDR1_A7:
-	s->scssr1 &= ~SH7750_SCSSR1_TEND;
-	s->sctdr1 = mem_value;
-	return;
-    case SH7750_SCSSR1_A7:
-	serial1_change_scssr1(s, mem_value);
-	return;
     default:
 	error_access("byte write", addr);
 	assert(0);
@@ -684,8 +299,6 @@
 
     switch (addr) {
 	/* SDRAM controller */
-    case SH7750_SCBRR1_A7:
-    case SH7750_SCBRR2_A7:
     case SH7750_BCR2_A7:
     case SH7750_BCR3_A7:
     case SH7750_RTCOR_A7:
@@ -708,22 +321,6 @@
 	fprintf(stderr, "Write access to refresh count register\n");
 	s->rfcr = mem_value;
 	return;
-    case SH7750_SCLSR2_A7:
-	s->sclsr2 = mem_value;
-	return;
-    case SH7750_SCSCR2_A7:
-	s->scscr2 = mem_value;
-	scscr2_changed(s);
-	return;
-    case SH7750_SCFCR2_A7:
-	s->scfcr2 = mem_value;
-	return;
-    case SH7750_SCSMR2_A7:
-	s->scsmr2 = mem_value;
-	return;
-    case SH7750_TCR0_A7:
-	s->tcr0 = mem_value;
-	return;
     case SH7750_GPIOIC_A7:
 	s->gpioic = mem_value;
 	if (mem_value != 0) {
@@ -731,6 +328,21 @@
 	    assert(0);
 	}
 	return;
+    case 0x1fd00000:
+        s->icr = mem_value;
+	return;
+    case 0x1fd00004:
+        s->ipra = mem_value;
+	return;
+    case 0x1fd00008:
+        s->iprb = mem_value;
+	return;
+    case 0x1fd0000c:
+        s->iprc = mem_value;
+	return;
+    case 0x1fd00010:
+        s->iprd = mem_value;
+	return;
     default:
 	error_access("word write", addr);
 	assert(0);
@@ -768,9 +380,6 @@
 	s->portpullupb = portpullup(mem_value);
 	portb_changed(s, temp);
 	return;
-    case SH7750_TCNT0_A7:
-	s->tcnt0 = mem_value & 0xf;
-	return;
     case SH7750_MMUCR_A7:
 	s->cpu->mmucr = mem_value;
 	return;
@@ -798,6 +407,16 @@
     case SH7750_CCR_A7:
 	s->ccr = mem_value;
 	return;
+    case 0x1e080000:
+        s->intpri00 = mem_value;
+	return;
+    case 0x1e080020:
+        return;
+    case 0x1e080040:
+        s->intmsk00 = mem_value;
+	return;
+    case 0x1e080060:
+        return;
     default:
 	error_access("long write", addr);
 	assert(0);
@@ -828,7 +447,14 @@
 					      sh7750_mem_read,
 					      sh7750_mem_write, s);
     cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory);
-    init_timers(s);
-    init_serial_ports(s);
+
+    sh_serial_init(0x1fe00000, 0, s->periph_freq, serial_hds[0]);
+    sh_serial_init(0x1fe80000, SH_SERIAL_FEAT_SCIF,
+		   s->periph_freq, serial_hds[1]);
+
+    tmu012_init(0x1fd80000,
+		TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK,
+		s->periph_freq);
+    tmu012_init(0x1e100000, 0, s->periph_freq);
     return s;
 }
diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c
index 5fcb0d6..84d5c1a 100644
--- a/hw/sh7750_regnames.c
+++ b/hw/sh7750_regnames.c
@@ -42,18 +42,6 @@
 	REGNAME(SH7750_RMONAR_A7)
 	REGNAME(SH7750_RCR1_A7)
 	REGNAME(SH7750_RCR2_A7)
-	REGNAME(SH7750_TOCR_A7)
-	REGNAME(SH7750_TSTR_A7)
-	REGNAME(SH7750_TCOR0_A7)
-	REGNAME(SH7750_TCOR1_A7)
-	REGNAME(SH7750_TCOR2_A7)
-	REGNAME(SH7750_TCNT0_A7)
-	REGNAME(SH7750_TCNT1_A7)
-	REGNAME(SH7750_TCNT2_A7)
-	REGNAME(SH7750_TCR0_A7)
-	REGNAME(SH7750_TCR1_A7)
-	REGNAME(SH7750_TCR2_A7)
-	REGNAME(SH7750_TCPR2_A7)
 	REGNAME(SH7750_BCR1_A7)
 	REGNAME(SH7750_BCR2_A7)
 	REGNAME(SH7750_WCR1_A7)
@@ -82,24 +70,6 @@
 	REGNAME(SH7750_CHCR2_A7)
 	REGNAME(SH7750_CHCR3_A7)
 	REGNAME(SH7750_DMAOR_A7)
-	REGNAME(SH7750_SCRDR1_A7)
-	REGNAME(SH7750_SCRDR2_A7)
-	REGNAME(SH7750_SCTDR1_A7)
-	REGNAME(SH7750_SCTDR2_A7)
-	REGNAME(SH7750_SCSMR1_A7)
-	REGNAME(SH7750_SCSMR2_A7)
-	REGNAME(SH7750_SCSCR1_A7)
-	REGNAME(SH7750_SCSCR2_A7)
-	REGNAME(SH7750_SCSSR1_A7)
-	REGNAME(SH7750_SCSFR2_A7)
-	REGNAME(SH7750_SCSPTR1_A7)
-	REGNAME(SH7750_SCSPTR2_A7)
-	REGNAME(SH7750_SCBRR1_A7)
-	REGNAME(SH7750_SCBRR2_A7)
-	REGNAME(SH7750_SCFCR2_A7)
-	REGNAME(SH7750_SCFDR2_A7)
-	REGNAME(SH7750_SCLSR2_A7)
-	REGNAME(SH7750_SCSCMR1_A7)
 	REGNAME(SH7750_PCTRA_A7)
 	REGNAME(SH7750_PDTRA_A7)
 	REGNAME(SH7750_PCTRB_A7)
diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h
index 44ae95b..15b2769 100644
--- a/hw/sh7750_regs.h
+++ b/hw/sh7750_regs.h
@@ -12,26 +12,26 @@
  * The license and distribution terms for this file may be
  * found in the file LICENSE in this distribution or at
  *  http://www.rtems.com/license/LICENSE.
- * 
+ *
  * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp
  */
 
 #ifndef __SH7750_REGS_H__
 #define __SH7750_REGS_H__
 
-/* 
- * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address)  and 
+/*
+ * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address)  and
  * in 0x1f000000 - 0x1fffffff (area 7 address)
  */
-#define SH7750_P4_BASE       0xff000000	/* Accessable only in 
+#define SH7750_P4_BASE       0xff000000	/* Accessable only in
 					   priveleged mode */
 #define SH7750_A7_BASE       0x1f000000	/* Accessable only using TLB */
 
 #define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs))
 #define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs))
 
-/* 
- * MMU Registers 
+/*
+ * MMU Registers
  */
 
 /* Page Table Entry High register - PTEH */
@@ -61,9 +61,9 @@
 #define SH7750_PTEL_PR_RWPO   0x00000020	/*   read-write in priv mode */
 #define SH7750_PTEL_PR_ROPU   0x00000040	/*   read-only in priv or user mode */
 #define SH7750_PTEL_PR_RWPU   0x00000060	/*   read-write in priv or user mode */
-#define SH7750_PTEL_C         0x00000008	/* Cacheability 
+#define SH7750_PTEL_C         0x00000008	/* Cacheability
 						   (0 - page not cacheable) */
-#define SH7750_PTEL_D         0x00000004	/* Dirty bit (1 - write has been 
+#define SH7750_PTEL_D         0x00000004	/* Dirty bit (1 - write has been
 						   performed to a page) */
 #define SH7750_PTEL_SH        0x00000002	/* Share Status bit (1 - page are
 						   shared by processes) */
@@ -130,12 +130,12 @@
 #define SH7750_CCR_A7         SH7750_A7_REG32(SH7750_CCR_REGOFS)
 
 #define SH7750_CCR_IIX      0x00008000	/* IC index enable bit */
-#define SH7750_CCR_ICI      0x00000800	/* IC invalidation bit: 
+#define SH7750_CCR_ICI      0x00000800	/* IC invalidation bit:
 					   set it to clear IC */
 #define SH7750_CCR_ICE      0x00000100	/* IC enable bit */
 #define SH7750_CCR_OIX      0x00000080	/* OC index enable bit */
-#define SH7750_CCR_ORA      0x00000020	/* OC RAM enable bit 
-					   if you set OCE = 0, 
+#define SH7750_CCR_ORA      0x00000020	/* OC RAM enable bit
+					   if you set OCE = 0,
 					   you should set ORA = 0 */
 #define SH7750_CCR_OCI      0x00000008	/* OC invalidation bit */
 #define SH7750_CCR_CB       0x00000004	/* Copy-back bit for P1 area */
@@ -254,7 +254,7 @@
 
 /* Peripheral Module Interrupts - Memory Refresh Unit (REF) */
 #define SH7750_EVT_REF_RCMI            0x580	/* Compare-match Interrupt */
-#define SH7750_EVT_REF_ROVI            0x5A0	/* Refresh Counter Overflow 
+#define SH7750_EVT_REF_ROVI            0x5A0	/* Refresh Counter Overflow
 						   interrupt */
 
 /* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */
@@ -331,7 +331,7 @@
 #define SH7750_FRQCR          SH7750_P4_REG32(SH7750_FRQCR_REGOFS)
 #define SH7750_FRQCR_A7       SH7750_A7_REG32(SH7750_FRQCR_REGOFS)
 
-#define SH7750_FRQCR_CKOEN    0x0800	/* Clock Output Enable 
+#define SH7750_FRQCR_CKOEN    0x0800	/* Clock Output Enable
 					   0 - CKIO pin goes to HiZ/pullup
 					   1 - Clock is output from CKIO */
 #define SH7750_FRQCR_PLL1EN   0x0400	/* PLL circuit 1 enable */
@@ -524,94 +524,6 @@
 					   year counters are stopped
 					   1 - sec, min, hr, day-of-week, month,
 					   year counters operate normally */
-
-
-/*
- * Timer Unit (TMU)
- */
-/* Timer Output Control Register (byte) - TOCR */
-#define SH7750_TOCR_REGOFS    0xD80000	/* offset */
-#define SH7750_TOCR           SH7750_P4_REG32(SH7750_TOCR_REGOFS)
-#define SH7750_TOCR_A7        SH7750_A7_REG32(SH7750_TOCR_REGOFS)
-#define SH7750_TOCR_TCOE      0x01	/* Timer Clock Pin Control:
-					   0 - TCLK is used as external clock
-					   input or input capture control
-					   1 - TCLK is used as on-chip RTC
-					   output clock pin */
-
-/* Timer Start Register (byte) - TSTR */
-#define SH7750_TSTR_REGOFS    0xD80004	/* offset */
-#define SH7750_TSTR           SH7750_P4_REG32(SH7750_TSTR_REGOFS)
-#define SH7750_TSTR_A7        SH7750_A7_REG32(SH7750_TSTR_REGOFS)
-#define SH7750_TSTR_STR2      0x04	/* TCNT2 performs count operations */
-#define SH7750_TSTR_STR1      0x02	/* TCNT1 performs count operations */
-#define SH7750_TSTR_STR0      0x01	/* TCNT0 performs count operations */
-#define SH7750_TSTR_STR(n)    (1 << (n))
-
-/* Timer Constant Register - TCOR0, TCOR1, TCOR2 */
-#define SH7750_TCOR_REGOFS(n) (0xD80008 + ((n)*12))	/* offset */
-#define SH7750_TCOR(n)        SH7750_P4_REG32(SH7750_TCOR_REGOFS(n))
-#define SH7750_TCOR_A7(n)     SH7750_A7_REG32(SH7750_TCOR_REGOFS(n))
-#define SH7750_TCOR0          SH7750_TCOR(0)
-#define SH7750_TCOR1          SH7750_TCOR(1)
-#define SH7750_TCOR2          SH7750_TCOR(2)
-#define SH7750_TCOR0_A7       SH7750_TCOR_A7(0)
-#define SH7750_TCOR1_A7       SH7750_TCOR_A7(1)
-#define SH7750_TCOR2_A7       SH7750_TCOR_A7(2)
-
-/* Timer Counter Register - TCNT0, TCNT1, TCNT2 */
-#define SH7750_TCNT_REGOFS(n) (0xD8000C + ((n)*12))	/* offset */
-#define SH7750_TCNT(n)        SH7750_P4_REG32(SH7750_TCNT_REGOFS(n))
-#define SH7750_TCNT_A7(n)     SH7750_A7_REG32(SH7750_TCNT_REGOFS(n))
-#define SH7750_TCNT0          SH7750_TCNT(0)
-#define SH7750_TCNT1          SH7750_TCNT(1)
-#define SH7750_TCNT2          SH7750_TCNT(2)
-#define SH7750_TCNT0_A7       SH7750_TCNT_A7(0)
-#define SH7750_TCNT1_A7       SH7750_TCNT_A7(1)
-#define SH7750_TCNT2_A7       SH7750_TCNT_A7(2)
-
-/* Timer Control Register (half) - TCR0, TCR1, TCR2 */
-#define SH7750_TCR_REGOFS(n)  (0xD80010 + ((n)*12))	/* offset */
-#define SH7750_TCR(n)         SH7750_P4_REG32(SH7750_TCR_REGOFS(n))
-#define SH7750_TCR_A7(n)      SH7750_A7_REG32(SH7750_TCR_REGOFS(n))
-#define SH7750_TCR0           SH7750_TCR(0)
-#define SH7750_TCR1           SH7750_TCR(1)
-#define SH7750_TCR2           SH7750_TCR(2)
-#define SH7750_TCR0_A7        SH7750_TCR_A7(0)
-#define SH7750_TCR1_A7        SH7750_TCR_A7(1)
-#define SH7750_TCR2_A7        SH7750_TCR_A7(2)
-
-#define SH7750_TCR2_ICPF       0x200	/* Input Capture Interrupt Flag
-					   (1 - input capture has occured) */
-#define SH7750_TCR_UNF         0x100	/* Underflow flag */
-#define SH7750_TCR2_ICPE       0x0C0	/* Input Capture Control: */
-#define SH7750_TCR2_ICPE_DIS   0x000	/*   Input Capture function is not used */
-#define SH7750_TCR2_ICPE_NOINT 0x080	/*   Input Capture function is used, but
-					   input capture interrupt is not
-					   enabled */
-#define SH7750_TCR2_ICPE_INT   0x0C0	/*   Input Capture function is used,
-					   input capture interrupt enabled */
-#define SH7750_TCR_UNIE        0x020	/* Underflow Interrupt Control
-					   (1 - underflow interrupt enabled) */
-#define SH7750_TCR_CKEG        0x018	/* Clock Edge selection: */
-#define SH7750_TCR_CKEG_RAISE  0x000	/*   Count/capture on rising edge */
-#define SH7750_TCR_CKEG_FALL   0x008	/*   Count/capture on falling edge */
-#define SH7750_TCR_CKEG_BOTH   0x018	/*   Count/capture on both rising and
-					   falling edges */
-#define SH7750_TCR_TPSC         0x007	/* Timer prescaler */
-#define SH7750_TCR_TPSC_DIV4    0x000	/*   Counts on peripheral clock/4 */
-#define SH7750_TCR_TPSC_DIV16   0x001	/*   Counts on peripheral clock/16 */
-#define SH7750_TCR_TPSC_DIV64   0x002	/*   Counts on peripheral clock/64 */
-#define SH7750_TCR_TPSC_DIV256  0x003	/*   Counts on peripheral clock/256 */
-#define SH7750_TCR_TPSC_DIV1024 0x004	/*   Counts on peripheral clock/1024 */
-#define SH7750_TCR_TPSC_RTC     0x006	/*   Counts on on-chip RTC output clk */
-#define SH7750_TCR_TPSC_EXT     0x007	/*   Counts on external clock */
-
-/* Input Capture Register (read-only) - TCPR2 */
-#define SH7750_TCPR2_REGOFS   0xD8002C	/* offset */
-#define SH7750_TCPR2          SH7750_P4_REG32(SH7750_TCPR2_REGOFS)
-#define SH7750_TCPR2_A7       SH7750_A7_REG32(SH7750_TCPR2_REGOFS)
-
 /*
  * Bus State Controller - BSC
  */
@@ -643,7 +555,7 @@
 #define SH7750_BCR1_BREQEN    0x00080000	/* BREQ Enable:
 						   0 - External requests are  not
 						   accepted
-						   1 - External requests are 
+						   1 - External requests are
 						   accepted */
 #define SH7750_BCR1_PSHR      0x00040000	/* Partial Sharing Bit:
 						   0 - Master Mode
@@ -877,7 +789,7 @@
 #define SH7750_MCR_TCAS_1     0x00000000	/*    1 */
 #define SH7750_MCR_TCAS_2     0x00800000	/*    2 */
 
-#define SH7750_MCR_TPC        0x00380000	/* DRAM: RAS Precharge Period 
+#define SH7750_MCR_TPC        0x00380000	/* DRAM: RAS Precharge Period
 						   SDRAM: minimum number of cycles
 						   until the next bank active cmd
 						   is output after precharging */
@@ -1148,7 +1060,7 @@
 #define SH7750_CHCR_DSA_AMEM16  0x0E000000	/* 16-bit attribute memory space */
 
 #define SH7750_CHCR_DTC       0x01000000	/* Destination Address Wait Control
-						   Select, specifies CS5 or CS6 
+						   Select, specifies CS5 or CS6
 						   space wait control for PCMCIA
 						   access */
 
@@ -1186,8 +1098,8 @@
 						   Address Mode (External Addr
 						   Space -> External Device) */
 #define SH7750_CHCR_RS_ER_SA_ED_TO_EA   0x300	/* External Request, Single
-						   Address Mode, (External 
-						   Device -> External Addr 
+						   Address Mode, (External
+						   Device -> External Addr
 						   Space) */
 #define SH7750_CHCR_RS_AR_EA_TO_EA      0x400	/* Auto-Request (External Addr
 						   Space -> External Addr Space) */
@@ -1195,7 +1107,7 @@
 #define SH7750_CHCR_RS_AR_EA_TO_OCP     0x500	/* Auto-Request (External Addr
 						   Space -> On-chip Peripheral
 						   Module) */
-#define SH7750_CHCR_RS_AR_OCP_TO_EA     0x600	/* Auto-Request (On-chip 
+#define SH7750_CHCR_RS_AR_OCP_TO_EA     0x600	/* Auto-Request (On-chip
 						   Peripheral Module ->
 						   External Addr Space */
 #define SH7750_CHCR_RS_SCITX_EA_TO_SC   0x800	/* SCI Transmit-Data-Empty intr
@@ -1257,231 +1169,6 @@
 #define SH7750_DMAOR_DME      0x00000001	/* DMAC Master Enable */
 
 /*
- * Serial Communication Interface - SCI
- * Serial Communication Interface with FIFO - SCIF
- */
-/* SCI Receive Data Register (byte, read-only) - SCRDR1, SCFRDR2 */
-#define SH7750_SCRDR_REGOFS(n) ((n) == 1 ? 0xE00014 : 0xE80014)	/* offset */
-#define SH7750_SCRDR(n)       SH7750_P4_REG32(SH7750_SCRDR_REGOFS(n))
-#define SH7750_SCRDR1         SH7750_SCRDR(1)
-#define SH7750_SCRDR2         SH7750_SCRDR(2)
-#define SH7750_SCRDR_A7(n)    SH7750_A7_REG32(SH7750_SCRDR_REGOFS(n))
-#define SH7750_SCRDR1_A7      SH7750_SCRDR_A7(1)
-#define SH7750_SCRDR2_A7      SH7750_SCRDR_A7(2)
-
-/* SCI Transmit Data Register (byte) - SCTDR1, SCFTDR2 */
-#define SH7750_SCTDR_REGOFS(n) ((n) == 1 ? 0xE0000C : 0xE8000C)	/* offset */
-#define SH7750_SCTDR(n)       SH7750_P4_REG32(SH7750_SCTDR_REGOFS(n))
-#define SH7750_SCTDR1         SH7750_SCTDR(1)
-#define SH7750_SCTDR2         SH7750_SCTDR(2)
-#define SH7750_SCTDR_A7(n)    SH7750_A7_REG32(SH7750_SCTDR_REGOFS(n))
-#define SH7750_SCTDR1_A7      SH7750_SCTDR_A7(1)
-#define SH7750_SCTDR2_A7      SH7750_SCTDR_A7(2)
-
-/* SCI Serial Mode Register - SCSMR1(byte), SCSMR2(half) */
-#define SH7750_SCSMR_REGOFS(n) ((n) == 1 ? 0xE00000 : 0xE80000)	/* offset */
-#define SH7750_SCSMR(n)       SH7750_P4_REG32(SH7750_SCSMR_REGOFS(n))
-#define SH7750_SCSMR1         SH7750_SCSMR(1)
-#define SH7750_SCSMR2         SH7750_SCSMR(2)
-#define SH7750_SCSMR_A7(n)    SH7750_A7_REG32(SH7750_SCSMR_REGOFS(n))
-#define SH7750_SCSMR1_A7      SH7750_SCSMR_A7(1)
-#define SH7750_SCSMR2_A7      SH7750_SCSMR_A7(2)
-
-#define SH7750_SCSMR1_CA       0x80	/* Communication Mode (C/A\): */
-#define SH7750_SCSMR1_CA_ASYNC 0x00	/*     Asynchronous Mode */
-#define SH7750_SCSMR1_CA_SYNC  0x80	/*     Synchronous Mode */
-#define SH7750_SCSMR_CHR       0x40	/* Character Length: */
-#define SH7750_SCSMR_CHR_8     0x00	/*     8-bit data */
-#define SH7750_SCSMR_CHR_7     0x40	/*     7-bit data */
-#define SH7750_SCSMR_PE        0x20	/* Parity Enable */
-#define SH7750_SCSMR_PM        0x10	/* Parity Mode: */
-#define SH7750_SCSMR_PM_EVEN   0x00	/*     Even Parity */
-#define SH7750_SCSMR_PM_ODD    0x10	/*     Odd Parity */
-#define SH7750_SCSMR_STOP      0x08	/* Stop Bit Length: */
-#define SH7750_SCSMR_STOP_1    0x00	/*     1 stop bit */
-#define SH7750_SCSMR_STOP_2    0x08	/*     2 stop bit */
-#define SH7750_SCSMR1_MP       0x04	/* Multiprocessor Mode */
-#define SH7750_SCSMR_CKS       0x03	/* Clock Select */
-#define SH7750_SCSMR_CKS_S     0
-#define SH7750_SCSMR_CKS_DIV1  0x00	/*     Periph clock */
-#define SH7750_SCSMR_CKS_DIV4  0x01	/*     Periph clock / 4 */
-#define SH7750_SCSMR_CKS_DIV16 0x02	/*     Periph clock / 16 */
-#define SH7750_SCSMR_CKS_DIV64 0x03	/*     Periph clock / 64 */
-
-/* SCI Serial Control Register - SCSCR1(byte), SCSCR2(half) */
-#define SH7750_SCSCR_REGOFS(n) ((n) == 1 ? 0xE00008 : 0xE80008)	/* offset */
-#define SH7750_SCSCR(n)       SH7750_P4_REG32(SH7750_SCSCR_REGOFS(n))
-#define SH7750_SCSCR1         SH7750_SCSCR(1)
-#define SH7750_SCSCR2         SH7750_SCSCR(2)
-#define SH7750_SCSCR_A7(n)    SH7750_A7_REG32(SH7750_SCSCR_REGOFS(n))
-#define SH7750_SCSCR1_A7      SH7750_SCSCR_A7(1)
-#define SH7750_SCSCR2_A7      SH7750_SCSCR_A7(2)
-
-#define SH7750_SCSCR_TIE      0x80	/* Transmit Interrupt Enable */
-#define SH7750_SCSCR_RIE      0x40	/* Receive Interrupt Enable */
-#define SH7750_SCSCR_TE       0x20	/* Transmit Enable */
-#define SH7750_SCSCR_RE       0x10	/* Receive Enable */
-#define SH7750_SCSCR1_MPIE    0x08	/* Multiprocessor Interrupt Enable */
-#define SH7750_SCSCR2_REIE    0x08	/* Receive Error Interrupt Enable */
-#define SH7750_SCSCR1_TEIE    0x04	/* Transmit End Interrupt Enable */
-#define SH7750_SCSCR1_CKE     0x03	/* Clock Enable: */
-#define SH7750_SCSCR_CKE_INTCLK            0x00	/* Use Internal Clock */
-#define SH7750_SCSCR_CKE_EXTCLK            0x02	/* Use External Clock from SCK */
-#define SH7750_SCSCR1_CKE_ASYNC_SCK_CLKOUT 0x01	/* Use SCK as a clock output
-						   in asynchronous mode */
-
-/* SCI Serial Status Register - SCSSR1(byte), SCSFR2(half) */
-#define SH7750_SCSSR_REGOFS(n) ((n) == 1 ? 0xE00010 : 0xE80010)	/* offset */
-#define SH7750_SCSSR(n)       SH7750_P4_REG32(SH7750_SCSSR_REGOFS(n))
-#define SH7750_SCSSR1         SH7750_SCSSR(1)
-#define SH7750_SCSFR2         SH7750_SCSSR(2)
-#define SH7750_SCSSR_A7(n)    SH7750_A7_REG32(SH7750_SCSSR_REGOFS(n))
-#define SH7750_SCSSR1_A7      SH7750_SCSSR_A7(1)
-#define SH7750_SCSFR2_A7      SH7750_SCSSR_A7(2)
-
-#define SH7750_SCSSR1_TDRE    0x80	/* Transmit Data Register Empty */
-#define SH7750_SCSSR1_RDRF    0x40	/* Receive Data Register Full */
-#define SH7750_SCSSR1_ORER    0x20	/* Overrun Error */
-#define SH7750_SCSSR1_FER     0x10	/* Framing Error */
-#define SH7750_SCSSR1_PER     0x08	/* Parity Error */
-#define SH7750_SCSSR1_TEND    0x04	/* Transmit End */
-#define SH7750_SCSSR1_MPB     0x02	/* Multiprocessor Bit */
-#define SH7750_SCSSR1_MPBT    0x01	/* Multiprocessor Bit Transfer */
-
-#define SH7750_SCFSR2_PERN    0xF000	/* Number of Parity Errors */
-#define SH7750_SCFSR2_PERN_S  12
-#define SH7750_SCFSR2_FERN    0x0F00	/* Number of Framing Errors */
-#define SH7750_SCFSR2_FERN_S  8
-#define SH7750_SCFSR2_ER      0x0080	/* Receive Error */
-#define SH7750_SCFSR2_TEND    0x0040	/* Transmit End */
-#define SH7750_SCFSR2_TDFE    0x0020	/* Transmit FIFO Data Empty */
-#define SH7750_SCFSR2_BRK     0x0010	/* Break Detect */
-#define SH7750_SCFSR2_FER     0x0008	/* Framing Error */
-#define SH7750_SCFSR2_PER     0x0004	/* Parity Error */
-#define SH7750_SCFSR2_RDF     0x0002	/* Receive FIFO Data Full */
-#define SH7750_SCFSR2_DR      0x0001	/* Receive Data Ready */
-
-/* SCI Serial Port Register - SCSPTR1(byte) */
-#define SH7750_SCSPTR1_REGOFS 0xE0001C	/* offset */
-#define SH7750_SCSPTR1        SH7750_P4_REG32(SH7750_SCSPTR1_REGOFS)
-#define SH7750_SCSPTR1_A7     SH7750_A7_REG32(SH7750_SCSPTR1_REGOFS)
-
-#define SH7750_SCSPTR1_EIO    0x80	/* Error Interrupt Only */
-#define SH7750_SCSPTR1_SPB1IO 0x08	/* 1: Output SPB1DT bit to SCK pin */
-#define SH7750_SCSPTR1_SPB1DT 0x04	/* Serial Port Clock Port Data */
-#define SH7750_SCSPTR1_SPB0IO 0x02	/* 1: Output SPB0DT bit to TxD pin */
-#define SH7750_SCSPTR1_SPB0DT 0x01	/* Serial Port Break Data */
-
-/* SCIF Serial Port Register - SCSPTR2(half) */
-#define SH7750_SCSPTR2_REGOFS 0xE80020	/* offset */
-#define SH7750_SCSPTR2        SH7750_P4_REG32(SH7750_SCSPTR2_REGOFS)
-#define SH7750_SCSPTR2_A7     SH7750_A7_REG32(SH7750_SCSPTR2_REGOFS)
-
-#define SH7750_SCSPTR2_RTSIO  0x80	/* 1: Output RTSDT bit to RTS2\ pin */
-#define SH7750_SCSPTR2_RTSDT  0x40	/* RTS Port Data */
-#define SH7750_SCSPTR2_CTSIO  0x20	/* 1: Output CTSDT bit to CTS2\ pin */
-#define SH7750_SCSPTR2_CTSDT  0x10	/* CTS Port Data */
-#define SH7750_SCSPTR2_SPB2IO 0x02	/* 1: Output SPBDT bit to TxD2 pin */
-#define SH7750_SCSPTR2_SPB2DT 0x01	/* Serial Port Break Data */
-
-/* SCI Bit Rate Register - SCBRR1(byte), SCBRR2(byte) */
-#define SH7750_SCBRR_REGOFS(n) ((n) == 1 ? 0xE00004 : 0xE80004)	/* offset */
-#define SH7750_SCBRR(n)       SH7750_P4_REG32(SH7750_SCBRR_REGOFS(n))
-#define SH7750_SCBRR1         SH7750_SCBRR_P4(1)
-#define SH7750_SCBRR2         SH7750_SCBRR_P4(2)
-#define SH7750_SCBRR_A7(n)    SH7750_A7_REG32(SH7750_SCBRR_REGOFS(n))
-#define SH7750_SCBRR1_A7      SH7750_SCBRR_A7(1)
-#define SH7750_SCBRR2_A7      SH7750_SCBRR_A7(2)
-
-/* SCIF FIFO Control Register - SCFCR2(half) */
-#define SH7750_SCFCR2_REGOFS  0xE80018	/* offset */
-#define SH7750_SCFCR2         SH7750_P4_REG32(SH7750_SCFCR2_REGOFS)
-#define SH7750_SCFCR2_A7      SH7750_A7_REG32(SH7750_SCFCR2_REGOFS)
-
-#define SH7750_SCFCR2_RSTRG   0x700	/* RTS2\ Output Active Trigger; RTS2\
-					   signal goes to high level when the
-					   number of received data stored in
-					   FIFO exceeds the trigger number */
-#define SH7750_SCFCR2_RSTRG_15 0x000	/* 15 bytes */
-#define SH7750_SCFCR2_RSTRG_1  0x000	/* 1 byte */
-#define SH7750_SCFCR2_RSTRG_4  0x000	/* 4 bytes */
-#define SH7750_SCFCR2_RSTRG_6  0x000	/* 6 bytes */
-#define SH7750_SCFCR2_RSTRG_8  0x000	/* 8 bytes */
-#define SH7750_SCFCR2_RSTRG_10 0x000	/* 10 bytes */
-#define SH7750_SCFCR2_RSTRG_14 0x000	/* 14 bytes */
-
-#define SH7750_SCFCR2_RTRG    0x0C0	/* Receive FIFO Data Number Trigger,
-					   Receive Data Full (RDF) Flag sets
-					   when number of receive data bytes is
-					   equal or greater than the trigger
-					   number */
-#define SH7750_SCFCR2_RTRG_1  0x000	/* 1 byte */
-#define SH7750_SCFCR2_RTRG_4  0x040	/* 4 bytes */
-#define SH7750_SCFCR2_RTRG_8  0x080	/* 8 bytes */
-#define SH7750_SCFCR2_RTRG_14 0x0C0	/* 14 bytes */
-
-#define SH7750_SCFCR2_TTRG    0x030	/* Transmit FIFO Data Number Trigger,
-					   Transmit FIFO Data Register Empty (TDFE)
-					   flag sets when the number of remaining
-					   transmit data bytes is equal or less
-					   than the trigger number */
-#define SH7750_SCFCR2_TTRG_8  0x000	/* 8 bytes */
-#define SH7750_SCFCR2_TTRG_4  0x010	/* 4 bytes */
-#define SH7750_SCFCR2_TTRG_2  0x020	/* 2 bytes */
-#define SH7750_SCFCR2_TTRG_1  0x030	/* 1 byte */
-
-#define SH7750_SCFCR2_MCE     0x008	/* Modem Control Enable */
-#define SH7750_SCFCR2_TFRST   0x004	/* Transmit FIFO Data Register Reset,
-					   invalidates the transmit data in the
-					   transmit FIFO */
-#define SH7750_SCFCR2_RFRST   0x002	/* Receive FIFO Data Register Reset,
-					   invalidates the receive data in the
-					   receive FIFO data register and resets
-					   it to the empty state */
-#define SH7750_SCFCR2_LOOP    0x001	/* Loopback Test */
-
-/* SCIF FIFO Data Count Register - SCFDR2(half, read-only) */
-#define SH7750_SCFDR2_REGOFS  0xE8001C	/* offset */
-#define SH7750_SCFDR2         SH7750_P4_REG32(SH7750_SCFDR2_REGOFS)
-#define SH7750_SCFDR2_A7      SH7750_A7_REG32(SH7750_SCFDR2_REGOFS)
-
-#define SH7750_SCFDR2_T       0x1F00	/* Number of untransmitted data bytes
-					   in transmit FIFO */
-#define SH7750_SCFDR2_T_S     8
-#define SH7750_SCFDR2_R       0x001F	/* Number of received data bytes in
-					   receive FIFO */
-#define SH7750_SCFDR2_R_S     0
-
-/* SCIF Line Status Register - SCLSR2(half, read-only) */
-#define SH7750_SCLSR2_REGOFS  0xE80024	/* offset */
-#define SH7750_SCLSR2         SH7750_P4_REG32(SH7750_SCLSR2_REGOFS)
-#define SH7750_SCLSR2_A7      SH7750_A7_REG32(SH7750_SCLSR2_REGOFS)
-
-#define SH7750_SCLSR2_ORER    0x0001	/* Overrun Error */
-
-/*
- * SCI-based Smart Card Interface
- */
-/* Smart Card Mode Register - SCSCMR1(byte) */
-#define SH7750_SCSCMR1_REGOFS 0xE00018	/* offset */
-#define SH7750_SCSCMR1        SH7750_P4_REG32(SH7750_SCSCMR1_REGOFS)
-#define SH7750_SCSCMR1_A7     SH7750_A7_REG32(SH7750_SCSCMR1_REGOFS)
-
-#define SH7750_SCSCMR1_SDIR   0x08	/* Smart Card Data Transfer Direction: */
-#define SH7750_SCSCMR1_SDIR_LSBF 0x00	/* LSB-first */
-#define SH7750_SCSCMR1_SDIR_MSBF 0x08	/* MSB-first */
-
-#define SH7750_SCSCMR1_SINV   0x04	/* Smart Card Data Inversion */
-#define SH7750_SCSCMR1_SMIF   0x01	/* Smart Card Interface Mode Select */
-
-/* Smart-card specific bits in other registers */
-/* SCSMR1: */
-#define SH7750_SCSMR1_GSM     0x80	/* GSM mode select */
-
-/* SCSSR1: */
-#define SH7750_SCSSR1_ERS     0x10	/* Error Signal Status */
-
-/*
  * I/O Ports
  */
 /* Port Control Register A - PCTRA */
@@ -1596,7 +1283,7 @@
 #define SH7750_IPRC_HUDI_S    0
 
 
-/* 
+/*
  * User Break Controller registers
  */
 #define SH7750_BARA           0x200000	/* Break address regiser A */
diff --git a/hw/sh_serial.c b/hw/sh_serial.c
new file mode 100644
index 0000000..03a096c
--- /dev/null
+++ b/hw/sh_serial.c
@@ -0,0 +1,315 @@
+/*
+ * QEMU SCI/SCIF serial port emulation
+ *
+ * Copyright (c) 2007 Magnus Damm
+ *
+ * Based on serial.c - QEMU 16450 UART emulation
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+#include <assert.h>
+
+//#define DEBUG_SERIAL
+
+#define SH_SERIAL_FLAG_TEND (1 << 0)
+#define SH_SERIAL_FLAG_TDE  (1 << 1)
+#define SH_SERIAL_FLAG_RDF  (1 << 2)
+#define SH_SERIAL_FLAG_BRK  (1 << 3)
+#define SH_SERIAL_FLAG_DR   (1 << 4)
+
+typedef struct {
+    uint8_t smr;
+    uint8_t brr;
+    uint8_t scr;
+    uint8_t dr; /* ftdr / tdr */
+    uint8_t sr; /* fsr / ssr */
+    uint16_t fcr;
+    uint8_t sptr;
+
+    uint8_t rx_fifo[16]; /* frdr / rdr */
+    uint8_t rx_cnt;
+
+    target_phys_addr_t base;
+    int freq;
+    int feat;
+    int flags;
+
+    CharDriverState *chr;
+} sh_serial_state;
+
+static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val)
+{
+    sh_serial_state *s = opaque;
+    unsigned char ch;
+
+#ifdef DEBUG_SERIAL
+    printf("sh_serial: write base=0x%08lx offs=0x%02x val=0x%02x\n",
+	   (unsigned long) s->base, offs, val);
+#endif
+    switch(offs) {
+    case 0x00: /* SMR */
+        s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff);
+        return;
+    case 0x04: /* BRR */
+        s->brr = val;
+	return;
+    case 0x08: /* SCR */
+        s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfb : 0xff);
+        if (!(val & (1 << 5)))
+            s->flags |= SH_SERIAL_FLAG_TEND;
+        return;
+    case 0x0c: /* FTDR / TDR */
+        if (s->chr) {
+            ch = val;
+            qemu_chr_write(s->chr, &ch, 1);
+	}
+	s->dr = val;
+	s->flags &= ~SH_SERIAL_FLAG_TDE;
+        return;
+#if 0
+    case 0x14: /* FRDR / RDR */
+        ret = 0;
+        break;
+#endif
+    }
+    if (s->feat & SH_SERIAL_FEAT_SCIF) {
+        switch(offs) {
+        case 0x10: /* FSR */
+            if (!(val & (1 << 6)))
+                s->flags &= ~SH_SERIAL_FLAG_TEND;
+            if (!(val & (1 << 5)))
+                s->flags &= ~SH_SERIAL_FLAG_TDE;
+            if (!(val & (1 << 4)))
+                s->flags &= ~SH_SERIAL_FLAG_BRK;
+            if (!(val & (1 << 1)))
+                s->flags &= ~SH_SERIAL_FLAG_RDF;
+            if (!(val & (1 << 0)))
+                s->flags &= ~SH_SERIAL_FLAG_DR;
+            return;
+        case 0x18: /* FCR */
+            s->fcr = val;
+            return;
+        case 0x20: /* SPTR */
+            s->sptr = val;
+            return;
+        case 0x24: /* LSR */
+            return;
+        }
+    }
+    else {
+#if 0
+        switch(offs) {
+        case 0x0c:
+            ret = s->dr;
+            break;
+        case 0x10:
+            ret = 0;
+            break;
+        case 0x1c:
+            ret = s->sptr;
+            break;
+        }
+#endif
+    }
+
+    fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs);
+    assert(0);
+}
+
+static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs)
+{
+    sh_serial_state *s = opaque;
+    uint32_t ret = ~0;
+
+#if 0
+    switch(offs) {
+    case 0x00:
+        ret = s->smr;
+        break;
+    case 0x04:
+        ret = s->brr;
+	break;
+    case 0x08:
+        ret = s->scr;
+        break;
+    case 0x14:
+        ret = 0;
+        break;
+    }
+#endif
+    if (s->feat & SH_SERIAL_FEAT_SCIF) {
+        switch(offs) {
+        case 0x10: /* FSR */
+            ret = 0;
+            if (s->flags & SH_SERIAL_FLAG_TEND)
+                ret |= (1 << 6);
+            if (s->flags & SH_SERIAL_FLAG_TDE)
+                ret |= (1 << 5);
+            if (s->flags & SH_SERIAL_FLAG_BRK)
+                ret |= (1 << 4);
+            if (s->flags & SH_SERIAL_FLAG_RDF)
+                ret |= (1 << 1);
+            if (s->flags & SH_SERIAL_FLAG_DR)
+                ret |= (1 << 0);
+
+	    if (s->scr & (1 << 5))
+                s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND;
+
+            break;
+#if 0
+        case 0x18:
+            ret = s->fcr;
+            break;
+#endif
+        case 0x1c:
+            ret = s->rx_cnt;
+            break;
+        case 0x20:
+            ret = s->sptr;
+            break;
+        case 0x24:
+            ret = 0;
+            break;
+        }
+    }
+    else {
+#if 0
+        switch(offs) {
+        case 0x0c:
+            ret = s->dr;
+            break;
+        case 0x10:
+            ret = 0;
+            break;
+        case 0x1c:
+            ret = s->sptr;
+            break;
+        }
+#endif
+    }
+#ifdef DEBUG_SERIAL
+    printf("sh_serial: read base=0x%08lx offs=0x%02x val=0x%x\n",
+	   (unsigned long) s->base, offs, ret);
+#endif
+
+    if (ret & ~((1 << 16) - 1)) {
+        fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs);
+	assert(0);
+    }
+
+    return ret;
+}
+
+static int sh_serial_can_receive(sh_serial_state *s)
+{
+    return 0;
+}
+
+static void sh_serial_receive_byte(sh_serial_state *s, int ch)
+{
+}
+
+static void sh_serial_receive_break(sh_serial_state *s)
+{
+}
+
+static int sh_serial_can_receive1(void *opaque)
+{
+    sh_serial_state *s = opaque;
+    return sh_serial_can_receive(s);
+}
+
+static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+    sh_serial_state *s = opaque;
+    sh_serial_receive_byte(s, buf[0]);
+}
+
+static void sh_serial_event(void *opaque, int event)
+{
+    sh_serial_state *s = opaque;
+    if (event == CHR_EVENT_BREAK)
+        sh_serial_receive_break(s);
+}
+
+uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr)
+{
+    sh_serial_state *s = opaque;
+    return sh_serial_ioport_read(s, addr - s->base);
+}
+
+void sh_serial_write (void *opaque,
+		      target_phys_addr_t addr, uint32_t value)
+{
+    sh_serial_state *s = opaque;
+    sh_serial_ioport_write(s, addr - s->base, value);
+}
+
+static CPUReadMemoryFunc *sh_serial_readfn[] = {
+    &sh_serial_read,
+    &sh_serial_read,
+    &sh_serial_read,
+};
+
+static CPUWriteMemoryFunc *sh_serial_writefn[] = {
+    &sh_serial_write,
+    &sh_serial_write,
+    &sh_serial_write,
+};
+
+void sh_serial_init (target_phys_addr_t base, int feat,
+		     uint32_t freq, CharDriverState *chr)
+{
+    sh_serial_state *s;
+    int s_io_memory;
+
+    s = qemu_mallocz(sizeof(sh_serial_state));
+    if (!s)
+        return;
+
+    s->base = base;
+    s->feat = feat;
+    s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE;
+
+    s->smr = 0;
+    s->brr = 0xff;
+    s->scr = 0;
+    s->sptr = 0;
+
+    if (feat & SH_SERIAL_FEAT_SCIF) {
+        s->fcr = 0;
+    }
+    else {
+        s->dr = 0xff;
+    }
+
+    s->rx_cnt = 0;
+
+    s_io_memory = cpu_register_io_memory(0, sh_serial_readfn,
+					 sh_serial_writefn, s);
+    cpu_register_physical_memory(base, 0x28, s_io_memory);
+
+    s->chr = chr;
+
+    if (chr)
+        qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1,
+			      sh_serial_event, s);
+}
diff --git a/hw/sh_timer.c b/hw/sh_timer.c
new file mode 100644
index 0000000..40f3930
--- /dev/null
+++ b/hw/sh_timer.c
@@ -0,0 +1,323 @@
+/*
+ * SuperH Timer modules.
+ *
+ * Copyright (c) 2007 Magnus Damm
+ * Based on arm_timer.c by Paul Brook
+ * Copyright (c) 2005-2006 CodeSourcery.
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+
+//#define DEBUG_TIMER
+
+#define TIMER_TCR_TPSC          (7 << 0)
+#define TIMER_TCR_CKEG          (3 << 3)
+#define TIMER_TCR_UNIE          (1 << 5)
+#define TIMER_TCR_ICPE          (3 << 6)
+#define TIMER_TCR_UNF           (1 << 8)
+#define TIMER_TCR_ICPF          (1 << 9)
+#define TIMER_TCR_RESERVED      (0x3f << 10)
+
+#define TIMER_FEAT_CAPT   (1 << 0)
+#define TIMER_FEAT_EXTCLK (1 << 1)
+
+typedef struct {
+    ptimer_state *timer;
+    uint32_t tcnt;
+    uint32_t tcor;
+    uint32_t tcr;
+    uint32_t tcpr;
+    int freq;
+    int int_level;
+    int feat;
+    int enabled;
+    qemu_irq irq;
+} sh_timer_state;
+
+/* Check all active timers, and schedule the next timer interrupt. */
+
+static void sh_timer_update(sh_timer_state *s)
+{
+#if 0 /* not yet */
+    /* Update interrupts.  */
+    if (s->int_level && (s->tcr & TIMER_TCR_UNIE)) {
+        qemu_irq_raise(s->irq);
+    } else {
+        qemu_irq_lower(s->irq);
+    }
+#endif
+}
+
+uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+
+    switch (offset >> 2) {
+    case 0:
+        return s->tcor;
+    case 1:
+        return ptimer_get_count(s->timer);
+    case 2:
+        return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0);
+    case 3:
+        if (s->feat & TIMER_FEAT_CAPT)
+            return s->tcpr;
+    default:
+        cpu_abort (cpu_single_env, "sh_timer_read: Bad offset %x\n",
+                   (int)offset);
+        return 0;
+    }
+}
+
+static void sh_timer_write(void *opaque, target_phys_addr_t offset,
+                            uint32_t value)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+    int freq;
+
+    switch (offset >> 2) {
+    case 0:
+        s->tcor = value;
+        ptimer_set_limit(s->timer, s->tcor, 0);
+        break;
+    case 1:
+        s->tcnt = value;
+        ptimer_set_count(s->timer, s->tcnt);
+        break;
+    case 2:
+        if (s->enabled) {
+            /* Pause the timer if it is running.  This may cause some
+               inaccuracy dure to rounding, but avoids a whole lot of other
+               messyness.  */
+            ptimer_stop(s->timer);
+        }
+        freq = s->freq;
+        /* ??? Need to recalculate expiry time after changing divisor.  */
+        switch (value & TIMER_TCR_TPSC) {
+        case 0: freq >>= 2; break;
+        case 1: freq >>= 4; break;
+        case 2: freq >>= 6; break;
+        case 3: freq >>= 8; break;
+        case 4: freq >>= 10; break;
+	case 6:
+	case 7: if (s->feat & TIMER_FEAT_EXTCLK) break;
+	default: cpu_abort (cpu_single_env,
+			   "sh_timer_write: Reserved TPSC value\n"); break;
+        }
+        switch ((value & TIMER_TCR_CKEG) >> 3) {
+	case 0: break;
+        case 1:
+        case 2:
+        case 3: if (s->feat & TIMER_FEAT_EXTCLK) break;
+	default: cpu_abort (cpu_single_env,
+			   "sh_timer_write: Reserved CKEG value\n"); break;
+        }
+        switch ((value & TIMER_TCR_ICPE) >> 6) {
+	case 0: break;
+        case 2:
+        case 3: if (s->feat & TIMER_FEAT_CAPT) break;
+	default: cpu_abort (cpu_single_env,
+			   "sh_timer_write: Reserved ICPE value\n"); break;
+        }
+	if ((value & TIMER_TCR_UNF) == 0)
+            s->int_level = 0;
+
+	value &= ~TIMER_TCR_UNF;
+
+	if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT)))
+            cpu_abort (cpu_single_env,
+		       "sh_timer_write: Reserved ICPF value\n");
+
+	value &= ~TIMER_TCR_ICPF; /* capture not supported */
+
+	if (value & TIMER_TCR_RESERVED)
+            cpu_abort (cpu_single_env,
+		       "sh_timer_write: Reserved TCR bits set\n");
+        s->tcr = value;
+        ptimer_set_limit(s->timer, s->tcor, 0);
+        ptimer_set_freq(s->timer, freq);
+        if (s->enabled) {
+            /* Restart the timer if still enabled.  */
+            ptimer_run(s->timer, 0);
+        }
+        break;
+    case 3:
+        if (s->feat & TIMER_FEAT_CAPT) {
+            s->tcpr = value;
+	    break;
+	}
+    default:
+        cpu_abort (cpu_single_env, "sh_timer_write: Bad offset %x\n",
+                   (int)offset);
+    }
+    sh_timer_update(s);
+}
+
+static void sh_timer_start_stop(void *opaque, int enable)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled);
+#endif
+
+    if (s->enabled && !enable) {
+        ptimer_stop(s->timer);
+    }
+    if (!s->enabled && enable) {
+        ptimer_run(s->timer, 0);
+    }
+    s->enabled = !!enable;
+
+#ifdef DEBUG_TIMER
+    printf("sh_timer_start_stop done %d\n", s->enabled);
+#endif
+}
+
+static void sh_timer_tick(void *opaque)
+{
+    sh_timer_state *s = (sh_timer_state *)opaque;
+    s->int_level = s->enabled;
+    sh_timer_update(s);
+}
+
+static void *sh_timer_init(uint32_t freq, int feat)
+{
+    sh_timer_state *s;
+    QEMUBH *bh;
+
+    s = (sh_timer_state *)qemu_mallocz(sizeof(sh_timer_state));
+    s->freq = freq;
+    s->feat = feat;
+    s->tcor = 0xffffffff;
+    s->tcnt = 0xffffffff;
+    s->tcpr = 0xdeadbeef;
+    s->tcor = 0;
+    s->enabled = 0;
+
+    bh = qemu_bh_new(sh_timer_tick, s);
+    s->timer = ptimer_init(bh);
+    /* ??? Save/restore.  */
+    return s;
+}
+
+typedef struct {
+    void *timer[3];
+    int level[3];
+    uint32_t tocr;
+    uint32_t tstr;
+    target_phys_addr_t base;
+    int feat;
+} tmu012_state;
+
+static uint32_t tmu012_read(void *opaque, target_phys_addr_t offset)
+{
+    tmu012_state *s = (tmu012_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("tmu012_read 0x%lx\n", (unsigned long) offset);
+#endif
+    offset -= s->base;
+
+    if (offset >= 0x20) {
+        if (!(s->feat & TMU012_FEAT_3CHAN))
+	    cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n",
+		       (int)offset);
+        return sh_timer_read(s->timer[2], offset - 0x20);
+    }
+
+    if (offset >= 0x14)
+        return sh_timer_read(s->timer[1], offset - 0x14);
+
+    if (offset >= 0x08)
+        return sh_timer_read(s->timer[0], offset - 0x08);
+
+    if (offset == 4)
+        return s->tstr;
+
+    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0)
+        return s->tocr;
+
+    cpu_abort (cpu_single_env, "tmu012_write: Bad offset %x\n",
+	       (int)offset);
+    return 0;
+}
+
+static void tmu012_write(void *opaque, target_phys_addr_t offset,
+                        uint32_t value)
+{
+    tmu012_state *s = (tmu012_state *)opaque;
+
+#ifdef DEBUG_TIMER
+    printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value);
+#endif
+    offset -= s->base;
+
+    if (offset >= 0x20) {
+        if (!(s->feat & TMU012_FEAT_3CHAN))
+	    cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n",
+		       (int)offset);
+        sh_timer_write(s->timer[2], offset - 0x20, value);
+	return;
+    }
+
+    if (offset >= 0x14) {
+        sh_timer_write(s->timer[1], offset - 0x14, value);
+	return;
+    }
+
+    if (offset >= 0x08) {
+        sh_timer_write(s->timer[0], offset - 0x08, value);
+	return;
+    }
+
+    if (offset == 4) {
+        sh_timer_start_stop(s->timer[0], value & (1 << 0));
+        sh_timer_start_stop(s->timer[1], value & (1 << 1));
+        if (s->feat & TMU012_FEAT_3CHAN)
+            sh_timer_start_stop(s->timer[2], value & (1 << 2));
+	else
+            if (value & (1 << 2))
+                cpu_abort (cpu_single_env, "tmu012_write: Bad channel\n");
+
+	s->tstr = value;
+	return;
+    }
+
+    if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) {
+        s->tocr = value & (1 << 0);
+    }
+}
+
+static CPUReadMemoryFunc *tmu012_readfn[] = {
+    tmu012_read,
+    tmu012_read,
+    tmu012_read
+};
+
+static CPUWriteMemoryFunc *tmu012_writefn[] = {
+    tmu012_write,
+    tmu012_write,
+    tmu012_write
+};
+
+void tmu012_init(uint32_t base, int feat, uint32_t freq)
+{
+    int iomemtype;
+    tmu012_state *s;
+    int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0;
+
+    s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state));
+    s->base = base;
+    s->feat = feat;
+    s->timer[0] = sh_timer_init(freq, timer_feat);
+    s->timer[1] = sh_timer_init(freq, timer_feat);
+    if (feat & TMU012_FEAT_3CHAN)
+        s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT);
+    iomemtype = cpu_register_io_memory(0, tmu012_readfn,
+                                       tmu012_writefn, s);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+    /* ??? Save/restore.  */
+}
diff --git a/hw/shix.c b/hw/shix.c
index 9577c09..e668426 100644
--- a/hw/shix.c
+++ b/hw/shix.c
@@ -1,8 +1,8 @@
 /*
  * SHIX 2.0 board description
- * 
+ *
  * Copyright (c) 2005 Samuel Tardieu
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -21,7 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
-/* 
+/*
    Shix 2.0 board by Alexis Polti, described at
    http://perso.enst.fr/~polti/realisations/shix20/
 
@@ -42,11 +42,6 @@
     /* XXXXX */
 }
 
-void pic_set_irq(int irq, int level)
-{
-    /* XXXXX */
-}
-
 void pic_info()
 {
     /* XXXXX */
@@ -70,7 +65,7 @@
 void shix_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 *initrd_filename, const char *cpu_model)
 {
     int ret;
     CPUState *env;
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
index 288fb50..f604702 100644
--- a/hw/slavio_intctl.c
+++ b/hw/slavio_intctl.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Sparc SLAVIO interrupt controller emulation
- * 
+ *
  * Copyright (c) 2003-2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -40,10 +40,11 @@
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
  *
  * There is a system master controller and one for each cpu.
- * 
+ *
  */
 
 #define MAX_CPUS 16
+#define MAX_PILS 16
 
 typedef struct SLAVIO_INTCTLState {
     uint32_t intreg_pending[MAX_CPUS];
@@ -53,29 +54,39 @@
 #ifdef DEBUG_IRQ_COUNT
     uint64_t irq_count[32];
 #endif
-    CPUState *cpu_envs[MAX_CPUS];
+    qemu_irq *cpu_irqs[MAX_CPUS];
+    const uint32_t *intbit_to_level;
+    uint32_t cputimer_bit;
+    uint32_t pil_out[MAX_CPUS];
 } SLAVIO_INTCTLState;
 
 #define INTCTL_MAXADDR 0xf
-#define INTCTLM_MAXADDR 0xf
+#define INTCTL_SIZE (INTCTL_MAXADDR + 1)
+#define INTCTLM_MAXADDR 0x13
+#define INTCTLM_SIZE (INTCTLM_MAXADDR + 1)
+#define INTCTLM_MASK 0x1f
 static void slavio_check_interrupts(void *opaque);
 
 // per-cpu interrupt controller
 static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     SLAVIO_INTCTLState *s = opaque;
-    uint32_t saddr;
+    uint32_t saddr, ret;
     int cpu;
 
     cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
     saddr = (addr & INTCTL_MAXADDR) >> 2;
     switch (saddr) {
     case 0:
-	return s->intreg_pending[cpu];
+        ret = s->intreg_pending[cpu];
+        break;
     default:
-	break;
+        ret = 0;
+        break;
     }
-    return 0;
+    DPRINTF("read cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, ret);
+
+    return ret;
 }
 
 static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -86,12 +97,14 @@
 
     cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
     saddr = (addr & INTCTL_MAXADDR) >> 2;
+    DPRINTF("write cpu %d reg 0x" TARGET_FMT_plx " = %x\n", cpu, addr, val);
     switch (saddr) {
     case 1: // clear pending softints
 	if (val & 0x4000)
 	    val |= 80000000;
 	val &= 0xfffe0000;
 	s->intreg_pending[cpu] &= ~val;
+        slavio_check_interrupts(s);
 	DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
 	break;
     case 2: // set softint
@@ -121,20 +134,26 @@
 static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     SLAVIO_INTCTLState *s = opaque;
-    uint32_t saddr;
+    uint32_t saddr, ret;
 
     saddr = (addr & INTCTLM_MAXADDR) >> 2;
     switch (saddr) {
     case 0:
-	return s->intregm_pending & 0x7fffffff;
+        ret = s->intregm_pending & 0x7fffffff;
+        break;
     case 1:
-	return s->intregm_disabled;
+        ret = s->intregm_disabled;
+        break;
     case 4:
-	return s->target_cpu;
+        ret = s->target_cpu;
+        break;
     default:
-	break;
+        ret = 0;
+        break;
     }
-    return 0;
+    DPRINTF("read system reg 0x" TARGET_FMT_plx " = %x\n", addr, ret);
+
+    return ret;
 }
 
 static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
@@ -142,7 +161,8 @@
     SLAVIO_INTCTLState *s = opaque;
     uint32_t saddr;
 
-    saddr = (addr & INTCTLM_MAXADDR) >> 2;
+    saddr = (addr & INTCTLM_MASK) >> 2;
+    DPRINTF("write system reg 0x" TARGET_FMT_plx " = %x\n", addr, val);
     switch (saddr) {
     case 2: // clear (enable)
 	// Force clear unused bits
@@ -156,10 +176,12 @@
 	val &= ~0x4fb2007f;
 	s->intregm_disabled |= val;
 	s->intregm_pending &= ~val;
+        slavio_check_interrupts(s);
 	DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
 	break;
     case 4:
 	s->target_cpu = val & (MAX_CPUS - 1);
+        slavio_check_interrupts(s);
 	DPRINTF("Set master irq cpu %d\n", s->target_cpu);
 	break;
     default:
@@ -208,72 +230,36 @@
 #endif
 }
 
-static const uint32_t intbit_to_level[32] = {
-    2, 3, 5, 7, 9, 11, 0, 14,	3, 5, 7, 9, 11, 13, 12, 12,
-    6, 0, 4, 10, 8, 0, 11, 0,	0, 0, 0, 0, 15, 0, 15, 0,
-};
-
 static void slavio_check_interrupts(void *opaque)
 {
-    CPUState *env;
     SLAVIO_INTCTLState *s = opaque;
-    uint32_t pending = s->intregm_pending;
-    unsigned int i, j, max = 0;
+    uint32_t pending = s->intregm_pending, pil_pending;
+    unsigned int i, j;
 
     pending &= ~s->intregm_disabled;
 
-    if (pending && !(s->intregm_disabled & 0x80000000)) {
-	for (i = 0; i < 32; i++) {
-	    if (pending & (1 << i)) {
-		if (max < intbit_to_level[i])
-		    max = intbit_to_level[i];
-	    }
-	}
-        env = s->cpu_envs[s->target_cpu];
-        if (!env) {
-	    DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending);
-        }
-	else {
-            if (env->halted)
-                env->halted = 0;
-            if (env->interrupt_index == 0) {
-                DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max);
-#ifdef DEBUG_IRQ_COUNT
-                s->irq_count[max]++;
-#endif
-                env->interrupt_index = TT_EXTINT | max;
-                cpu_interrupt(env, CPU_INTERRUPT_HARD);
-            }
-            else
-                DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
-	}
-    }
-    else
-	DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
-    
+    DPRINTF("pending %x disabled %x\n", pending, s->intregm_disabled);
     for (i = 0; i < MAX_CPUS; i++) {
-        max = 0;
-        env = s->cpu_envs[i];
-        if (!env)
-            continue;
-        for (j = 17; j < 32; j++) {
-            if (s->intreg_pending[i] & (1 << j)) {
-                if (max < j - 16)
-                    max = j - 16;
+        pil_pending = 0;
+        if (pending && !(s->intregm_disabled & 0x80000000) &&
+            (i == s->target_cpu)) {
+            for (j = 0; j < 32; j++) {
+                if (pending & (1 << j))
+                    pil_pending |= 1 << s->intbit_to_level[j];
             }
         }
-	if (max > 0) {
-            if (env->halted)
-                env->halted = 0;
-            if (env->interrupt_index == 0) {
-                DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending);
-#ifdef DEBUG_IRQ_COUNT
-                s->irq_count[max]++;
-#endif
-                env->interrupt_index = TT_EXTINT | max;
-                cpu_interrupt(env, CPU_INTERRUPT_HARD);
+        pil_pending |= (s->intreg_pending[i] >> 16) & 0xfffe;
+
+        for (j = 0; j < MAX_PILS; j++) {
+            if (pil_pending & (1 << j)) {
+                if (!(s->pil_out[i] & (1 << j)))
+                    qemu_irq_raise(s->cpu_irqs[i][j]);
+            } else {
+                if (s->pil_out[i] & (1 << j))
+                    qemu_irq_lower(s->cpu_irqs[i][j]);
             }
         }
+        s->pil_out[i] = pil_pending;
     }
 }
 
@@ -281,48 +267,40 @@
  * "irq" here is the bit number in the system interrupt register to
  * separate serial and keyboard interrupts sharing a level.
  */
-void slavio_pic_set_irq(void *opaque, int irq, int level)
+static void slavio_set_irq(void *opaque, int irq, int level)
 {
     SLAVIO_INTCTLState *s = opaque;
+    uint32_t mask = 1 << irq;
+    uint32_t pil = s->intbit_to_level[irq];
 
-    DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level);
-    if (irq < 32) {
-	uint32_t mask = 1 << irq;
-	uint32_t pil = intbit_to_level[irq];
-	if (pil > 0) {
-	    if (level) {
-		s->intregm_pending |= mask;
-		s->intreg_pending[s->target_cpu] |= 1 << pil;
-	    }
-	    else {
-		s->intregm_pending &= ~mask;
-		s->intreg_pending[s->target_cpu] &= ~(1 << pil);
-	    }
-	}
+    DPRINTF("Set cpu %d irq %d -> pil %d level %d\n", s->target_cpu, irq, pil,
+            level);
+    if (pil > 0) {
+        if (level) {
+#ifdef DEBUG_IRQ_COUNT
+            s->irq_count[pil]++;
+#endif
+            s->intregm_pending |= mask;
+            s->intreg_pending[s->target_cpu] |= 1 << pil;
+        } else {
+            s->intregm_pending &= ~mask;
+            s->intreg_pending[s->target_cpu] &= ~(1 << pil);
+        }
+        slavio_check_interrupts(s);
     }
-    slavio_check_interrupts(s);
 }
 
-void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
+static void slavio_set_timer_irq_cpu(void *opaque, int cpu, int level)
 {
     SLAVIO_INTCTLState *s = opaque;
 
-    DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level);
-    if (cpu == (unsigned int)-1) {
-        slavio_pic_set_irq(opaque, irq, level);
-        return;
-    }
-    if (irq < 32) {
-	uint32_t pil = intbit_to_level[irq];
-    	if (pil > 0) {
-	    if (level) {
-		s->intreg_pending[cpu] |= 1 << pil;
-	    }
-	    else {
-		s->intreg_pending[cpu] &= ~(1 << pil);
-	    }
-	}
-    }
+    DPRINTF("Set cpu %d local timer level %d\n", cpu, level);
+
+    if (level)
+        s->intreg_pending[cpu] |= s->cputimer_bit;
+    else
+        s->intreg_pending[cpu] &= ~s->cputimer_bit;
+
     slavio_check_interrupts(s);
 }
 
@@ -330,7 +308,7 @@
 {
     SLAVIO_INTCTLState *s = opaque;
     int i;
-    
+
     for (i = 0; i < MAX_CPUS; i++) {
 	qemu_put_be32s(f, &s->intreg_pending[i]);
     }
@@ -353,6 +331,7 @@
     qemu_get_be32s(f, &s->intregm_pending);
     qemu_get_be32s(f, &s->intregm_disabled);
     qemu_get_be32s(f, &s->target_cpu);
+    slavio_check_interrupts(s);
     return 0;
 }
 
@@ -367,15 +346,13 @@
     s->intregm_disabled = ~0xffb2007f;
     s->intregm_pending = 0;
     s->target_cpu = 0;
+    slavio_check_interrupts(s);
 }
 
-void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env)
-{
-    SLAVIO_INTCTLState *s = opaque;
-    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, qemu_irq **cpu_irq,
+                         qemu_irq **parent_irq, unsigned int cputimer)
 {
     int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
     SLAVIO_INTCTLState *s;
@@ -384,16 +361,23 @@
     if (!s)
         return NULL;
 
+    s->intbit_to_level = intbit_to_level;
     for (i = 0; i < MAX_CPUS; i++) {
 	slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
-	cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
+	cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_SIZE,
+                                     slavio_intctl_io_memory);
+        s->cpu_irqs[i] = parent_irq[i];
     }
 
     slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
-    cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
+    cpu_register_physical_memory(addrg, INTCTLM_SIZE, slavio_intctlm_io_memory);
 
     register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
     qemu_register_reset(slavio_intctl_reset, s);
+    *irq = qemu_allocate_irqs(slavio_set_irq, s, 32);
+
+    *cpu_irq = qemu_allocate_irqs(slavio_set_timer_irq_cpu, s, MAX_CPUS);
+    s->cputimer_bit = 1 << s->intbit_to_level[cputimer];
     slavio_intctl_reset(s);
     return s;
 }
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
index a48a7af..34072c6 100644
--- a/hw/slavio_misc.c
+++ b/hw/slavio_misc.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Sparc SLAVIO aux io port emulation
- * 
+ *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -41,22 +41,24 @@
 #endif
 
 typedef struct MiscState {
-    int irq;
+    qemu_irq irq;
     uint8_t config;
     uint8_t aux1, aux2;
     uint8_t diag, mctrl, sysctrl;
 } MiscState;
 
-#define MISC_MAXADDR 1
+#define MISC_SIZE 1
 
 static void slavio_misc_update_irq(void *opaque)
 {
     MiscState *s = opaque;
 
     if ((s->aux2 & 0x4) && (s->config & 0x8)) {
-        pic_set_irq(s->irq, 1);
+        MISC_DPRINTF("Raise IRQ\n");
+        qemu_irq_raise(s->irq);
     } else {
-        pic_set_irq(s->irq, 0);
+        MISC_DPRINTF("Lower IRQ\n");
+        qemu_irq_lower(s->irq);
     }
 }
 
@@ -180,8 +182,10 @@
 static void slavio_misc_save(QEMUFile *f, void *opaque)
 {
     MiscState *s = opaque;
+    int tmp;
 
-    qemu_put_be32s(f, &s->irq);
+    tmp = 0;
+    qemu_put_be32s(f, &tmp); /* ignored, was IRQ.  */
     qemu_put_8s(f, &s->config);
     qemu_put_8s(f, &s->aux1);
     qemu_put_8s(f, &s->aux2);
@@ -193,11 +197,12 @@
 static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
 {
     MiscState *s = opaque;
+    int tmp;
 
     if (version_id != 1)
         return -EINVAL;
 
-    qemu_get_be32s(f, &s->irq);
+    qemu_get_be32s(f, &tmp);
     qemu_get_8s(f, &s->config);
     qemu_get_8s(f, &s->aux1);
     qemu_get_8s(f, &s->aux2);
@@ -207,7 +212,8 @@
     return 0;
 }
 
-void *slavio_misc_init(uint32_t base, int 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;
@@ -218,19 +224,25 @@
 
     slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s);
     // Slavio control
-    cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory);
+    cpu_register_physical_memory(base + 0x1800000, MISC_SIZE,
+                                 slavio_misc_io_memory);
     // AUX 1
-    cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory);
+    cpu_register_physical_memory(base + 0x1900000, MISC_SIZE,
+                                 slavio_misc_io_memory);
     // AUX 2
-    cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory);
+    cpu_register_physical_memory(base + 0x1910000, MISC_SIZE,
+                                 slavio_misc_io_memory);
     // Diagnostics
-    cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory);
+    cpu_register_physical_memory(base + 0x1a00000, MISC_SIZE,
+                                 slavio_misc_io_memory);
     // Modem control
-    cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory);
+    cpu_register_physical_memory(base + 0x1b00000, MISC_SIZE,
+                                 slavio_misc_io_memory);
     // System control
-    cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
+    cpu_register_physical_memory(base + 0x1f00000, MISC_SIZE,
+                                 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_SIZE, slavio_misc_io_memory);
 
     s->irq = irq;
 
diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c
index e72bb70..1aa5e7a 100644
--- a/hw/slavio_serial.c
+++ b/hw/slavio_serial.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Sparc SLAVIO serial port emulation
- * 
+ *
  * Copyright (c) 2003-2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -35,7 +35,7 @@
  * This is the serial port, mouse and keyboard part of chip STP2001
  * (Slave I/O), also produced as NCR89C105. See
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- * 
+ *
  * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
  * mouse and keyboard ports don't implement all functions and they are
  * only asynchronous. There is no DMA.
@@ -52,8 +52,6 @@
 #ifdef DEBUG_SERIAL
 #define SER_DPRINTF(fmt, args...) \
 do { printf("SER: " fmt , ##args); } while (0)
-#define pic_set_irq(irq, level) \
-do { printf("SER: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
 #else
 #define SER_DPRINTF(fmt, args...)
 #endif
@@ -88,7 +86,7 @@
 } SERIOQueue;
 
 typedef struct ChannelState {
-    int irq;
+    qemu_irq irq;
     int reg;
     int rxint, txint, rxint_under_svc, txint_under_svc;
     chn_id_t chn; // this channel, A (base+4) or B (base+0)
@@ -97,6 +95,7 @@
     uint8_t rx, tx, wregs[16], rregs[16];
     SERIOQueue queue;
     CharDriverState *chr;
+    int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
 } ChannelState;
 
 struct SerialState {
@@ -104,12 +103,20 @@
 };
 
 #define SERIAL_MAXADDR 7
+#define SERIAL_SIZE (SERIAL_MAXADDR + 1)
 
 static void handle_kbd_command(ChannelState *s, int val);
 static int serial_can_receive(void *opaque);
 static void serial_receive_byte(ChannelState *s, int ch);
 static inline void set_txint(ChannelState *s);
 
+static void clear_queue(void *opaque)
+{
+    ChannelState *s = opaque;
+    SERIOQueue *q = &s->queue;
+    q->rptr = q->wptr = q->count = 0;
+}
+
 static void put_queue(void *opaque, int b)
 {
     ChannelState *s = opaque;
@@ -130,7 +137,7 @@
     ChannelState *s = opaque;
     SERIOQueue *q = &s->queue;
     int val;
-    
+
     if (q->count == 0) {
 	return 0;
     } else {
@@ -139,7 +146,7 @@
             q->rptr = 0;
         q->count--;
     }
-    KBD_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
+    SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
     if (q->count > 0)
 	serial_receive_byte(s, 0);
     return val;
@@ -164,7 +171,8 @@
     irq = slavio_serial_update_irq_chn(s);
     irq |= slavio_serial_update_irq_chn(s->otherchn);
 
-    pic_set_irq(s->irq, irq);
+    SER_DPRINTF("IRQ = %d\n", irq);
+    qemu_set_irq(s->irq, irq);
 }
 
 static void slavio_serial_reset_chn(ChannelState *s)
@@ -172,7 +180,7 @@
     int i;
 
     s->reg = 0;
-    for (i = 0; i < SERIAL_MAXADDR; i++) {
+    for (i = 0; i < SERIAL_SIZE; i++) {
 	s->rregs[i] = 0;
 	s->wregs[i] = 0;
     }
@@ -187,6 +195,8 @@
     s->rx = s->tx = 0;
     s->rxint = s->txint = 0;
     s->rxint_under_svc = s->txint_under_svc = 0;
+    s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
+    clear_queue(s);
 }
 
 static void slavio_serial_reset(void *opaque)
@@ -200,14 +210,21 @@
 {
     s->rxint = 0;
     s->rxint_under_svc = 0;
-    if (s->chn == chn_a)
+    if (s->chn == chn_a) {
+        if (s->wregs[9] & 0x10)
+            s->otherchn->rregs[2] = 0x60;
+        else
+            s->otherchn->rregs[2] = 0x06;
         s->rregs[3] &= ~0x20;
-    else
+    } else {
+        if (s->wregs[9] & 0x10)
+            s->rregs[2] = 0x60;
+        else
+            s->rregs[2] = 0x06;
         s->otherchn->rregs[3] &= ~4;
+    }
     if (s->txint)
         set_txint(s);
-    else
-        s->rregs[2] = 6;
     slavio_serial_update_irq(s);
 }
 
@@ -216,27 +233,44 @@
     s->rxint = 1;
     if (!s->txint_under_svc) {
         s->rxint_under_svc = 1;
-        if (s->chn == chn_a)
-            s->rregs[3] |= 0x20;
-        else
-            s->otherchn->rregs[3] |= 4;
-        s->rregs[2] = 4;
-        slavio_serial_update_irq(s);
+        if (s->chn == chn_a) {
+            if (s->wregs[9] & 0x10)
+                s->otherchn->rregs[2] = 0x30;
+            else
+                s->otherchn->rregs[2] = 0x0c;
+        } else {
+            if (s->wregs[9] & 0x10)
+                s->rregs[2] = 0x20;
+            else
+                s->rregs[2] = 0x04;
+        }
     }
+    if (s->chn == chn_a)
+        s->rregs[3] |= 0x20;
+    else
+        s->otherchn->rregs[3] |= 4;
+    slavio_serial_update_irq(s);
 }
 
 static inline void clr_txint(ChannelState *s)
 {
     s->txint = 0;
     s->txint_under_svc = 0;
-    if (s->chn == chn_a)
+    if (s->chn == chn_a) {
+        if (s->wregs[9] & 0x10)
+            s->otherchn->rregs[2] = 0x60;
+        else
+            s->otherchn->rregs[2] = 0x06;
         s->rregs[3] &= ~0x10;
-    else
+    } else {
+        if (s->wregs[9] & 0x10)
+            s->rregs[2] = 0x60;
+        else
+            s->rregs[2] = 0x06;
         s->otherchn->rregs[3] &= ~2;
+    }
     if (s->rxint)
         set_rxint(s);
-    else
-        s->rregs[2] = 6;
     slavio_serial_update_irq(s);
 }
 
@@ -245,13 +279,20 @@
     s->txint = 1;
     if (!s->rxint_under_svc) {
         s->txint_under_svc = 1;
-        if (s->chn == chn_a)
-            s->rregs[3] |= 0x10;
-        else
-            s->otherchn->rregs[3] |= 2;
-        s->rregs[2] = 0;
-        slavio_serial_update_irq(s);
+        if (s->chn == chn_a) {
+            if (s->wregs[9] & 0x10)
+                s->otherchn->rregs[2] = 0x10;
+            else
+                s->otherchn->rregs[2] = 0x08;
+        } else {
+            s->rregs[2] = 0;
+        }
     }
+    if (s->chn == chn_a)
+        s->rregs[3] |= 0x10;
+    else
+        s->otherchn->rregs[3] |= 2;
+    slavio_serial_update_irq(s);
 }
 
 static void slavio_serial_update_parameters(ChannelState *s)
@@ -315,7 +356,7 @@
 
 static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
-    SerialState *ser = opaque;
+    SerialState *serial = opaque;
     ChannelState *s;
     uint32_t saddr;
     int newreg, channel;
@@ -323,7 +364,7 @@
     val &= 0xff;
     saddr = (addr & 3) >> 1;
     channel = (addr & SERIAL_MAXADDR) >> 2;
-    s = &ser->chn[channel];
+    s = &serial->chn[channel];
     switch (saddr) {
     case 0:
 	SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff);
@@ -368,13 +409,13 @@
 	    default:
 		break;
 	    case 0x40:
-		slavio_serial_reset_chn(&ser->chn[1]);
+		slavio_serial_reset_chn(&serial->chn[1]);
 		return;
 	    case 0x80:
-		slavio_serial_reset_chn(&ser->chn[0]);
+		slavio_serial_reset_chn(&serial->chn[0]);
 		return;
 	    case 0xc0:
-		slavio_serial_reset(ser);
+		slavio_serial_reset(serial);
 		return;
 	    }
 	    break;
@@ -388,17 +429,17 @@
 	break;
     case 1:
 	SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
+        s->tx = val;
 	if (s->wregs[5] & 8) { // tx enabled
-	    s->tx = val;
 	    if (s->chr)
 		qemu_chr_write(s->chr, &s->tx, 1);
 	    else if (s->type == kbd) {
 		handle_kbd_command(s, val);
 	    }
-	    s->rregs[0] |= 4; // Tx buffer empty
-	    s->rregs[1] |= 1; // All sent
-            set_txint(s);
 	}
+        s->rregs[0] |= 4; // Tx buffer empty
+        s->rregs[1] |= 1; // All sent
+        set_txint(s);
 	break;
     default:
 	break;
@@ -407,7 +448,7 @@
 
 static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
 {
-    SerialState *ser = opaque;
+    SerialState *serial = opaque;
     ChannelState *s;
     uint32_t saddr;
     uint32_t ret;
@@ -415,7 +456,7 @@
 
     saddr = (addr & 3) >> 1;
     channel = (addr & SERIAL_MAXADDR) >> 2;
-    s = &ser->chn[channel];
+    s = &serial->chn[channel];
     switch (saddr) {
     case 0:
 	SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]);
@@ -492,7 +533,9 @@
 
 static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
 {
-    qemu_put_be32s(f, &s->irq);
+    int tmp;
+    tmp = 0;
+    qemu_put_be32s(f, &tmp); /* unused, was IRQ.  */
     qemu_put_be32s(f, &s->reg);
     qemu_put_be32s(f, &s->rxint);
     qemu_put_be32s(f, &s->txint);
@@ -514,10 +557,12 @@
 
 static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
 {
+    int tmp;
+
     if (version_id > 2)
         return -EINVAL;
 
-    qemu_get_be32s(f, &s->irq);
+    qemu_get_be32s(f, &tmp); /* unused */
     qemu_get_be32s(f, &s->reg);
     qemu_get_be32s(f, &s->rxint);
     qemu_get_be32s(f, &s->txint);
@@ -545,7 +590,8 @@
 
 }
 
-SerialState *slavio_serial_init(int base, int 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;
@@ -555,7 +601,7 @@
         return NULL;
 
     slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
-    cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
+    cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory);
 
     s->chn[0].chr = chr1;
     s->chn[1].chr = chr2;
@@ -588,42 +634,94 @@
     0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
 };
 
+static const uint8_t e0_keycodes[128] = {
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
+    113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
 static void sunkbd_event(void *opaque, int ch)
 {
     ChannelState *s = opaque;
     int release = ch & 0x80;
 
-    ch = keycodes[ch & 0x7f];
-    KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press");
+    KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" : "press");
+    switch (ch) {
+    case 58: // Caps lock press
+        s->caps_lock_mode ^= 1;
+        if (s->caps_lock_mode == 2)
+            return; // Drop second press
+        break;
+    case 69: // Num lock press
+        s->num_lock_mode ^= 1;
+        if (s->num_lock_mode == 2)
+            return; // Drop second press
+        break;
+    case 186: // Caps lock release
+        s->caps_lock_mode ^= 2;
+        if (s->caps_lock_mode == 3)
+            return; // Drop first release
+        break;
+    case 197: // Num lock release
+        s->num_lock_mode ^= 2;
+        if (s->num_lock_mode == 3)
+            return; // Drop first release
+        break;
+    case 0xe0:
+        s->e0_mode = 1;
+        return;
+    default:
+        break;
+    }
+    if (s->e0_mode) {
+        s->e0_mode = 0;
+        ch = e0_keycodes[ch & 0x7f];
+    } else {
+        ch = keycodes[ch & 0x7f];
+    }
+    KBD_DPRINTF("Translated keycode %2.2x\n", ch);
     put_queue(s, ch | release);
 }
 
 static void handle_kbd_command(ChannelState *s, int val)
 {
     KBD_DPRINTF("Command %d\n", val);
+    if (s->led_mode) { // Ignore led byte
+        s->led_mode = 0;
+        return;
+    }
     switch (val) {
     case 1: // Reset, return type code
+        clear_queue(s);
 	put_queue(s, 0xff);
-	put_queue(s, 5); // Type 5
+	put_queue(s, 4); // Type 4
+	put_queue(s, 0x7f);
 	break;
+    case 0xe: // Set leds
+        s->led_mode = 1;
+        break;
     case 7: // Query layout
+    case 0xf:
+        clear_queue(s);
 	put_queue(s, 0xfe);
-	put_queue(s, 0x20); // XXX, layout?
+	put_queue(s, 0); // XXX, layout?
 	break;
     default:
 	break;
     }
 }
 
-static void sunmouse_event(void *opaque, 
+static void sunmouse_event(void *opaque,
                                int dx, int dy, int dz, int buttons_state)
 {
     ChannelState *s = opaque;
     int ch;
 
-    /* XXX: SDL sometimes generates nul events: we delete them */
-    if (dx == 0 && dy == 0 && dz == 0 && buttons_state == 0)
-        return;
     MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
 
     ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
@@ -661,7 +759,7 @@
     put_queue(s, 0);
 }
 
-void slavio_serial_ms_kbd_init(int base, int irq)
+void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq)
 {
     int slavio_serial_io_memory, i;
     SerialState *s;
@@ -680,10 +778,11 @@
     s->chn[1].type = kbd;
 
     slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
-    cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
+    cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory);
 
     qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, "QEMU Sun Mouse");
     qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
+    register_savevm("slavio_serial_mouse", base, 2, slavio_serial_save, slavio_serial_load, s);
     qemu_register_reset(slavio_serial_reset, s);
     slavio_serial_reset(s);
 }
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
index 976f0d4..d3c75bf 100644
--- a/hw/slavio_timer.c
+++ b/hw/slavio_timer.c
@@ -2,7 +2,7 @@
  * QEMU Sparc SLAVIO timer controller emulation
  *
  * Copyright (c) 2003-2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -38,7 +38,7 @@
  * This is the timer/counter part of chip STP2001 (Slave I/O), also
  * produced as NCR89C105. See
  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- * 
+ *
  * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
  * are zero. Bit 31 is 1 when count has been reached.
  *
@@ -48,62 +48,28 @@
  */
 
 typedef struct SLAVIO_TIMERState {
-    uint32_t limit, count, counthigh;
-    int64_t count_load_time;
-    int64_t expire_time;
-    int64_t stop_time, tick_offset;
-    QEMUTimer *irq_timer;
-    int irq;
-    int reached, stopped;
+    qemu_irq irq;
+    ptimer_state *timer;
+    uint32_t count, counthigh, reached;
+    uint64_t limit;
+    int stopped;
     int mode; // 0 = processor, 1 = user, 2 = system
-    unsigned int cpu;
 } SLAVIO_TIMERState;
 
 #define TIMER_MAXADDR 0x1f
-#define CNT_FREQ 2000000
+#define TIMER_SIZE (TIMER_MAXADDR + 1)
 
 // Update count, set irq, update expire_time
+// Convert from ptimer countdown units
 static void slavio_timer_get_out(SLAVIO_TIMERState *s)
 {
-    int out;
-    int64_t diff, ticks, count;
-    uint32_t limit;
+    uint64_t count;
 
-    // There are three clock tick units: CPU ticks, register units
-    // (nanoseconds), and counter ticks (500 ns).
-    if (s->mode == 1 && s->stopped)
-	ticks = s->stop_time;
-    else
-	ticks = qemu_get_clock(vm_clock) - s->tick_offset;
-
-    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;
-
-    // Convert cpu ticks to counter ticks
-    diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
-
-    // Calculate what the counter should be, convert to register
-    // units
-    count = diff % limit;
-    s->count = count << 9;
-    s->counthigh = count >> 22;
-
-    // Expire time: CPU ticks left to next interrupt
-    // Convert remaining counter ticks to CPU ticks
-    s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
-
-    DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
-
-    if (s->mode != 1)
-	pic_set_irq_cpu(s->irq, out, s->cpu);
+    count = s->limit - (ptimer_get_count(s->timer) << 9);
+    DPRINTF("get_out: limit %" PRIx64 " count %x%08x\n", s->limit, s->counthigh,
+            s->count);
+    s->count = count & 0xfffffe00;
+    s->counthigh = count >> 32;
 }
 
 // timer callback
@@ -111,17 +77,17 @@
 {
     SLAVIO_TIMERState *s = opaque;
 
-    if (!s->irq_timer)
-        return;
     slavio_timer_get_out(s);
+    DPRINTF("callback: count %x%08x\n", s->counthigh, s->count);
+    s->reached = 0x80000000;
     if (s->mode != 1)
-	qemu_mod_timer(s->irq_timer, s->expire_time);
+	qemu_irq_raise(s->irq);
 }
 
 static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
 {
     SLAVIO_TIMERState *s = opaque;
-    uint32_t saddr;
+    uint32_t saddr, ret;
 
     saddr = (addr & TIMER_MAXADDR) >> 2;
     switch (saddr) {
@@ -130,63 +96,71 @@
 	// part of counter (user mode)
 	if (s->mode != 1) {
 	    // clear irq
-	    pic_set_irq_cpu(s->irq, 0, s->cpu);
-	    s->count_load_time = qemu_get_clock(vm_clock);
+            qemu_irq_lower(s->irq);
 	    s->reached = 0;
-	    return s->limit;
+            ret = s->limit & 0x7fffffff;
 	}
 	else {
 	    slavio_timer_get_out(s);
-	    return s->counthigh & 0x7fffffff;
+            ret = s->counthigh & 0x7fffffff;
 	}
+        break;
     case 1:
 	// read counter and reached bit (system mode) or read lsbits
 	// of counter (user mode)
 	slavio_timer_get_out(s);
 	if (s->mode != 1)
-	    return (s->count & 0x7fffffff) | s->reached;
+            ret = (s->count & 0x7fffffff) | s->reached;
 	else
-	    return s->count;
+            ret = s->count;
+        break;
     case 3:
 	// read start/stop status
-	return s->stopped;
+        ret = s->stopped;
+        break;
     case 4:
 	// read user/system mode
-	return s->mode & 1;
+        ret = s->mode & 1;
+        break;
     default:
-	return 0;
+        ret = 0;
+        break;
     }
+    DPRINTF("read " TARGET_FMT_plx " = %08x\n", addr, ret);
+
+    return ret;
 }
 
 static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
 {
     SLAVIO_TIMERState *s = opaque;
     uint32_t saddr;
+    int reload = 0;
 
+    DPRINTF("write " TARGET_FMT_plx " %08x\n", addr, val);
     saddr = (addr & TIMER_MAXADDR) >> 2;
     switch (saddr) {
     case 0:
 	// set limit, reset counter
-	s->count_load_time = qemu_get_clock(vm_clock);
+        reload = 1;
+	qemu_irq_lower(s->irq);
 	// fall through
     case 2:
 	// set limit without resetting counter
-	if (!val)
-	    s->limit = 0x7fffffff;
-	else
-	    s->limit = val & 0x7fffffff;
-	slavio_timer_irq(s);
+        s->limit = val & 0x7ffffe00ULL;
+        if (!s->limit)
+            s->limit = 0x7ffffe00ULL;
+        ptimer_set_limit(s->timer, s->limit >> 9, reload);
 	break;
     case 3:
 	// start/stop user counter
 	if (s->mode == 1) {
 	    if (val & 1) {
-		s->stop_time = qemu_get_clock(vm_clock);
+                ptimer_stop(s->timer);
 		s->stopped = 1;
 	    }
 	    else {
-		if (s->stopped)
-		    s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time;
+                ptimer_run(s->timer, 0);
 		s->stopped = 0;
 	    }
 	}
@@ -195,6 +169,11 @@
 	// bit 0: user (1) or system (0) counter mode
 	if (s->mode == 0 || s->mode == 1)
 	    s->mode = val & 1;
+        if (s->mode == 1) {
+            qemu_irq_lower(s->irq);
+            s->limit = -1ULL;
+        }
+        ptimer_set_limit(s->timer, s->limit >> 9, 1);
 	break;
     default:
 	break;
@@ -217,37 +196,33 @@
 {
     SLAVIO_TIMERState *s = opaque;
 
-    qemu_put_be32s(f, &s->limit);
+    qemu_put_be64s(f, &s->limit);
     qemu_put_be32s(f, &s->count);
     qemu_put_be32s(f, &s->counthigh);
-    qemu_put_be64s(f, &s->count_load_time);
-    qemu_put_be64s(f, &s->expire_time);
-    qemu_put_be64s(f, &s->stop_time);
-    qemu_put_be64s(f, &s->tick_offset);
-    qemu_put_be32s(f, &s->irq);
+    qemu_put_be32(f, 0); // Was irq
     qemu_put_be32s(f, &s->reached);
     qemu_put_be32s(f, &s->stopped);
     qemu_put_be32s(f, &s->mode);
+    qemu_put_ptimer(f, s->timer);
 }
 
 static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
 {
     SLAVIO_TIMERState *s = opaque;
-    
-    if (version_id != 1)
+    uint32_t tmp;
+
+    if (version_id != 2)
         return -EINVAL;
 
-    qemu_get_be32s(f, &s->limit);
+    qemu_get_be64s(f, &s->limit);
     qemu_get_be32s(f, &s->count);
     qemu_get_be32s(f, &s->counthigh);
-    qemu_get_be64s(f, &s->count_load_time);
-    qemu_get_be64s(f, &s->expire_time);
-    qemu_get_be64s(f, &s->stop_time);
-    qemu_get_be64s(f, &s->tick_offset);
-    qemu_get_be32s(f, &s->irq);
+    qemu_get_be32s(f, &tmp); // Was irq
     qemu_get_be32s(f, &s->reached);
     qemu_get_be32s(f, &s->stopped);
     qemu_get_be32s(f, &s->mode);
+    qemu_get_ptimer(f, s->timer);
+
     return 0;
 }
 
@@ -255,34 +230,35 @@
 {
     SLAVIO_TIMERState *s = opaque;
 
-    s->limit = 0;
+    s->limit = 0x7ffffe00ULL;
     s->count = 0;
-    s->count_load_time = qemu_get_clock(vm_clock);;
-    s->stop_time = s->count_load_time;
-    s->tick_offset = 0;
     s->reached = 0;
     s->mode &= 2;
+    ptimer_set_limit(s->timer, s->limit >> 9, 1);
+    ptimer_run(s->timer, 0);
     s->stopped = 1;
-    slavio_timer_get_out(s);
+    qemu_irq_lower(s->irq);
 }
 
-void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu)
+void slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode)
 {
     int slavio_timer_io_memory;
     SLAVIO_TIMERState *s;
+    QEMUBH *bh;
 
     s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
     if (!s)
         return;
     s->irq = irq;
     s->mode = mode;
-    s->cpu = cpu;
-    s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
+    bh = qemu_bh_new(slavio_timer_irq, s);
+    s->timer = ptimer_init(bh);
+    ptimer_set_period(s->timer, 500ULL);
 
     slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
 						    slavio_timer_mem_write, s);
-    cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory);
-    register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s);
+    cpu_register_physical_memory(addr, TIMER_SIZE, slavio_timer_io_memory);
+    register_savevm("slavio_timer", addr, 2, slavio_timer_save, slavio_timer_load, s);
     qemu_register_reset(slavio_timer_reset, s);
     slavio_timer_reset(s);
 }
diff --git a/hw/smbus.c b/hw/smbus.c
new file mode 100644
index 0000000..103e917
--- /dev/null
+++ b/hw/smbus.c
@@ -0,0 +1,306 @@
+/*
+ * QEMU SMBus device emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+/* TODO: Implement PEC.  */
+
+#include "vl.h"
+
+//#define DEBUG_SMBUS 1
+
+#ifdef DEBUG_SMBUS
+#define DPRINTF(fmt, args...) \
+do { printf("smbus(%02x): " fmt , dev->i2c.address, ##args); } while (0)
+#define BADF(fmt, args...) \
+do { fprintf(stderr, "smbus: error: " fmt , ##args); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#define BADF(fmt, args...) \
+do { fprintf(stderr, "smbus: error: " fmt , ##args);} while (0)
+#endif
+
+enum {
+    SMBUS_IDLE,
+    SMBUS_WRITE_DATA,
+    SMBUS_RECV_BYTE,
+    SMBUS_READ_DATA,
+    SMBUS_DONE,
+    SMBUS_CONFUSED = -1
+};
+
+static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
+{
+    DPRINTF("Quick Command %d\n", recv);
+    if (dev->quick_cmd)
+        dev->quick_cmd(dev, recv);
+}
+
+static void smbus_do_write(SMBusDevice *dev)
+{
+    if (dev->data_len == 0) {
+        smbus_do_quick_cmd(dev, 0);
+    } else if (dev->data_len == 1) {
+        DPRINTF("Send Byte\n");
+        if (dev->send_byte) {
+            dev->send_byte(dev, dev->data_buf[0]);
+        }
+    } else {
+        dev->command = dev->data_buf[0];
+        DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
+        if (dev->write_data) {
+            dev->write_data(dev, dev->command, dev->data_buf + 1,
+                            dev->data_len - 1);
+        }
+    }
+}
+
+void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
+{
+    SMBusDevice *dev = (SMBusDevice *)s;
+    switch (event) {
+    case I2C_START_SEND:
+        switch (dev->mode) {
+        case SMBUS_IDLE:
+            DPRINTF("Incoming data\n");
+            dev->mode = SMBUS_WRITE_DATA;
+            break;
+        default:
+            BADF("Unexpected send start condition in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+        break;
+
+    case I2C_START_RECV:
+        switch (dev->mode) {
+        case SMBUS_IDLE:
+            DPRINTF("Read mode\n");
+            dev->mode = SMBUS_RECV_BYTE;
+            break;
+        case SMBUS_WRITE_DATA:
+            if (dev->data_len == 0) {
+                BADF("Read after write with no data\n");
+                dev->mode = SMBUS_CONFUSED;
+            } else {
+                if (dev->data_len > 1) {
+                    smbus_do_write(dev);
+                } else {
+                    dev->command = dev->data_buf[0];
+                    DPRINTF("%02x: Command %d\n", dev->i2c.address,
+                            dev->command);
+                }
+                DPRINTF("Read mode\n");
+                dev->data_len = 0;
+                dev->mode = SMBUS_READ_DATA;
+            }
+            break;
+        default:
+            BADF("Unexpected recv start condition in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+        break;
+
+    case I2C_FINISH:
+        switch (dev->mode) {
+        case SMBUS_WRITE_DATA:
+            smbus_do_write(dev);
+            break;
+        case SMBUS_RECV_BYTE:
+            smbus_do_quick_cmd(dev, 1);
+            break;
+        case SMBUS_READ_DATA:
+            BADF("Unexpected stop during receive\n");
+            break;
+        default:
+            /* Nothing to do.  */
+            break;
+        }
+        dev->mode = SMBUS_IDLE;
+        dev->data_len = 0;
+        break;
+
+    case I2C_NACK:
+        switch (dev->mode) {
+        case SMBUS_DONE:
+            /* Nothing to do.  */
+            break;
+        case SMBUS_READ_DATA:
+            dev->mode = SMBUS_DONE;
+            break;
+        default:
+            BADF("Unexpected NACK in state %d\n", dev->mode);
+            dev->mode = SMBUS_CONFUSED;
+            break;
+        }
+    }
+}
+
+static int smbus_i2c_recv(i2c_slave *s)
+{
+    SMBusDevice *dev = (SMBusDevice *)s;
+    int ret;
+
+    switch (dev->mode) {
+    case SMBUS_RECV_BYTE:
+        if (dev->receive_byte) {
+            ret = dev->receive_byte(dev);
+        } else {
+            ret = 0;
+        }
+        DPRINTF("Receive Byte %02x\n", ret);
+        dev->mode = SMBUS_DONE;
+        break;
+    case SMBUS_READ_DATA:
+        if (dev->read_data) {
+            ret = dev->read_data(dev, dev->command, dev->data_len);
+            dev->data_len++;
+        } else {
+            ret = 0;
+        }
+        DPRINTF("Read data %02x\n", ret);
+        break;
+    default:
+        BADF("Unexpected read in state %d\n", dev->mode);
+        dev->mode = SMBUS_CONFUSED;
+        ret = 0;
+        break;
+    }
+    return ret;
+}
+
+static int smbus_i2c_send(i2c_slave *s, uint8_t data)
+{
+    SMBusDevice *dev = (SMBusDevice *)s;
+    switch (dev->mode) {
+    case SMBUS_WRITE_DATA:
+        DPRINTF("Write data %02x\n", data);
+        dev->data_buf[dev->data_len++] = data;
+        break;
+    default:
+        BADF("Unexpected write in state %d\n", dev->mode);
+        break;
+    }
+    return 0;
+}
+
+SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size)
+{
+    SMBusDevice *dev;
+
+    if (size < sizeof(SMBusDevice))
+        cpu_abort(cpu_single_env, "SMBus struct too small");
+
+    dev = (SMBusDevice *)i2c_slave_init(bus, address, size);
+    dev->i2c.event = smbus_i2c_event;
+    dev->i2c.recv = smbus_i2c_recv;
+    dev->i2c.send = smbus_i2c_send;
+
+    return dev;
+}
+
+/* Master device commands.  */
+void smbus_quick_command(i2c_bus *bus, int addr, int read)
+{
+    i2c_start_transfer(bus, addr, read);
+    i2c_end_transfer(bus);
+}
+
+uint8_t smbus_receive_byte(i2c_bus *bus, int addr)
+{
+    uint8_t data;
+
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, data);
+    i2c_end_transfer(bus);
+}
+
+uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command)
+{
+    uint8_t data;
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, data);
+    i2c_end_transfer(bus);
+}
+
+uint16_t smbus_read_word(i2c_bus *bus, int addr, uint8_t command)
+{
+    uint16_t data;
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    data = i2c_recv(bus);
+    data |= i2c_recv(bus) << 8;
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return data;
+}
+
+void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data)
+{
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, data & 0xff);
+    i2c_send(bus, data >> 8);
+    i2c_end_transfer(bus);
+}
+
+int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data)
+{
+    int len;
+    int i;
+
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_start_transfer(bus, addr, 1);
+    len = i2c_recv(bus);
+    if (len > 32)
+        len = 0;
+    for (i = 0; i < len; i++)
+        data[i] = i2c_recv(bus);
+    i2c_nack(bus);
+    i2c_end_transfer(bus);
+    return len;
+}
+
+void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data,
+                       int len)
+{
+    int i;
+
+    if (len > 32)
+        len = 32;
+
+    i2c_start_transfer(bus, addr, 0);
+    i2c_send(bus, command);
+    i2c_send(bus, len);
+    for (i = 0; i < len; i++)
+        i2c_send(bus, data[i]);
+    i2c_end_transfer(bus);
+}
diff --git a/hw/smbus.h b/hw/smbus.h
index 76fc3c8..0d35bb6 100644
--- a/hw/smbus.h
+++ b/hw/smbus.h
@@ -1,8 +1,8 @@
 /*
  * QEMU SMBus API
- * 
+ *
  * Copyright (c) 2007 Arastra, Inc.
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -25,14 +25,46 @@
 typedef struct SMBusDevice SMBusDevice;
 
 struct SMBusDevice {
-    uint8_t addr;
+    /* The SMBus protocol is implemented on top of I2C.  */
+    i2c_slave i2c;
+
+    /* Callbacks set by the device.  */
     void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
     void (*send_byte)(SMBusDevice *dev, uint8_t val);
     uint8_t (*receive_byte)(SMBusDevice *dev);
-    void (*write_byte)(SMBusDevice *dev, uint8_t cmd, uint8_t val);
-    uint8_t (*read_byte)(SMBusDevice *dev, uint8_t cmd);
-    void (*write_word)(SMBusDevice *dev, uint8_t cmd, uint16_t val);
-    uint16_t (*read_word)(SMBusDevice *dev, uint8_t cmd);
-    void (*write_block)(SMBusDevice *dev, uint8_t cmd, uint8_t len, uint8_t *buf);
-    uint8_t (*read_block)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf);
+    /* We can't distinguish between a word write and a block write with
+       length 1, so pass the whole data block including the length byte
+       (if present).  The device is responsible figuring out what type of
+       command  this is.  */
+    void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len);
+    /* Likewise we can't distinguish between different reads, or even know
+       the length of the read until the read is complete, so read data a
+       byte at a time.  The device is responsible for adding the length
+       byte on block reads.  */
+    uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n);
+
+    /* Remaining fields for internal use only.  */
+    int mode;
+    int data_len;
+    uint8_t data_buf[34]; /* command + len + 32 bytes of data.  */
+    uint8_t command;
 };
+
+/* Create a slave device.  */
+SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size);
+
+/* Master device commands.  */
+void smbus_quick_command(i2c_bus *bus, int addr, int read);
+uint8_t smbus_receive_byte(i2c_bus *bus, int addr);
+void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data);
+uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command);
+void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data);
+uint16_t smbus_read_word(i2c_bus *bus, int addr, uint8_t command);
+void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data);
+int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data);
+void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data,
+                       int len);
+
+/* smbus_eeprom.c */
+void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf);
+
diff --git a/hw/smbus_eeprom.c b/hw/smbus_eeprom.c
index d401b17..cf54c34 100644
--- a/hw/smbus_eeprom.c
+++ b/hw/smbus_eeprom.c
@@ -1,8 +1,8 @@
 /*
  * QEMU SMBus EEPROM device
- * 
+ *
  * Copyright (c) 2007 Arastra, Inc.
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -58,37 +58,51 @@
     return val;
 }
 
-static void eeprom_write_byte(SMBusDevice *dev, uint8_t cmd, uint8_t val)
+static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
 {
     SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+    int n;
 #ifdef DEBUG
     printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", dev->addr,
-           cmd, val);
+           cmd, buf[0]);
 #endif
-    eeprom->data[cmd] = val;
+    /* An page write operation is not a valid SMBus command.
+       It is a block write without a length byte.  Fortunately we
+       get the full block anyway.  */
+    /* TODO: Should this set the current location?  */
+    if (cmd + len > 256)
+        n = 256 - cmd;
+    else
+        n = len;
+    memcpy(eeprom->data + cmd, buf, n);
+    len -= n;
+    if (len)
+        memcpy(eeprom->data, buf + n, len);
 }
 
-static uint8_t eeprom_read_byte(SMBusDevice *dev, uint8_t cmd)
+static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
 {
     SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
-    uint8_t val = eeprom->data[cmd];
-#ifdef DEBUG
-    printf("eeprom_read_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", dev->addr,
-           cmd, val);
-#endif
-    return val;
+    /* If this is the first byte then set the current position.  */
+    if (n == 0)
+        eeprom->offset = cmd;
+    /* As with writes, we implement block reads without the
+       SMBus length byte.  */
+    return eeprom_receive_byte(dev);
 }
 
-SMBusDevice *smbus_eeprom_device_init(uint8_t addr, uint8_t *buf)
+void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf)
 {
-    SMBusEEPROMDevice *eeprom = qemu_mallocz(sizeof(SMBusEEPROMDevice));
-    eeprom->dev.addr = addr;
+    SMBusEEPROMDevice *eeprom;
+
+    eeprom = (SMBusEEPROMDevice *)smbus_device_init(bus, addr,
+        sizeof(SMBusEEPROMDevice));
+
     eeprom->dev.quick_cmd = eeprom_quick_cmd;
     eeprom->dev.send_byte = eeprom_send_byte;
     eeprom->dev.receive_byte = eeprom_receive_byte;
-    eeprom->dev.write_byte = eeprom_write_byte;
-    eeprom->dev.read_byte = eeprom_read_byte;
+    eeprom->dev.write_data = eeprom_write_data;
+    eeprom->dev.read_data = eeprom_read_data;
     eeprom->data = buf;
     eeprom->offset = 0;
-    return (SMBusDevice *) eeprom;
 }
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 0249cfe..b8d0cba 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * SMSC 91C111 Ethernet interface emulation
  *
  * Copyright (c) 2005 CodeSourcery, LLC.
@@ -24,8 +24,7 @@
     uint16_t gpr;
     uint16_t ptr;
     uint16_t ercv;
-    void *pic;
-    int irq;
+    qemu_irq irq;
     int bank;
     int packet_num;
     int tx_alloc;
@@ -86,7 +85,7 @@
     if (s->tx_fifo_done_len != 0)
         s->int_level |= INT_TX;
     level = (s->int_level & s->int_mask) != 0;
-    pic_set_irq_new(s->pic, s->irq, level);
+    qemu_set_irq(s->irq, level);
 }
 
 /* Try to allocate a packet.  Returns 0x80 on failure.  */
@@ -446,7 +445,9 @@
         case 7:
             /* Not implemented.  */
             return 0;
-        case 8: /* Free memory available.  */
+        case 8: /* Memory size.  */
+            return NUM_PACKETS;
+        case 9: /* Free memory available.  */
             {
                 int i;
                 int n;
@@ -457,8 +458,6 @@
                 }
                 return n;
             }
-        case 9: /* Memory size.  */
-            return NUM_PACKETS;
         case 10: case 11: /* RPCR */
             /* Not implemented.  */
             return 0;
@@ -650,7 +649,7 @@
     /* Pad short packets.  */
     if (size < 64) {
         int pad;
-        
+
         if (size & 1)
             *(p++) = buf[size - 1];
         pad = 64 - size;
@@ -693,7 +692,7 @@
     smc91c111_writel
 };
 
-void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq)
+void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
 {
     smc91c111_state *s;
     int iomemtype;
@@ -703,7 +702,6 @@
                                        smc91c111_writefn, s);
     cpu_register_physical_memory(base, 16, iomemtype);
     s->base = base;
-    s->pic = pic;
     s->irq = irq;
     memcpy(s->macaddr, nd->macaddr, 6);
 
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index b17a12b..3c80fd6 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -37,40 +37,33 @@
 #ifdef DEBUG_DMA
 #define DPRINTF(fmt, args...) \
 do { printf("DMA: " fmt , ##args); } while (0)
-#define pic_set_irq_new(ctl, irq, level)                                \
-    do { printf("DMA: set_irq(%d): %d\n", (irq), (level));              \
-        pic_set_irq_new((ctl), (irq),(level));} while (0)
 #else
 #define DPRINTF(fmt, args...)
 #endif
 
-#define DMA_REGS 8
-#define DMA_MAXADDR (DMA_REGS * 4 - 1)
+#define DMA_REGS 4
+#define DMA_SIZE (4 * sizeof(uint32_t))
+#define DMA_MAXADDR (DMA_SIZE - 1)
 
 #define DMA_VER 0xa0000000
 #define DMA_INTR 1
 #define DMA_INTREN 0x10
 #define DMA_WRITE_MEM 0x100
 #define DMA_LOADED 0x04000000
+#define DMA_DRAIN_FIFO 0x40
 #define DMA_RESET 0x80
 
 typedef struct DMAState DMAState;
 
 struct DMAState {
     uint32_t dmaregs[DMA_REGS];
-    int espirq, leirq;
-    void *iommu, *esp_opaque, *lance_opaque, *intctl;
+    qemu_irq irq;
+    void *iommu;
+    qemu_irq dev_reset;
 };
 
-void ledma_set_irq(void *opaque, int isr)
-{
-    DMAState *s = opaque;
-
-    pic_set_irq_new(s->intctl, s->leirq, isr);
-}
-
 /* Note: on sparc, the lance 16 bit bus is swapped */
-void ledma_memory_read(void *opaque, target_phys_addr_t addr, 
+void ledma_memory_read(void *opaque, target_phys_addr_t addr,
                        uint8_t *buf, int len, int do_bswap)
 {
     DMAState *s = opaque;
@@ -78,7 +71,7 @@
 
     DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n",
             s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
-    addr |= s->dmaregs[7];
+    addr |= s->dmaregs[3];
     if (do_bswap) {
         sparc_iommu_memory_read(s->iommu, addr, buf, len);
     } else {
@@ -91,7 +84,7 @@
     }
 }
 
-void ledma_memory_write(void *opaque, target_phys_addr_t addr, 
+void ledma_memory_write(void *opaque, target_phys_addr_t addr,
                         uint8_t *buf, int len, int do_bswap)
 {
     DMAState *s = opaque;
@@ -100,7 +93,7 @@
 
     DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n",
             s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]);
-    addr |= s->dmaregs[7];
+    addr |= s->dmaregs[3];
     if (do_bswap) {
         sparc_iommu_memory_write(s->iommu, addr, buf, len);
     } else {
@@ -121,20 +114,18 @@
     }
 }
 
-void espdma_raise_irq(void *opaque)
+static void dma_set_irq(void *opaque, int irq, int level)
 {
     DMAState *s = opaque;
-
-    s->dmaregs[0] |= DMA_INTR;
-    pic_set_irq_new(s->intctl, s->espirq, 1);
-}
-
-void espdma_clear_irq(void *opaque)
-{
-    DMAState *s = opaque;
-
-    s->dmaregs[0] &= ~DMA_INTR;
-    pic_set_irq_new(s->intctl, s->espirq, 0);
+    if (level) {
+        DPRINTF("Raise IRQ\n");
+        s->dmaregs[0] |= DMA_INTR;
+        qemu_irq_raise(s->irq);
+    } else {
+        s->dmaregs[0] &= ~DMA_INTR;
+        DPRINTF("Lower IRQ\n");
+        qemu_irq_lower(s->irq);
+    }
 }
 
 void espdma_memory_read(void *opaque, uint8_t *buf, int len)
@@ -165,7 +156,8 @@
     uint32_t saddr;
 
     saddr = (addr & DMA_MAXADDR) >> 2;
-    DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->dmaregs[saddr]);
+    DPRINTF("read dmareg " TARGET_FMT_plx ": 0x%8.8x\n", addr,
+            s->dmaregs[saddr]);
 
     return s->dmaregs[saddr];
 }
@@ -176,31 +168,27 @@
     uint32_t saddr;
 
     saddr = (addr & DMA_MAXADDR) >> 2;
-    DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->dmaregs[saddr], val);
+    DPRINTF("write dmareg " TARGET_FMT_plx ": 0x%8.8x -> 0x%8.8x\n", addr,
+            s->dmaregs[saddr], val);
     switch (saddr) {
     case 0:
-        if (!(val & DMA_INTREN))
-            pic_set_irq_new(s->intctl, s->espirq, 0);
+        if (!(val & DMA_INTREN)) {
+            DPRINTF("Lower IRQ\n");
+            qemu_irq_lower(s->irq);
+        }
         if (val & DMA_RESET) {
-            esp_reset(s->esp_opaque);
-        } else if (val & 0x40) {
-            val &= ~0x40;
+            qemu_irq_raise(s->dev_reset);
+            qemu_irq_lower(s->dev_reset);
+        } else if (val & DMA_DRAIN_FIFO) {
+            val &= ~DMA_DRAIN_FIFO;
         } else if (val == 0)
-            val = 0x40;
+            val = DMA_DRAIN_FIFO;
         val &= 0x0fffffff;
         val |= DMA_VER;
         break;
     case 1:
         s->dmaregs[0] |= DMA_LOADED;
         break;
-    case 4:
-        if (!(val & DMA_INTREN))
-            pic_set_irq_new(s->intctl, s->leirq, 0);
-        if (val & DMA_RESET)
-            pcnet_h_reset(s->lance_opaque);
-        val &= 0x0fffffff;
-        val |= DMA_VER;
-        break;
     default:
         break;
     }
@@ -223,9 +211,8 @@
 {
     DMAState *s = opaque;
 
-    memset(s->dmaregs, 0, DMA_REGS * 4);
+    memset(s->dmaregs, 0, DMA_SIZE);
     s->dmaregs[0] = DMA_VER;
-    s->dmaregs[4] = DMA_VER;
 }
 
 static void dma_save(QEMUFile *f, void *opaque)
@@ -242,7 +229,7 @@
     DMAState *s = opaque;
     unsigned int i;
 
-    if (version_id != 1)
+    if (version_id != 2)
         return -EINVAL;
     for (i = 0; i < DMA_REGS; i++)
         qemu_get_be32s(f, &s->dmaregs[i]);
@@ -250,7 +237,8 @@
     return 0;
 }
 
-void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, void *intctl)
+void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq,
+                       void *iommu, qemu_irq **dev_irq, qemu_irq **reset)
 {
     DMAState *s;
     int dma_io_memory;
@@ -259,25 +247,17 @@
     if (!s)
         return NULL;
 
-    s->espirq = espirq;
-    s->leirq = leirq;
+    s->irq = parent_irq;
     s->iommu = iommu;
-    s->intctl = intctl;
 
     dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s);
-    cpu_register_physical_memory(daddr, 16 * 2, dma_io_memory);
+    cpu_register_physical_memory(daddr, DMA_SIZE, dma_io_memory);
 
-    register_savevm("sparc32_dma", daddr, 1, dma_save, dma_load, s);
+    register_savevm("sparc32_dma", daddr, 2, dma_save, dma_load, s);
     qemu_register_reset(dma_reset, s);
+    *dev_irq = qemu_allocate_irqs(dma_set_irq, s, 1);
+
+    *reset = &s->dev_reset;
 
     return s;
 }
-
-void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque,
-                                void *lance_opaque)
-{
-    DMAState *s = opaque;
-
-    s->esp_opaque = esp_opaque;
-    s->lance_opaque = lance_opaque;
-}
diff --git a/hw/spitz.c b/hw/spitz.c
new file mode 100644
index 0000000..540e1b2
--- /dev/null
+++ b/hw/spitz.c
@@ -0,0 +1,1285 @@
+/*
+ * PXA270-based Clamshell PDA platforms.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This code is licensed under the GNU GPL v2.
+ */
+
+#include "vl.h"
+
+#define spitz_printf(format, ...)	\
+    fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
+#undef REG_FMT
+#define REG_FMT			"0x%02lx"
+
+/* Spitz Flash */
+#define FLASH_BASE		0x0c000000
+#define FLASH_ECCLPLB		0x00	/* Line parity 7 - 0 bit */
+#define FLASH_ECCLPUB		0x04	/* Line parity 15 - 8 bit */
+#define FLASH_ECCCP		0x08	/* Column parity 5 - 0 bit */
+#define FLASH_ECCCNTR		0x0c	/* ECC byte counter */
+#define FLASH_ECCCLRR		0x10	/* Clear ECC */
+#define FLASH_FLASHIO		0x14	/* Flash I/O */
+#define FLASH_FLASHCTL		0x18	/* Flash Control */
+
+#define FLASHCTL_CE0		(1 << 0)
+#define FLASHCTL_CLE		(1 << 1)
+#define FLASHCTL_ALE		(1 << 2)
+#define FLASHCTL_WP		(1 << 3)
+#define FLASHCTL_CE1		(1 << 4)
+#define FLASHCTL_RYBY		(1 << 5)
+#define FLASHCTL_NCE		(FLASHCTL_CE0 | FLASHCTL_CE1)
+
+struct sl_nand_s {
+    target_phys_addr_t target_base;
+    struct nand_flash_s *nand;
+    uint8_t ctl;
+    struct ecc_state_s ecc;
+};
+
+static uint32_t sl_readb(void *opaque, target_phys_addr_t addr)
+{
+    struct sl_nand_s *s = (struct sl_nand_s *) opaque;
+    int ryby;
+    addr -= s->target_base;
+
+    switch (addr) {
+#define BSHR(byte, from, to)	((s->ecc.lp[byte] >> (from - to)) & (1 << to))
+    case FLASH_ECCLPLB:
+        return BSHR(0, 4, 0) | BSHR(0, 5, 2) | BSHR(0, 6, 4) | BSHR(0, 7, 6) |
+                BSHR(1, 4, 1) | BSHR(1, 5, 3) | BSHR(1, 6, 5) | BSHR(1, 7, 7);
+
+#define BSHL(byte, from, to)	((s->ecc.lp[byte] << (to - from)) & (1 << to))
+    case FLASH_ECCLPUB:
+        return BSHL(0, 0, 0) | BSHL(0, 1, 2) | BSHL(0, 2, 4) | BSHL(0, 3, 6) |
+                BSHL(1, 0, 1) | BSHL(1, 1, 3) | BSHL(1, 2, 5) | BSHL(1, 3, 7);
+
+    case FLASH_ECCCP:
+        return s->ecc.cp;
+
+    case FLASH_ECCCNTR:
+        return s->ecc.count & 0xff;
+
+    case FLASH_FLASHCTL:
+        nand_getpins(s->nand, &ryby);
+        if (ryby)
+            return s->ctl | FLASHCTL_RYBY;
+        else
+            return s->ctl;
+
+    case FLASH_FLASHIO:
+        return ecc_digest(&s->ecc, nand_getio(s->nand));
+
+    default:
+        spitz_printf("Bad register offset " REG_FMT "\n", addr);
+    }
+    return 0;
+}
+
+static uint32_t sl_readl(void *opaque, target_phys_addr_t addr)
+{
+    struct sl_nand_s *s = (struct sl_nand_s *) opaque;
+    addr -= s->target_base;
+
+    if (addr == FLASH_FLASHIO)
+        return ecc_digest(&s->ecc, nand_getio(s->nand)) |
+                (ecc_digest(&s->ecc, nand_getio(s->nand)) << 16);
+
+    return sl_readb(opaque, addr);
+}
+
+static void sl_writeb(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct sl_nand_s *s = (struct sl_nand_s *) opaque;
+    addr -= s->target_base;
+
+    switch (addr) {
+    case FLASH_ECCCLRR:
+        /* Value is ignored.  */
+        ecc_reset(&s->ecc);
+        break;
+
+    case FLASH_FLASHCTL:
+        s->ctl = value & 0xff & ~FLASHCTL_RYBY;
+        nand_setpins(s->nand,
+                        s->ctl & FLASHCTL_CLE,
+                        s->ctl & FLASHCTL_ALE,
+                        s->ctl & FLASHCTL_NCE,
+                        s->ctl & FLASHCTL_WP,
+                        0);
+        break;
+
+    case FLASH_FLASHIO:
+        nand_setio(s->nand, ecc_digest(&s->ecc, value & 0xff));
+        break;
+
+    default:
+        spitz_printf("Bad register offset " REG_FMT "\n", addr);
+    }
+}
+
+static void sl_save(QEMUFile *f, void *opaque)
+{
+    struct sl_nand_s *s = (struct sl_nand_s *) opaque;
+
+    qemu_put_8s(f, &s->ctl);
+    ecc_put(f, &s->ecc);
+}
+
+static int sl_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct sl_nand_s *s = (struct sl_nand_s *) opaque;
+
+    qemu_get_8s(f, &s->ctl);
+    ecc_get(f, &s->ecc);
+
+    return 0;
+}
+
+enum {
+    FLASH_128M,
+    FLASH_1024M,
+};
+
+static void sl_flash_register(struct pxa2xx_state_s *cpu, int size)
+{
+    int iomemtype;
+    struct sl_nand_s *s;
+    CPUReadMemoryFunc *sl_readfn[] = {
+        sl_readb,
+        sl_readb,
+        sl_readl,
+    };
+    CPUWriteMemoryFunc *sl_writefn[] = {
+        sl_writeb,
+        sl_writeb,
+        sl_writeb,
+    };
+
+    s = (struct sl_nand_s *) qemu_mallocz(sizeof(struct sl_nand_s));
+    s->target_base = FLASH_BASE;
+    s->ctl = 0;
+    if (size == FLASH_128M)
+        s->nand = nand_init(NAND_MFR_SAMSUNG, 0x73);
+    else if (size == FLASH_1024M)
+        s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1);
+
+    iomemtype = cpu_register_io_memory(0, sl_readfn,
+                    sl_writefn, s);
+    cpu_register_physical_memory(s->target_base, 0x40, iomemtype);
+
+    register_savevm("sl_flash", 0, 0, sl_save, sl_load, s);
+}
+
+/* Spitz Keyboard */
+
+#define SPITZ_KEY_STROBE_NUM	11
+#define SPITZ_KEY_SENSE_NUM	7
+
+static const int spitz_gpio_key_sense[SPITZ_KEY_SENSE_NUM] = {
+    12, 17, 91, 34, 36, 38, 39
+};
+
+static const int spitz_gpio_key_strobe[SPITZ_KEY_STROBE_NUM] = {
+    88, 23, 24, 25, 26, 27, 52, 103, 107, 108, 114
+};
+
+/* Eighth additional row maps the special keys */
+static int spitz_keymap[SPITZ_KEY_SENSE_NUM + 1][SPITZ_KEY_STROBE_NUM] = {
+    { 0x1d, 0x02, 0x04, 0x06, 0x07, 0x08, 0x0a, 0x0b, 0x0e, 0x3f, 0x40 },
+    {  -1 , 0x03, 0x05, 0x13, 0x15, 0x09, 0x17, 0x18, 0x19, 0x41, 0x42 },
+    { 0x0f, 0x10, 0x12, 0x14, 0x22, 0x16, 0x24, 0x25,  -1 ,  -1 ,  -1  },
+    { 0x3c, 0x11, 0x1f, 0x21, 0x2f, 0x23, 0x32, 0x26,  -1 , 0x36,  -1  },
+    { 0x3b, 0x1e, 0x20, 0x2e, 0x30, 0x31, 0x34,  -1 , 0x1c, 0x2a,  -1  },
+    { 0x44, 0x2c, 0x2d, 0x0c, 0x39, 0x33,  -1 , 0x48,  -1 ,  -1 , 0x3d },
+    { 0x37, 0x38,  -1 , 0x45, 0x57, 0x58, 0x4b, 0x50, 0x4d,  -1 ,  -1  },
+    { 0x52, 0x43, 0x01, 0x47, 0x49,  -1 ,  -1 ,  -1 ,  -1 ,  -1 ,  -1  },
+};
+
+#define SPITZ_GPIO_AK_INT	13	/* Remote control */
+#define SPITZ_GPIO_SYNC		16	/* Sync button */
+#define SPITZ_GPIO_ON_KEY	95	/* Power button */
+#define SPITZ_GPIO_SWA		97	/* Lid */
+#define SPITZ_GPIO_SWB		96	/* Tablet mode */
+
+/* The special buttons are mapped to unused keys */
+static const int spitz_gpiomap[5] = {
+    SPITZ_GPIO_AK_INT, SPITZ_GPIO_SYNC, SPITZ_GPIO_ON_KEY,
+    SPITZ_GPIO_SWA, SPITZ_GPIO_SWB,
+};
+static int spitz_gpio_invert[5] = { 0, 0, 0, 0, 0, };
+
+struct spitz_keyboard_s {
+    struct pxa2xx_state_s *cpu;
+    int keymap[0x80];
+    uint16_t keyrow[SPITZ_KEY_SENSE_NUM];
+    uint16_t strobe_state;
+    uint16_t sense_state;
+
+    uint16_t pre_map[0x100];
+    uint16_t modifiers;
+    uint16_t imodifiers;
+    uint8_t fifo[16];
+    int fifopos, fifolen;
+    QEMUTimer *kbdtimer;
+};
+
+static void spitz_keyboard_sense_update(struct spitz_keyboard_s *s)
+{
+    int i;
+    uint16_t strobe, sense = 0;
+    for (i = 0; i < SPITZ_KEY_SENSE_NUM; i ++) {
+        strobe = s->keyrow[i] & s->strobe_state;
+        if (strobe) {
+            sense |= 1 << i;
+            if (!(s->sense_state & (1 << i)))
+                pxa2xx_gpio_set(s->cpu->gpio, spitz_gpio_key_sense[i], 1);
+        } else if (s->sense_state & (1 << i))
+            pxa2xx_gpio_set(s->cpu->gpio, spitz_gpio_key_sense[i], 0);
+    }
+
+    s->sense_state = sense;
+}
+
+static void spitz_keyboard_strobe(int line, int level,
+                struct spitz_keyboard_s *s)
+{
+    int i;
+    for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
+        if (spitz_gpio_key_strobe[i] == line) {
+            if (level)
+                s->strobe_state |= 1 << i;
+            else
+                s->strobe_state &= ~(1 << i);
+
+            spitz_keyboard_sense_update(s);
+            break;
+        }
+}
+
+static void spitz_keyboard_keydown(struct spitz_keyboard_s *s, int keycode)
+{
+    int spitz_keycode = s->keymap[keycode & 0x7f];
+    if (spitz_keycode == -1)
+        return;
+
+    /* Handle the additional keys */
+    if ((spitz_keycode >> 4) == SPITZ_KEY_SENSE_NUM) {
+        pxa2xx_gpio_set(s->cpu->gpio, spitz_gpiomap[spitz_keycode & 0xf],
+                        (keycode < 0x80) ^
+                        spitz_gpio_invert[spitz_keycode & 0xf]);
+        return;
+    }
+
+    if (keycode & 0x80)
+        s->keyrow[spitz_keycode >> 4] &= ~(1 << (spitz_keycode & 0xf));
+    else
+        s->keyrow[spitz_keycode >> 4] |= 1 << (spitz_keycode & 0xf);
+
+    spitz_keyboard_sense_update(s);
+}
+
+#define SHIFT	(1 << 7)
+#define CTRL	(1 << 8)
+#define FN	(1 << 9)
+
+#define QUEUE_KEY(c)	s->fifo[(s->fifopos + s->fifolen ++) & 0xf] = c
+
+static void spitz_keyboard_handler(struct spitz_keyboard_s *s, int keycode)
+{
+    uint16_t code;
+    int mapcode;
+    switch (keycode) {
+    case 0x2a:	/* Left Shift */
+        s->modifiers |= 1;
+        break;
+    case 0xaa:
+        s->modifiers &= ~1;
+        break;
+    case 0x36:	/* Right Shift */
+        s->modifiers |= 2;
+        break;
+    case 0xb6:
+        s->modifiers &= ~2;
+        break;
+    case 0x1d:	/* Control */
+        s->modifiers |= 4;
+        break;
+    case 0x9d:
+        s->modifiers &= ~4;
+        break;
+    case 0x38:	/* Alt */
+        s->modifiers |= 8;
+        break;
+    case 0xb8:
+        s->modifiers &= ~8;
+        break;
+    }
+
+    code = s->pre_map[mapcode = ((s->modifiers & 3) ?
+            (keycode | SHIFT) :
+            (keycode & ~SHIFT))];
+
+    if (code != mapcode) {
+#if 0
+        if ((code & SHIFT) && !(s->modifiers & 1))
+            QUEUE_KEY(0x2a | (keycode & 0x80));
+        if ((code & CTRL ) && !(s->modifiers & 4))
+            QUEUE_KEY(0x1d | (keycode & 0x80));
+        if ((code & FN   ) && !(s->modifiers & 8))
+            QUEUE_KEY(0x38 | (keycode & 0x80));
+        if ((code & FN   ) && (s->modifiers & 1))
+            QUEUE_KEY(0x2a | (~keycode & 0x80));
+        if ((code & FN   ) && (s->modifiers & 2))
+            QUEUE_KEY(0x36 | (~keycode & 0x80));
+#else
+        if (keycode & 0x80) {
+            if ((s->imodifiers & 1   ) && !(s->modifiers & 1))
+                QUEUE_KEY(0x2a | 0x80);
+            if ((s->imodifiers & 4   ) && !(s->modifiers & 4))
+                QUEUE_KEY(0x1d | 0x80);
+            if ((s->imodifiers & 8   ) && !(s->modifiers & 8))
+                QUEUE_KEY(0x38 | 0x80);
+            if ((s->imodifiers & 0x10) && (s->modifiers & 1))
+                QUEUE_KEY(0x2a);
+            if ((s->imodifiers & 0x20) && (s->modifiers & 2))
+                QUEUE_KEY(0x36);
+            s->imodifiers = 0;
+        } else {
+            if ((code & SHIFT) && !((s->modifiers | s->imodifiers) & 1)) {
+                QUEUE_KEY(0x2a);
+                s->imodifiers |= 1;
+            }
+            if ((code & CTRL ) && !((s->modifiers | s->imodifiers) & 4)) {
+                QUEUE_KEY(0x1d);
+                s->imodifiers |= 4;
+            }
+            if ((code & FN   ) && !((s->modifiers | s->imodifiers) & 8)) {
+                QUEUE_KEY(0x38);
+                s->imodifiers |= 8;
+            }
+            if ((code & FN   ) && (s->modifiers & 1) &&
+                            !(s->imodifiers & 0x10)) {
+                QUEUE_KEY(0x2a | 0x80);
+                s->imodifiers |= 0x10;
+            }
+            if ((code & FN   ) && (s->modifiers & 2) &&
+                            !(s->imodifiers & 0x20)) {
+                QUEUE_KEY(0x36 | 0x80);
+                s->imodifiers |= 0x20;
+            }
+        }
+#endif
+    }
+
+    QUEUE_KEY((code & 0x7f) | (keycode & 0x80));
+}
+
+static void spitz_keyboard_tick(void *opaque)
+{
+    struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque;
+
+    if (s->fifolen) {
+        spitz_keyboard_keydown(s, s->fifo[s->fifopos ++]);
+        s->fifolen --;
+        if (s->fifopos >= 16)
+            s->fifopos = 0;
+    }
+
+    qemu_mod_timer(s->kbdtimer, qemu_get_clock(vm_clock) + ticks_per_sec / 32);
+}
+
+static void spitz_keyboard_pre_map(struct spitz_keyboard_s *s)
+{
+    int i;
+    for (i = 0; i < 0x100; i ++)
+        s->pre_map[i] = i;
+    s->pre_map[0x02 | SHIFT	] = 0x02 | SHIFT;	/* exclam */
+    s->pre_map[0x28 | SHIFT	] = 0x03 | SHIFT;	/* quotedbl */
+    s->pre_map[0x04 | SHIFT	] = 0x04 | SHIFT;	/* numbersign */
+    s->pre_map[0x05 | SHIFT	] = 0x05 | SHIFT;	/* dollar */
+    s->pre_map[0x06 | SHIFT	] = 0x06 | SHIFT;	/* percent */
+    s->pre_map[0x08 | SHIFT	] = 0x07 | SHIFT;	/* ampersand */
+    s->pre_map[0x28		] = 0x08 | SHIFT;	/* apostrophe */
+    s->pre_map[0x0a | SHIFT	] = 0x09 | SHIFT;	/* parenleft */
+    s->pre_map[0x0b | SHIFT	] = 0x0a | SHIFT;	/* parenright */
+    s->pre_map[0x29 | SHIFT	] = 0x0b | SHIFT;	/* asciitilde */
+    s->pre_map[0x03 | SHIFT	] = 0x0c | SHIFT;	/* at */
+    s->pre_map[0xd3		] = 0x0e | FN;		/* Delete */
+    s->pre_map[0x3a		] = 0x0f | FN;		/* Caps_Lock */
+    s->pre_map[0x07 | SHIFT	] = 0x11 | FN;		/* asciicircum */
+    s->pre_map[0x0d		] = 0x12 | FN;		/* equal */
+    s->pre_map[0x0d | SHIFT	] = 0x13 | FN;		/* plus */
+    s->pre_map[0x1a		] = 0x14 | FN;		/* bracketleft */
+    s->pre_map[0x1b		] = 0x15 | FN;		/* bracketright */
+    s->pre_map[0x27		] = 0x22 | FN;		/* semicolon */
+    s->pre_map[0x27 | SHIFT	] = 0x23 | FN;		/* colon */
+    s->pre_map[0x09 | SHIFT	] = 0x24 | FN;		/* asterisk */
+    s->pre_map[0x2b		] = 0x25 | FN;		/* backslash */
+    s->pre_map[0x2b | SHIFT	] = 0x26 | FN;		/* bar */
+    s->pre_map[0x0c | SHIFT	] = 0x30 | FN;		/* underscore */
+    s->pre_map[0x35		] = 0x33 | SHIFT;	/* slash */
+    s->pre_map[0x35 | SHIFT	] = 0x34 | SHIFT;	/* question */
+    s->pre_map[0x49		] = 0x48 | FN;		/* Page_Up */
+    s->pre_map[0x51		] = 0x50 | FN;		/* Page_Down */
+
+    s->modifiers = 0;
+    s->imodifiers = 0;
+    s->fifopos = 0;
+    s->fifolen = 0;
+    s->kbdtimer = qemu_new_timer(vm_clock, spitz_keyboard_tick, s);
+    spitz_keyboard_tick(s);
+}
+
+#undef SHIFT
+#undef CTRL
+#undef FN
+
+static void spitz_keyboard_save(QEMUFile *f, void *opaque)
+{
+    struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque;
+    int i;
+
+    qemu_put_be16s(f, &s->sense_state);
+    qemu_put_be16s(f, &s->strobe_state);
+    for (i = 0; i < 5; i ++)
+        qemu_put_byte(f, spitz_gpio_invert[i]);
+}
+
+static int spitz_keyboard_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct spitz_keyboard_s *s = (struct spitz_keyboard_s *) opaque;
+    int i;
+
+    qemu_get_be16s(f, &s->sense_state);
+    qemu_get_be16s(f, &s->strobe_state);
+    for (i = 0; i < 5; i ++)
+        spitz_gpio_invert[i] = qemu_get_byte(f);
+
+    /* Release all pressed keys */
+    memset(s->keyrow, 0, sizeof(s->keyrow));
+    spitz_keyboard_sense_update(s);
+    s->modifiers = 0;
+    s->imodifiers = 0;
+    s->fifopos = 0;
+    s->fifolen = 0;
+
+    return 0;
+}
+
+static void spitz_keyboard_register(struct pxa2xx_state_s *cpu)
+{
+    int i, j;
+    struct spitz_keyboard_s *s;
+
+    s = (struct spitz_keyboard_s *)
+            qemu_mallocz(sizeof(struct spitz_keyboard_s));
+    memset(s, 0, sizeof(struct spitz_keyboard_s));
+    s->cpu = cpu;
+
+    for (i = 0; i < 0x80; i ++)
+        s->keymap[i] = -1;
+    for (i = 0; i < SPITZ_KEY_SENSE_NUM + 1; i ++)
+        for (j = 0; j < SPITZ_KEY_STROBE_NUM; j ++)
+            if (spitz_keymap[i][j] != -1)
+                s->keymap[spitz_keymap[i][j]] = (i << 4) | j;
+
+    for (i = 0; i < SPITZ_KEY_STROBE_NUM; i ++)
+        pxa2xx_gpio_handler_set(cpu->gpio, spitz_gpio_key_strobe[i],
+                        (gpio_handler_t) spitz_keyboard_strobe, s);
+
+    spitz_keyboard_pre_map(s);
+    qemu_add_kbd_event_handler((QEMUPutKBDEvent *) spitz_keyboard_handler, s);
+
+    register_savevm("spitz_keyboard", 0, 0,
+                    spitz_keyboard_save, spitz_keyboard_load, s);
+}
+
+/* SCOOP devices */
+
+struct scoop_info_s {
+    target_phys_addr_t target_base;
+    uint16_t status;
+    uint16_t power;
+    uint32_t gpio_level;
+    uint32_t gpio_dir;
+    uint32_t prev_level;
+    struct {
+        gpio_handler_t fn;
+        void *opaque;
+    } handler[16];
+
+    uint16_t mcr;
+    uint16_t cdr;
+    uint16_t ccr;
+    uint16_t irr;
+    uint16_t imr;
+    uint16_t isr;
+    uint16_t gprr;
+};
+
+#define SCOOP_MCR	0x00
+#define SCOOP_CDR	0x04
+#define SCOOP_CSR	0x08
+#define SCOOP_CPR	0x0c
+#define SCOOP_CCR	0x10
+#define SCOOP_IRR_IRM	0x14
+#define SCOOP_IMR	0x18
+#define SCOOP_ISR	0x1c
+#define SCOOP_GPCR	0x20
+#define SCOOP_GPWR	0x24
+#define SCOOP_GPRR	0x28
+
+static inline void scoop_gpio_handler_update(struct scoop_info_s *s) {
+    uint32_t level, diff;
+    int bit;
+    level = s->gpio_level & s->gpio_dir;
+
+    for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) {
+        bit = ffs(diff) - 1;
+        if (s->handler[bit].fn)
+            s->handler[bit].fn(bit, (level >> bit) & 1,
+                            s->handler[bit].opaque);
+    }
+
+    s->prev_level = level;
+}
+
+static uint32_t scoop_readb(void *opaque, target_phys_addr_t addr)
+{
+    struct scoop_info_s *s = (struct scoop_info_s *) opaque;
+    addr -= s->target_base;
+
+    switch (addr) {
+    case SCOOP_MCR:
+        return s->mcr;
+    case SCOOP_CDR:
+        return s->cdr;
+    case SCOOP_CSR:
+        return s->status;
+    case SCOOP_CPR:
+        return s->power;
+    case SCOOP_CCR:
+        return s->ccr;
+    case SCOOP_IRR_IRM:
+        return s->irr;
+    case SCOOP_IMR:
+        return s->imr;
+    case SCOOP_ISR:
+        return s->isr;
+    case SCOOP_GPCR:
+        return s->gpio_dir;
+    case SCOOP_GPWR:
+        return s->gpio_level;
+    case SCOOP_GPRR:
+        return s->gprr;
+    default:
+        spitz_printf("Bad register offset " REG_FMT "\n", addr);
+    }
+
+    return 0;
+}
+
+static void scoop_writeb(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    struct scoop_info_s *s = (struct scoop_info_s *) opaque;
+    addr -= s->target_base;
+    value &= 0xffff;
+
+    switch (addr) {
+    case SCOOP_MCR:
+        s->mcr = value;
+        break;
+    case SCOOP_CDR:
+        s->cdr = value;
+        break;
+    case SCOOP_CPR:
+        s->power = value;
+        if (value & 0x80)
+            s->power |= 0x8040;
+        break;
+    case SCOOP_CCR:
+        s->ccr = value;
+        break;
+    case SCOOP_IRR_IRM:
+        s->irr = value;
+        break;
+    case SCOOP_IMR:
+        s->imr = value;
+        break;
+    case SCOOP_ISR:
+        s->isr = value;
+        break;
+    case SCOOP_GPCR:
+        s->gpio_dir = value;
+        scoop_gpio_handler_update(s);
+        break;
+    case SCOOP_GPWR:
+        s->gpio_level = value & s->gpio_dir;
+        scoop_gpio_handler_update(s);
+        break;
+    case SCOOP_GPRR:
+        s->gprr = value;
+        break;
+    default:
+        spitz_printf("Bad register offset " REG_FMT "\n", addr);
+    }
+}
+
+CPUReadMemoryFunc *scoop_readfn[] = {
+    scoop_readb,
+    scoop_readb,
+    scoop_readb,
+};
+CPUWriteMemoryFunc *scoop_writefn[] = {
+    scoop_writeb,
+    scoop_writeb,
+    scoop_writeb,
+};
+
+static inline void scoop_gpio_set(struct scoop_info_s *s, int line, int level)
+{
+    if (line >= 16) {
+        spitz_printf("No GPIO pin %i\n", line);
+        return;
+    }
+
+    if (level)
+        s->gpio_level |= (1 << line);
+    else
+        s->gpio_level &= ~(1 << line);
+}
+
+static inline void scoop_gpio_handler_set(struct scoop_info_s *s, int line,
+                gpio_handler_t handler, void *opaque) {
+    if (line >= 16) {
+        spitz_printf("No GPIO pin %i\n", line);
+        return;
+    }
+
+    s->handler[line].fn = handler;
+    s->handler[line].opaque = opaque;
+}
+
+static void scoop_save(QEMUFile *f, void *opaque)
+{
+    struct scoop_info_s *s = (struct scoop_info_s *) opaque;
+    qemu_put_be16s(f, &s->status);
+    qemu_put_be16s(f, &s->power);
+    qemu_put_be32s(f, &s->gpio_level);
+    qemu_put_be32s(f, &s->gpio_dir);
+    qemu_put_be32s(f, &s->prev_level);
+    qemu_put_be16s(f, &s->mcr);
+    qemu_put_be16s(f, &s->cdr);
+    qemu_put_be16s(f, &s->ccr);
+    qemu_put_be16s(f, &s->irr);
+    qemu_put_be16s(f, &s->imr);
+    qemu_put_be16s(f, &s->isr);
+    qemu_put_be16s(f, &s->gprr);
+}
+
+static int scoop_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct scoop_info_s *s = (struct scoop_info_s *) opaque;
+    qemu_get_be16s(f, &s->status);
+    qemu_get_be16s(f, &s->power);
+    qemu_get_be32s(f, &s->gpio_level);
+    qemu_get_be32s(f, &s->gpio_dir);
+    qemu_get_be32s(f, &s->prev_level);
+    qemu_get_be16s(f, &s->mcr);
+    qemu_get_be16s(f, &s->cdr);
+    qemu_get_be16s(f, &s->ccr);
+    qemu_get_be16s(f, &s->irr);
+    qemu_get_be16s(f, &s->imr);
+    qemu_get_be16s(f, &s->isr);
+    qemu_get_be16s(f, &s->gprr);
+
+    return 0;
+}
+
+static struct scoop_info_s *spitz_scoop_init(struct pxa2xx_state_s *cpu,
+                int count) {
+    int iomemtype;
+    struct scoop_info_s *s;
+
+    s = (struct scoop_info_s *)
+            qemu_mallocz(sizeof(struct scoop_info_s) * 2);
+    memset(s, 0, sizeof(struct scoop_info_s) * count);
+    s[0].target_base = 0x10800000;
+    s[1].target_base = 0x08800040;
+
+    /* Ready */
+    s[0].status = 0x02;
+    s[1].status = 0x02;
+
+    iomemtype = cpu_register_io_memory(0, scoop_readfn,
+                    scoop_writefn, &s[0]);
+    cpu_register_physical_memory(s[0].target_base, 0x1000, iomemtype);
+    register_savevm("scoop", 0, 0, scoop_save, scoop_load, &s[0]);
+
+    if (count < 2)
+        return s;
+
+    iomemtype = cpu_register_io_memory(0, scoop_readfn,
+                    scoop_writefn, &s[1]);
+    cpu_register_physical_memory(s[1].target_base, 0x1000, iomemtype);
+    register_savevm("scoop", 1, 0, scoop_save, scoop_load, &s[1]);
+
+    return s;
+}
+
+/* LCD backlight controller */
+
+#define LCDTG_RESCTL	0x00
+#define LCDTG_PHACTRL	0x01
+#define LCDTG_DUTYCTRL	0x02
+#define LCDTG_POWERREG0	0x03
+#define LCDTG_POWERREG1	0x04
+#define LCDTG_GPOR3	0x05
+#define LCDTG_PICTRL	0x06
+#define LCDTG_POLCTRL	0x07
+
+static int bl_intensity, bl_power;
+
+static void spitz_bl_update(struct pxa2xx_state_s *s)
+{
+    if (bl_power && bl_intensity)
+        spitz_printf("LCD Backlight now at %i/63\n", bl_intensity);
+    else
+        spitz_printf("LCD Backlight now off\n");
+}
+
+static void spitz_bl_bit5(int line, int level, void *opaque)
+{
+    int prev = bl_intensity;
+
+    if (level)
+        bl_intensity &= ~0x20;
+    else
+        bl_intensity |= 0x20;
+
+    if (bl_power && prev != bl_intensity)
+        spitz_bl_update((struct pxa2xx_state_s *) opaque);
+}
+
+static void spitz_bl_power(int line, int level, void *opaque)
+{
+    bl_power = !!level;
+    spitz_bl_update((struct pxa2xx_state_s *) opaque);
+}
+
+static void spitz_lcdtg_dac_put(void *opaque, uint8_t cmd)
+{
+    int addr, value;
+    addr = cmd >> 5;
+    value = cmd & 0x1f;
+
+    switch (addr) {
+    case LCDTG_RESCTL:
+        if (value)
+            spitz_printf("LCD in QVGA mode\n");
+        else
+            spitz_printf("LCD in VGA mode\n");
+        break;
+
+    case LCDTG_DUTYCTRL:
+        bl_intensity &= ~0x1f;
+        bl_intensity |= value;
+        if (bl_power)
+            spitz_bl_update((struct pxa2xx_state_s *) opaque);
+        break;
+
+    case LCDTG_POWERREG0:
+        /* Set common voltage to M62332FP */
+        break;
+    }
+}
+
+/* SSP devices */
+
+#define CORGI_SSP_PORT		2
+
+#define SPITZ_GPIO_LCDCON_CS	53
+#define SPITZ_GPIO_ADS7846_CS	14
+#define SPITZ_GPIO_MAX1111_CS	20
+#define SPITZ_GPIO_TP_INT	11
+
+static int lcd_en, ads_en, max_en;
+static struct max111x_s *max1111;
+static struct ads7846_state_s *ads7846;
+
+/* "Demux" the signal based on current chipselect */
+static uint32_t corgi_ssp_read(void *opaque)
+{
+    if (lcd_en)
+        return 0;
+    if (ads_en)
+        return ads7846_read(ads7846);
+    if (max_en)
+        return max111x_read(max1111);
+    return 0;
+}
+
+static void corgi_ssp_write(void *opaque, uint32_t value)
+{
+    if (lcd_en)
+        spitz_lcdtg_dac_put(opaque, value);
+    if (ads_en)
+        ads7846_write(ads7846, value);
+    if (max_en)
+        max111x_write(max1111, value);
+}
+
+static void corgi_ssp_gpio_cs(int line, int level, struct pxa2xx_state_s *s)
+{
+    if (line == SPITZ_GPIO_LCDCON_CS)
+        lcd_en = !level;
+    else if (line == SPITZ_GPIO_ADS7846_CS)
+        ads_en = !level;
+    else if (line == SPITZ_GPIO_MAX1111_CS)
+        max_en = !level;
+}
+
+#define MAX1111_BATT_VOLT	1
+#define MAX1111_BATT_TEMP	2
+#define MAX1111_ACIN_VOLT	3
+
+#define SPITZ_BATTERY_TEMP	0xe0	/* About 2.9V */
+#define SPITZ_BATTERY_VOLT	0xd0	/* About 4.0V */
+#define SPITZ_CHARGEON_ACIN	0x80	/* About 5.0V */
+
+static void spitz_adc_temp_on(int line, int level, void *opaque)
+{
+    if (!max1111)
+        return;
+
+    if (level)
+        max111x_set_input(max1111, MAX1111_BATT_TEMP, SPITZ_BATTERY_TEMP);
+    else
+        max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
+}
+
+static void spitz_pendown_set(void *opaque, int line, int level)
+{
+    struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque;
+    pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_TP_INT, level);
+}
+
+static void spitz_ssp_save(QEMUFile *f, void *opaque)
+{
+    qemu_put_be32(f, lcd_en);
+    qemu_put_be32(f, ads_en);
+    qemu_put_be32(f, max_en);
+    qemu_put_be32(f, bl_intensity);
+    qemu_put_be32(f, bl_power);
+}
+
+static int spitz_ssp_load(QEMUFile *f, void *opaque, int version_id)
+{
+    lcd_en = qemu_get_be32(f);
+    ads_en = qemu_get_be32(f);
+    max_en = qemu_get_be32(f);
+    bl_intensity = qemu_get_be32(f);
+    bl_power = qemu_get_be32(f);
+
+    return 0;
+}
+
+static void spitz_ssp_attach(struct pxa2xx_state_s *cpu)
+{
+    lcd_en = ads_en = max_en = 0;
+
+    ads7846 = ads7846_init(qemu_allocate_irqs(spitz_pendown_set, cpu, 1)[0]);
+
+    max1111 = max1111_init(0);
+    max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT);
+    max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
+    max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
+
+    pxa2xx_ssp_attach(cpu->ssp[CORGI_SSP_PORT - 1], corgi_ssp_read,
+                    corgi_ssp_write, cpu);
+
+    pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_LCDCON_CS,
+                    (gpio_handler_t) corgi_ssp_gpio_cs, cpu);
+    pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_ADS7846_CS,
+                    (gpio_handler_t) corgi_ssp_gpio_cs, cpu);
+    pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_MAX1111_CS,
+                    (gpio_handler_t) corgi_ssp_gpio_cs, cpu);
+
+    bl_intensity = 0x20;
+    bl_power = 0;
+
+    register_savevm("spitz_ssp", 0, 0, spitz_ssp_save, spitz_ssp_load, cpu);
+}
+
+/* CF Microdrive */
+
+static void spitz_microdrive_attach(struct pxa2xx_state_s *cpu)
+{
+    struct pcmcia_card_s *md;
+    BlockDriverState *bs = bs_table[0];
+
+    if (bs && bdrv_is_inserted(bs) && !bdrv_is_removable(bs)) {
+        md = dscm1xxxx_init(bs);
+        pxa2xx_pcmcia_attach(cpu->pcmcia[1], md);
+    }
+}
+
+/* Wm8750 and Max7310 on I2C */
+
+#define AKITA_MAX_ADDR	0x18
+#define SPITZ_WM_ADDRL	0x1b
+#define SPITZ_WM_ADDRH	0x1a
+
+#define SPITZ_GPIO_WM	5
+
+#ifdef HAS_AUDIO
+static void spitz_wm8750_addr(int line, int level, void *opaque)
+{
+    i2c_slave *wm = (i2c_slave *) opaque;
+    if (level)
+        i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
+    else
+        i2c_set_slave_address(wm, SPITZ_WM_ADDRL);
+}
+#endif
+
+static void spitz_i2c_setup(struct pxa2xx_state_s *cpu)
+{
+    /* Attach the CPU on one end of our I2C bus.  */
+    i2c_bus *bus = pxa2xx_i2c_bus(cpu->i2c[0]);
+
+#ifdef HAS_AUDIO
+    AudioState *audio;
+    i2c_slave *wm;
+
+    audio = AUD_init();
+    if (!audio)
+        return;
+    /* Attach a WM8750 to the bus */
+    wm = wm8750_init(bus, audio);
+
+    spitz_wm8750_addr(0, 0, wm);
+    pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_WM, spitz_wm8750_addr, wm);
+    /* .. and to the sound interface.  */
+    cpu->i2s->opaque = wm;
+    cpu->i2s->codec_out = wm8750_dac_dat;
+    cpu->i2s->codec_in = wm8750_adc_dat;
+    wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
+#endif
+}
+
+static void spitz_akita_i2c_setup(struct pxa2xx_state_s *cpu)
+{
+    /* Attach a Max7310 to Akita I2C bus.  */
+    i2c_set_slave_address(max7310_init(pxa2xx_i2c_bus(cpu->i2c[0])),
+                    AKITA_MAX_ADDR);
+}
+
+/* Other peripherals */
+
+static void spitz_charge_switch(int line, int level, void *opaque)
+{
+    spitz_printf("Charging %s.\n", level ? "off" : "on");
+}
+
+static void spitz_discharge_switch(int line, int level, void *opaque)
+{
+    spitz_printf("Discharging %s.\n", level ? "on" : "off");
+}
+
+static void spitz_greenled_switch(int line, int level, void *opaque)
+{
+    spitz_printf("Green LED %s.\n", level ? "on" : "off");
+}
+
+static void spitz_orangeled_switch(int line, int level, void *opaque)
+{
+    spitz_printf("Orange LED %s.\n", level ? "on" : "off");
+}
+
+#define SPITZ_SCP_LED_GREEN		1
+#define SPITZ_SCP_JK_B			2
+#define SPITZ_SCP_CHRG_ON		3
+#define SPITZ_SCP_MUTE_L		4
+#define SPITZ_SCP_MUTE_R		5
+#define SPITZ_SCP_CF_POWER		6
+#define SPITZ_SCP_LED_ORANGE		7
+#define SPITZ_SCP_JK_A			8
+#define SPITZ_SCP_ADC_TEMP_ON		9
+#define SPITZ_SCP2_IR_ON		1
+#define SPITZ_SCP2_AKIN_PULLUP		2
+#define SPITZ_SCP2_BACKLIGHT_CONT	7
+#define SPITZ_SCP2_BACKLIGHT_ON		8
+#define SPITZ_SCP2_MIC_BIAS		9
+
+static void spitz_scoop_gpio_setup(struct pxa2xx_state_s *cpu,
+                struct scoop_info_s *scp, int num)
+{
+    scoop_gpio_handler_set(&scp[0], SPITZ_SCP_CHRG_ON,
+                    spitz_charge_switch, cpu);
+    scoop_gpio_handler_set(&scp[0], SPITZ_SCP_JK_B,
+                    spitz_discharge_switch, cpu);
+    scoop_gpio_handler_set(&scp[0], SPITZ_SCP_LED_GREEN,
+                    spitz_greenled_switch, cpu);
+    scoop_gpio_handler_set(&scp[0], SPITZ_SCP_LED_ORANGE,
+                    spitz_orangeled_switch, cpu);
+
+    if (num >= 2) {
+        scoop_gpio_handler_set(&scp[1], SPITZ_SCP2_BACKLIGHT_CONT,
+                        spitz_bl_bit5, cpu);
+        scoop_gpio_handler_set(&scp[1], SPITZ_SCP2_BACKLIGHT_ON,
+                        spitz_bl_power, cpu);
+    }
+
+    scoop_gpio_handler_set(&scp[0], SPITZ_SCP_ADC_TEMP_ON,
+                    spitz_adc_temp_on, cpu);
+}
+
+#define SPITZ_GPIO_HSYNC		22
+#define SPITZ_GPIO_SD_DETECT		9
+#define SPITZ_GPIO_SD_WP		81
+#define SPITZ_GPIO_ON_RESET		89
+#define SPITZ_GPIO_BAT_COVER		90
+#define SPITZ_GPIO_CF1_IRQ		105
+#define SPITZ_GPIO_CF1_CD		94
+#define SPITZ_GPIO_CF2_IRQ		106
+#define SPITZ_GPIO_CF2_CD		93
+
+int spitz_hsync;
+
+static void spitz_lcd_hsync_handler(void *opaque)
+{
+    struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque;
+    pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_HSYNC, spitz_hsync);
+    spitz_hsync ^= 1;
+}
+
+static void spitz_mmc_coverswitch_change(void *opaque, int in)
+{
+    struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque;
+    pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SD_DETECT, in);
+}
+
+static void spitz_mmc_writeprotect_change(void *opaque, int wp)
+{
+    struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque;
+    pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SD_WP, wp);
+}
+
+static void spitz_pcmcia_cb(void *opaque, int line, int level)
+{
+    struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque;
+    static const int gpio_map[] = {
+        SPITZ_GPIO_CF1_IRQ, SPITZ_GPIO_CF1_CD,
+        SPITZ_GPIO_CF2_IRQ, SPITZ_GPIO_CF2_CD,
+    };
+    pxa2xx_gpio_set(cpu->gpio, gpio_map[line], level);
+}
+
+static void spitz_gpio_setup(struct pxa2xx_state_s *cpu, int slots)
+{
+    qemu_irq *pcmcia_cb;
+    /*
+     * Bad hack: We toggle the LCD hsync GPIO on every GPIO status
+     * read to satisfy broken guests that poll-wait for hsync.
+     * Simulating a real hsync event would be less practical and
+     * wouldn't guarantee that a guest ever exits the loop.
+     */
+    spitz_hsync = 0;
+    pxa2xx_gpio_read_notifier(cpu->gpio, spitz_lcd_hsync_handler, cpu);
+    pxa2xx_lcd_vsync_cb(cpu->lcd, spitz_lcd_hsync_handler, cpu);
+
+    /* MMC/SD host */
+    pxa2xx_mmci_handlers(cpu->mmc, cpu, spitz_mmc_writeprotect_change,
+                    spitz_mmc_coverswitch_change);
+
+    /* Battery lock always closed */
+    pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_BAT_COVER, 1);
+
+    /* Handle reset */
+    pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_ON_RESET, pxa2xx_reset, cpu);
+
+    /* PCMCIA signals: card's IRQ and Card-Detect */
+    pcmcia_cb = qemu_allocate_irqs(spitz_pcmcia_cb, cpu, slots * 2);
+    if (slots >= 1)
+        pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], pcmcia_cb[0], pcmcia_cb[1]);
+    if (slots >= 2)
+        pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], pcmcia_cb[2], pcmcia_cb[3]);
+
+    /* Initialise the screen rotation related signals */
+    spitz_gpio_invert[3] = 0;	/* Always open */
+    if (graphic_rotate) {	/* Tablet mode */
+        spitz_gpio_invert[4] = 0;
+    } else {			/* Portrait mode */
+        spitz_gpio_invert[4] = 1;
+    }
+    pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SWA, spitz_gpio_invert[3]);
+    pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SWB, spitz_gpio_invert[4]);
+}
+
+/* Write the bootloader parameters memory area.  */
+
+#define MAGIC_CHG(a, b, c, d)	((d << 24) | (c << 16) | (b << 8) | a)
+
+struct __attribute__ ((__packed__)) sl_param_info {
+    uint32_t comadj_keyword;
+    int32_t comadj;
+
+    uint32_t uuid_keyword;
+    char uuid[16];
+
+    uint32_t touch_keyword;
+    int32_t touch_xp;
+    int32_t touch_yp;
+    int32_t touch_xd;
+    int32_t touch_yd;
+
+    uint32_t adadj_keyword;
+    int32_t adadj;
+
+    uint32_t phad_keyword;
+    int32_t phadadj;
+} spitz_bootparam = {
+    .comadj_keyword	= MAGIC_CHG('C', 'M', 'A', 'D'),
+    .comadj		= 125,
+    .uuid_keyword	= MAGIC_CHG('U', 'U', 'I', 'D'),
+    .uuid		= { -1 },
+    .touch_keyword	= MAGIC_CHG('T', 'U', 'C', 'H'),
+    .touch_xp		= -1,
+    .adadj_keyword	= MAGIC_CHG('B', 'V', 'A', 'D'),
+    .adadj		= -1,
+    .phad_keyword	= MAGIC_CHG('P', 'H', 'A', 'D'),
+    .phadadj		= 0x01,
+};
+
+static void sl_bootparam_write(uint32_t ptr)
+{
+    memcpy(phys_ram_base + ptr, &spitz_bootparam,
+                    sizeof(struct sl_param_info));
+}
+
+#define SL_PXA_PARAM_BASE	0xa0000a00
+
+/* Board init.  */
+enum spitz_model_e { spitz, akita, borzoi, terrier };
+
+static void spitz_common_init(int ram_size, int vga_ram_size,
+                DisplayState *ds, const char *kernel_filename,
+                const char *kernel_cmdline, const char *initrd_filename,
+                const char *cpu_model, enum spitz_model_e model, int arm_id)
+{
+    uint32_t spitz_ram = 0x04000000;
+    uint32_t spitz_rom = 0x00800000;
+    struct pxa2xx_state_s *cpu;
+    struct scoop_info_s *scp;
+
+    if (!cpu_model)
+        cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
+
+    /* Setup CPU & memory */
+    if (ram_size < spitz_ram + spitz_rom + PXA2XX_INTERNAL_SIZE) {
+        fprintf(stderr, "This platform requires %i bytes of memory\n",
+                        spitz_ram + spitz_rom + PXA2XX_INTERNAL_SIZE);
+        exit(1);
+    }
+    cpu = pxa270_init(spitz_ram, ds, cpu_model);
+
+    sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
+
+    cpu_register_physical_memory(0, spitz_rom,
+                    qemu_ram_alloc(spitz_rom) | IO_MEM_ROM);
+
+    /* Setup peripherals */
+    spitz_keyboard_register(cpu);
+
+    spitz_ssp_attach(cpu);
+
+    scp = spitz_scoop_init(cpu, (model == akita) ? 1 : 2);
+
+    spitz_scoop_gpio_setup(cpu, scp, (model == akita) ? 1 : 2);
+
+    spitz_gpio_setup(cpu, (model == akita) ? 1 : 2);
+
+    spitz_i2c_setup(cpu);
+
+    if (model == akita)
+        spitz_akita_i2c_setup(cpu);
+
+    if (model == terrier)
+        /* A 6.0 GB microdrive is permanently sitting in CF slot 1.  */
+        spitz_microdrive_attach(cpu);
+    else if (model != akita)
+        /* A 4.0 GB microdrive is permanently sitting in CF slot 1.  */
+        spitz_microdrive_attach(cpu);
+
+    /* Setup initial (reset) machine state */
+    cpu->env->regs[15] = PXA2XX_SDRAM_BASE;
+
+    arm_load_kernel(cpu->env, spitz_ram, kernel_filename, kernel_cmdline,
+                    initrd_filename, arm_id, PXA2XX_SDRAM_BASE);
+    sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE);
+}
+
+static void spitz_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)
+{
+    spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9);
+}
+
+static void borzoi_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)
+{
+    spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f);
+}
+
+static void akita_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)
+{
+    spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8);
+}
+
+static void terrier_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)
+{
+    spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename,
+                kernel_cmdline, initrd_filename, cpu_model, terrier, 0x33f);
+}
+
+QEMUMachine akitapda_machine = {
+    "akita",
+    "Akita PDA (PXA270)",
+    akita_init,
+};
+
+QEMUMachine spitzpda_machine = {
+    "spitz",
+    "Spitz PDA (PXA270)",
+    spitz_init,
+};
+
+QEMUMachine borzoipda_machine = {
+    "borzoi",
+    "Borzoi PDA (PXA270)",
+    borzoi_init,
+};
+
+QEMUMachine terrierpda_machine = {
+    "terrier",
+    "Terrier PDA (PXA270)",
+    terrier_init,
+};
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 9b6aae5..a76c53b 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Sun4m System Emulator
- * 
+ *
  * Copyright (c) 2003-2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -22,43 +22,55 @@
  * THE SOFTWARE.
  */
 #include "vl.h"
+//#define DEBUG_IRQ
+
+/*
+ * Sun4m architecture was used in the following machines:
+ *
+ * SPARCserver 6xxMP/xx
+ * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), SPARCclassic X (4/10)
+ * SPARCstation LX/ZX (4/30)
+ * SPARCstation Voyager
+ * SPARCstation 10/xx, SPARCserver 10/xx
+ * SPARCstation 5, SPARCserver 5
+ * SPARCstation 20/xx, SPARCserver 20
+ * SPARCstation 4
+ *
+ * See for example: http://www.sunhelp.org/faq/sunref1.html
+ */
+
+#ifdef DEBUG_IRQ
+#define DPRINTF(fmt, args...)                           \
+    do { printf("CPUIRQ: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
 
 #define KERNEL_LOAD_ADDR     0x00004000
 #define CMDLINE_ADDR         0x007ff000
 #define INITRD_LOAD_ADDR     0x00800000
 #define PROM_SIZE_MAX        (256 * 1024)
-#define PROM_ADDR	     0xffd00000
+#define PROM_PADDR           0xff0000000ULL
+#define PROM_VADDR           0xffd00000
 #define PROM_FILENAME	     "openbios-sparc32"
-#define PHYS_JJ_EEPROM	0x71200000	/* m48t08 */
-#define PHYS_JJ_IDPROM_OFF	0x1FD8
-#define PHYS_JJ_EEPROM_SIZE	0x2000
-// IRQs are not PIL ones, but master interrupt controller register
-// bits
-#define PHYS_JJ_IOMMU	0x10000000	/* I/O MMU */
-#define PHYS_JJ_TCX_FB	0x50000000	/* TCX frame buffer */
-#define PHYS_JJ_SLAVIO	0x70000000	/* Slavio base */
-#define PHYS_JJ_DMA     0x78400000      /* DMA controller */
-#define PHYS_JJ_ESP     0x78800000      /* ESP SCSI */
-#define PHYS_JJ_ESP_IRQ    18
-#define PHYS_JJ_LE      0x78C00000      /* Lance ethernet */
-#define PHYS_JJ_LE_IRQ     16
-#define PHYS_JJ_CLOCK	0x71D00000      /* Per-CPU timer/counter, L14 */
-#define PHYS_JJ_CLOCK_IRQ  7
-#define PHYS_JJ_CLOCK1	0x71D10000      /* System timer/counter, L10 */
-#define PHYS_JJ_CLOCK1_IRQ 19
-#define PHYS_JJ_INTR0	0x71E00000	/* Per-CPU interrupt control registers */
-#define PHYS_JJ_INTR_G	0x71E10000	/* Master interrupt control registers */
-#define PHYS_JJ_MS_KBD	0x71000000	/* Mouse and keyboard */
-#define PHYS_JJ_MS_KBD_IRQ    14
-#define PHYS_JJ_SER	0x71100000	/* Serial */
-#define PHYS_JJ_SER_IRQ    15
-#define PHYS_JJ_FDC	0x71400000	/* Floppy */
-#define PHYS_JJ_FLOPPY_IRQ 22
-#define PHYS_JJ_ME_IRQ 30		/* Module error, power fail */
-#define PHYS_JJ_CS      0x6c000000      /* Crystal CS4231 */
-#define PHYS_JJ_CS_IRQ  5
 
 #define MAX_CPUS 16
+#define MAX_PILS 16
+
+struct hwdef {
+    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
+    int intctl_g_intr, esp_irq, le_irq, clock_irq, clock1_irq;
+    int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq;
+    int machine_id; // For NVRAM
+    uint32_t intbit_to_level[32];
+};
 
 /* TSC handling */
 
@@ -115,17 +127,45 @@
     m48t59_write(nvram, addr + max - 1, '\0');
 }
 
-static m48t59_t *nvram;
+static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr,
+                                const unsigned char *str)
+{
+    uint32_t len;
+
+    len = strlen(str) + 1;
+    nvram_set_string(nvram, addr, str, len);
+
+    return addr + len;
+}
+
+static void nvram_finish_partition (m48t59_t *nvram, uint32_t start,
+                                    uint32_t end)
+{
+    unsigned int i, sum;
+
+    // Length divided by 16
+    m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff);
+    m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff);
+    // Checksum
+    sum = m48t59_read(nvram, start);
+    for (i = 0; i < 14; i++) {
+        sum += m48t59_read(nvram, start + 2 + i);
+        sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
+    }
+    m48t59_write(nvram, start + 1, sum & 0xff);
+}
 
 extern int nographic;
 
 static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline,
 		       int boot_device, uint32_t RAM_size,
 		       uint32_t kernel_size,
-		       int width, int height, int depth)
+		       int width, int height, int depth,
+                       int machine_id)
 {
     unsigned char tmp = 0;
-    int i, j;
+    unsigned int i, j;
+    uint32_t start, end;
 
     // Try to match PPC NVRAM
     nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
@@ -148,10 +188,32 @@
     nvram_set_word(nvram,   0x56, height);
     nvram_set_word(nvram,   0x58, depth);
 
+    // OpenBIOS nvram variables
+    // Variable partition
+    start = 252;
+    m48t59_write(nvram, start, 0x70);
+    nvram_set_string(nvram, start + 4, "system", 12);
+
+    end = start + 16;
+    for (i = 0; i < nb_prom_envs; i++)
+        end = nvram_set_var(nvram, end, prom_envs[i]);
+
+    m48t59_write(nvram, end++ , 0);
+    end = start + ((end - start + 15) & ~15);
+    nvram_finish_partition(nvram, start, end);
+
+    // free partition
+    start = end;
+    m48t59_write(nvram, start, 0x7f);
+    nvram_set_string(nvram, start + 4, "free", 12);
+
+    end = 0x1fd0;
+    nvram_finish_partition(nvram, start, end);
+
     // Sun4m specific use
-    i = 0x1fd8;
+    start = i = 0x1fd8;
     m48t59_write(nvram, i++, 0x01);
-    m48t59_write(nvram, i++, 0x80); /* Sun4m OBP */
+    m48t59_write(nvram, i++, machine_id);
     j = 0;
     m48t59_write(nvram, i++, macaddr[j++]);
     m48t59_write(nvram, i++, macaddr[j++]);
@@ -161,10 +223,10 @@
     m48t59_write(nvram, i, macaddr[j]);
 
     /* Calculate checksum */
-    for (i = 0x1fd8; i < 0x1fe7; i++) {
-	tmp ^= m48t59_read(nvram, i);
+    for (i = start; i < start + 15; i++) {
+        tmp ^= m48t59_read(nvram, i);
     }
-    m48t59_write(nvram, 0x1fe7, tmp);
+    m48t59_write(nvram, start + 15, tmp);
 }
 
 static void *slavio_intctl;
@@ -179,19 +241,46 @@
     slavio_irq_info(slavio_intctl);
 }
 
-void pic_set_irq(int irq, int level)
+void cpu_check_irqs(CPUState *env)
 {
-    slavio_pic_set_irq(slavio_intctl, irq, level);
+    if (env->pil_in && (env->interrupt_index == 0 ||
+                        (env->interrupt_index & ~15) == TT_EXTINT)) {
+        unsigned int i;
+
+        for (i = 15; i > 0; i--) {
+            if (env->pil_in & (1 << i)) {
+                int old_interrupt = env->interrupt_index;
+
+                env->interrupt_index = TT_EXTINT | i;
+                if (old_interrupt != env->interrupt_index)
+                    cpu_interrupt(env, CPU_INTERRUPT_HARD);
+                break;
+            }
+        }
+    } else if (!env->pil_in && (env->interrupt_index & ~15) == TT_EXTINT) {
+        env->interrupt_index = 0;
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
 }
 
-void pic_set_irq_new(void *opaque, int irq, int level)
+static void cpu_set_irq(void *opaque, int irq, int level)
 {
-    pic_set_irq(irq, level);
+    CPUState *env = opaque;
+
+    if (level) {
+        DPRINTF("Raise CPU IRQ %d\n", irq);
+        env->halted = 0;
+        env->pil_in |= 1 << irq;
+        cpu_check_irqs(env);
+    } else {
+        DPRINTF("Lower CPU IRQ %d\n", irq);
+        env->pil_in &= ~(1 << irq);
+        cpu_check_irqs(env);
+    }
 }
 
-void pic_set_irq_cpu(int irq, int level, unsigned int cpu)
+static void dummy_cpu_set_irq(void *opaque, int irq, int level)
 {
-    slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu);
 }
 
 static void *slavio_misc;
@@ -204,64 +293,109 @@
 static void main_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
+
     cpu_reset(env);
+    env->halted = 0;
 }
 
-/* Sun4m hardware initialisation */
-static void sun4m_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)
+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)
+
 {
     CPUState *env, *envs[MAX_CPUS];
-    char buf[1024];
-    int ret, linux_boot;
     unsigned int i;
-    long vram_size = 0x100000, prom_offset, initrd_size, kernel_size;
-    void *iommu, *dma, *main_esp, *main_lance = NULL;
-
-    linux_boot = (kernel_filename != NULL);
+    void *iommu, *espdma, *ledma, *main_esp, *nvram;
+    const sparc_def_t *def;
+    qemu_irq *cpu_irqs[MAX_CPUS], *slavio_irq, *slavio_cpu_irq,
+        *espdma_irq, *ledma_irq;
+    qemu_irq *esp_reset, *le_reset;
 
     /* init CPUs */
+    sparc_find_by_name(cpu_model, &def);
+    if (def == NULL) {
+        fprintf(stderr, "Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
+
     for(i = 0; i < smp_cpus; i++) {
         env = cpu_init();
+        cpu_sparc_register(env, def);
         envs[i] = env;
-        if (i != 0)
-            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(PHYS_JJ_IOMMU);
-    slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
-    for(i = 0; i < smp_cpus; i++) {
-        slavio_intctl_set_cpu(slavio_intctl, i, envs[i]);
-    }
-    dma = sparc32_dma_init(PHYS_JJ_DMA, PHYS_JJ_ESP_IRQ, PHYS_JJ_LE_IRQ, iommu, slavio_intctl);
-
-    tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height);
-    if (nd_table[0].vlan) {
-        if (nd_table[0].model == NULL
-            || strcmp(nd_table[0].model, "lance") == 0) {
-            main_lance = lance_init(&nd_table[0], PHYS_JJ_LE, dma);
+        if (i == 0) {
+            qemu_register_reset(main_cpu_reset, env);
         } else {
-            fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
-            exit (1);
+            qemu_register_reset(secondary_cpu_reset, env);
+            env->halted = 1;
         }
+        register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
+        cpu_irqs[i] = qemu_allocate_irqs(cpu_set_irq, envs[i], MAX_PILS);
     }
-    nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8);
+
+    for (i = smp_cpus; i < MAX_CPUS; i++)
+        cpu_irqs[i] = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, MAX_PILS);
+
+    /* 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 + 0x10000ULL,
+                                       &hwdef->intbit_to_level[0],
+                                       &slavio_irq, &slavio_cpu_irq,
+                                       cpu_irqs,
+                                       hwdef->clock_irq);
+
+    espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq],
+                              iommu, &espdma_irq, &esp_reset);
+
+    ledma = sparc32_dma_init(hwdef->dma_base + 16ULL,
+                             slavio_irq[hwdef->le_irq], iommu, &ledma_irq,
+                             &le_reset);
+
+    if (graphic_depth != 8 && graphic_depth != 24) {
+        fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+        exit (1);
+    }
+    tcx_init(ds, hwdef->tcx_base, phys_ram_base + RAM_size, RAM_size,
+             hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
+
+    if (nd_table[0].model == NULL
+        || strcmp(nd_table[0].model, "lance") == 0) {
+        lance_init(&nd_table[0], hwdef->le_base, ledma, *ledma_irq, le_reset);
+    } else if (strcmp(nd_table[0].model, "?") == 0) {
+        fprintf(stderr, "qemu: Supported NICs: lance\n");
+        exit (1);
+    } else {
+        fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
+        exit (1);
+    }
+
+    nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
+                        hwdef->nvram_size, 8);
     for (i = 0; i < MAX_CPUS; i++) {
-        slavio_timer_init(PHYS_JJ_CLOCK + i * TARGET_PAGE_SIZE, PHYS_JJ_CLOCK_IRQ, 0, i);
+        slavio_timer_init(hwdef->counter_base +
+                          (target_phys_addr_t)(i * TARGET_PAGE_SIZE),
+                           slavio_cpu_irq[i], 0);
     }
-    slavio_timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ, 2, (unsigned int)-1);
-    slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ);
+    slavio_timer_init(hwdef->counter_base + 0x10000ULL,
+                      slavio_irq[hwdef->clock1_irq], 2);
+    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
     // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
-    slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]);
-    fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
-    main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma);
+    slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq],
+                       serial_hds[1], serial_hds[0]);
+    fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table);
+
+    main_esp = esp_init(bs_table, hwdef->esp_base, espdma, *espdma_irq,
+                        esp_reset);
 
     for (i = 0; i < MAX_DISKS; i++) {
         if (bs_table[i]) {
@@ -269,32 +403,50 @@
         }
     }
 
-    slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ);
-    cs_init(PHYS_JJ_CS, PHYS_JJ_CS_IRQ, slavio_intctl);
-    sparc32_dma_set_reset_data(dma, main_esp, main_lance);
+    slavio_misc = slavio_misc_init(hwdef->slavio_base, hwdef->power_base,
+                                   slavio_irq[hwdef->me_irq]);
+    if (hwdef->cs_base != (target_phys_addr_t)-1)
+        cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl);
 
-    prom_offset = ram_size + vram_size;
-    cpu_register_physical_memory(PROM_ADDR, 
-                                 (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK, 
+    return nvram;
+}
+
+static void sun4m_load_kernel(long vram_size, int RAM_size, int boot_device,
+                              const char *kernel_filename,
+                              const char *kernel_cmdline,
+                              const char *initrd_filename,
+                              int machine_id,
+                              void *nvram)
+{
+    int ret, linux_boot;
+    char buf[1024];
+    unsigned int i;
+    long prom_offset, initrd_size, kernel_size;
+
+    linux_boot = (kernel_filename != NULL);
+
+    prom_offset = RAM_size + vram_size;
+    cpu_register_physical_memory(PROM_PADDR,
+                                 (PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK,
                                  prom_offset | IO_MEM_ROM);
 
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
-    ret = load_elf(buf, 0, NULL);
+    ret = load_elf(buf, PROM_PADDR - PROM_VADDR, NULL, NULL, NULL);
     if (ret < 0) {
-	fprintf(stderr, "qemu: could not load prom '%s'\n", 
+	fprintf(stderr, "qemu: could not load prom '%s'\n",
 		buf);
 	exit(1);
     }
 
     kernel_size = 0;
     if (linux_boot) {
-        kernel_size = load_elf(kernel_filename, -0xf0000000, NULL);
+        kernel_size = load_elf(kernel_filename, -0xf0000000, NULL, NULL, NULL);
         if (kernel_size < 0)
 	    kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
 	if (kernel_size < 0)
 	    kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
         if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
                     kernel_filename);
 	    exit(1);
         }
@@ -304,7 +456,7 @@
         if (initrd_filename) {
             initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
             if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                         initrd_filename);
                 exit(1);
             }
@@ -320,11 +472,134 @@
 	    }
         }
     }
-    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
+    nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+               boot_device, RAM_size, kernel_size, graphic_width,
+               graphic_height, graphic_depth, machine_id);
 }
 
-QEMUMachine sun4m_machine = {
-    "sun4m",
-    "Sun4m platform",
-    sun4m_init,
+static const struct hwdef hwdefs[] = {
+    /* SS-5 */
+    {
+        .iommu_base   = 0x10000000,
+        .tcx_base     = 0x50000000,
+        .cs_base      = 0x6c000000,
+        .slavio_base  = 0x70000000,
+        .ms_kb_base   = 0x71000000,
+        .serial_base  = 0x71100000,
+        .nvram_base   = 0x71200000,
+        .fd_base      = 0x71400000,
+        .counter_base = 0x71d00000,
+        .intctl_base  = 0x71e00000,
+        .dma_base     = 0x78400000,
+        .esp_base     = 0x78800000,
+        .le_base      = 0x78c00000,
+        .power_base   = 0x7a000000,
+        .vram_size    = 0x00100000,
+        .nvram_size   = 0x2000,
+        .esp_irq = 18,
+        .le_irq = 16,
+        .clock_irq = 7,
+        .clock1_irq = 19,
+        .ms_kb_irq = 14,
+        .ser_irq = 15,
+        .fd_irq = 22,
+        .me_irq = 30,
+        .cs_irq = 5,
+        .machine_id = 0x80,
+        .intbit_to_level = {
+            2, 3, 5, 7, 9, 11, 0, 14,	3, 5, 7, 9, 11, 13, 12, 12,
+            6, 0, 4, 10, 8, 0, 11, 0,	0, 0, 0, 0, 15, 0, 15, 0,
+        },
+    },
+    /* SS-10 */
+    {
+        .iommu_base   = 0xfe0000000ULL,
+        .tcx_base     = 0xe20000000ULL,
+        .cs_base      = -1,
+        .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,
+        .le_irq = 16,
+        .clock_irq = 7,
+        .clock1_irq = 19,
+        .ms_kb_irq = 14,
+        .ser_irq = 15,
+        .fd_irq = 22,
+        .me_irq = 30,
+        .cs_irq = -1,
+        .machine_id = 0x72,
+        .intbit_to_level = {
+            2, 3, 5, 7, 9, 11, 0, 14,	3, 5, 7, 9, 11, 13, 12, 12,
+            6, 0, 4, 10, 8, 0, 11, 0,	0, 0, 0, 0, 15, 0, 15, 0,
+        },
+    },
+};
+
+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, int max_ram)
+{
+    void *nvram;
+
+    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);
+    }
+    nvram = sun4m_hw_init(&hwdefs[machine], RAM_size, ds, cpu_model);
+
+    sun4m_load_kernel(hwdefs[machine].vram_size, RAM_size, boot_device,
+                      kernel_filename, kernel_cmdline, initrd_filename,
+                      hwdefs[machine].machine_id, nvram);
+}
+
+/* SPARCstation 5 hardware initialisation */
+static void ss5_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)
+{
+    if (cpu_model == NULL)
+        cpu_model = "Fujitsu MB86904";
+    sun4m_common_init(RAM_size, boot_device, ds, kernel_filename,
+                      kernel_cmdline, initrd_filename, cpu_model,
+                      0, 0x10000000);
+}
+
+/* SPARCstation 10 hardware initialisation */
+static void ss10_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)
+{
+    if (cpu_model == NULL)
+        cpu_model = "TI SuperSparc II";
+    sun4m_common_init(RAM_size, boot_device, ds, kernel_filename,
+                      kernel_cmdline, initrd_filename, cpu_model,
+                      1, 0xffffffff); // XXX actually first 62GB ok
+}
+
+QEMUMachine ss5_machine = {
+    "SS-5",
+    "Sun4m platform, SPARCstation 5",
+    ss5_init,
+};
+
+QEMUMachine ss10_machine = {
+    "SS-10",
+    "Sun4m platform, SPARCstation 10",
+    ss10_init,
 };
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 61069a6..0e9e72e 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Sun4u System Emulator
- * 
+ *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -29,6 +29,7 @@
 #define INITRD_LOAD_ADDR     0x00300000
 #define PROM_SIZE_MAX        (512 * 1024)
 #define PROM_ADDR	     0x1fff0000000ULL
+#define PROM_VADDR	     0x000ffd00000ULL
 #define APB_SPECIAL_BASE     0x1fe00000000ULL
 #define APB_MEM_BASE	     0x1ff00000000ULL
 #define VGA_BASE	     (APB_MEM_BASE + 0x400000ULL)
@@ -170,6 +171,34 @@
     return crc;
 }
 
+static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr,
+                                const unsigned char *str)
+{
+    uint32_t len;
+
+    len = strlen(str) + 1;
+    NVRAM_set_string(nvram, addr, str, len);
+
+    return addr + len;
+}
+
+static void nvram_finish_partition (m48t59_t *nvram, uint32_t start,
+                                    uint32_t end)
+{
+    unsigned int i, sum;
+
+    // Length divided by 16
+    m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff);
+    m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff);
+    // Checksum
+    sum = m48t59_read(nvram, start);
+    for (i = 0; i < 14; i++) {
+        sum += m48t59_read(nvram, start + 2 + i);
+        sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
+    }
+    m48t59_write(nvram, start + 1, sum & 0xff);
+}
+
 extern int nographic;
 
 int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
@@ -182,6 +211,8 @@
                           int width, int height, int depth)
 {
     uint16_t crc;
+    unsigned int i;
+    uint32_t start, end;
 
     /* Set parameters for Open Hack'Ware BIOS */
     NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
@@ -212,6 +243,28 @@
     crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
     NVRAM_set_word(nvram,  0xFC, crc);
 
+    // OpenBIOS nvram variables
+    // Variable partition
+    start = 256;
+    m48t59_write(nvram, start, 0x70);
+    NVRAM_set_string(nvram, start + 4, "system", 12);
+
+    end = start + 16;
+    for (i = 0; i < nb_prom_envs; i++)
+        end = nvram_set_var(nvram, end, prom_envs[i]);
+
+    m48t59_write(nvram, end++ , 0);
+    end = start + ((end - start + 15) & ~15);
+    nvram_finish_partition(nvram, start, end);
+
+    // free partition
+    start = end;
+    m48t59_write(nvram, start, 0x7f);
+    NVRAM_set_string(nvram, start + 4, "free", 12);
+
+    end = 0x1fd0;
+    nvram_finish_partition(nvram, start, end);
+
     return 0;
 }
 
@@ -223,14 +276,6 @@
 {
 }
 
-void pic_set_irq(int irq, int level)
-{
-}
-
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
-}
-
 void qemu_system_powerdown(void)
 {
 }
@@ -238,7 +283,39 @@
 static void main_cpu_reset(void *opaque)
 {
     CPUState *env = opaque;
+
     cpu_reset(env);
+    ptimer_set_limit(env->tick, 0x7fffffffffffffffULL, 1);
+    ptimer_run(env->tick, 0);
+    ptimer_set_limit(env->stick, 0x7fffffffffffffffULL, 1);
+    ptimer_run(env->stick, 0);
+    ptimer_set_limit(env->hstick, 0x7fffffffffffffffULL, 1);
+    ptimer_run(env->hstick, 0);
+}
+
+void tick_irq(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+}
+
+void stick_irq(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+}
+
+void hstick_irq(void *opaque)
+{
+    CPUState *env = opaque;
+
+    cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+}
+
+static void dummy_cpu_set_irq(void *opaque, int irq, int level)
+{
 }
 
 static const int ide_iobase[2] = { 0x1f0, 0x170 };
@@ -257,7 +334,7 @@
 static void sun4u_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 *initrd_filename, const char *cpu_model)
 {
     CPUState *env;
     char buf[1024];
@@ -266,25 +343,49 @@
     unsigned int i;
     long prom_offset, initrd_size, kernel_size;
     PCIBus *pci_bus;
+    const sparc_def_t *def;
+    QEMUBH *bh;
+    qemu_irq *irq;
 
     linux_boot = (kernel_filename != NULL);
 
+    /* init CPUs */
+    if (cpu_model == NULL)
+        cpu_model = "TI UltraSparc II";
+    sparc_find_by_name(cpu_model, &def);
+    if (def == NULL) {
+        fprintf(stderr, "Unable to find Sparc CPU definition\n");
+        exit(1);
+    }
     env = cpu_init();
+    cpu_sparc_register(env, def);
+    bh = qemu_bh_new(tick_irq, env);
+    env->tick = ptimer_init(bh);
+    ptimer_set_period(env->tick, 1ULL);
+
+    bh = qemu_bh_new(stick_irq, env);
+    env->stick = ptimer_init(bh);
+    ptimer_set_period(env->stick, 1ULL);
+
+    bh = qemu_bh_new(hstick_irq, env);
+    env->hstick = ptimer_init(bh);
+    ptimer_set_period(env->hstick, 1ULL);
     register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
     qemu_register_reset(main_cpu_reset, env);
+    main_cpu_reset(env);
 
     /* allocate RAM */
     cpu_register_physical_memory(0, ram_size, 0);
 
     prom_offset = ram_size + vga_ram_size;
-    cpu_register_physical_memory(PROM_ADDR, 
-                                 (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK, 
+    cpu_register_physical_memory(PROM_ADDR,
+                                 (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
                                  prom_offset | IO_MEM_ROM);
 
     snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
-    ret = load_elf(buf, 0, NULL);
+    ret = load_elf(buf, PROM_ADDR - PROM_VADDR, NULL, NULL, NULL);
     if (ret < 0) {
-	fprintf(stderr, "qemu: could not load prom '%s'\n", 
+	fprintf(stderr, "qemu: could not load prom '%s'\n",
 		buf);
 	exit(1);
     }
@@ -293,13 +394,13 @@
     initrd_size = 0;
     if (linux_boot) {
         /* XXX: put correct offset */
-        kernel_size = load_elf(kernel_filename, 0, NULL);
+        kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL);
         if (kernel_size < 0)
 	    kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
 	if (kernel_size < 0)
 	    kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
         if (kernel_size < 0) {
-            fprintf(stderr, "qemu: could not load kernel '%s'\n", 
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
                     kernel_filename);
 	    exit(1);
         }
@@ -308,7 +409,7 @@
         if (initrd_filename) {
             initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
             if (initrd_size < 0) {
-                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", 
+                fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
                         initrd_filename);
                 exit(1);
             }
@@ -330,14 +431,13 @@
 
     for(i = 0; i < MAX_SERIAL_PORTS; i++) {
         if (serial_hds[i]) {
-            serial_init(&pic_set_irq_new, NULL,
-                        serial_io[i], serial_irq[i], serial_hds[i]);
+            serial_init(serial_io[i], NULL/*serial_irq[i]*/, serial_hds[i]);
         }
     }
 
     for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
         if (parallel_hds[i]) {
-            parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
+            parallel_init(parallel_io[i], NULL/*parallel_irq[i]*/, parallel_hds[i]);
         }
     }
 
@@ -347,10 +447,13 @@
 	pci_nic_init(pci_bus, &nd_table[i], -1);
     }
 
-    pci_cmd646_ide_init(pci_bus, bs_table, 1);
-    kbd_init();
-    floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
-    nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
+    irq = qemu_allocate_irqs(dummy_cpu_set_irq, NULL, 32);
+    // XXX pci_cmd646_ide_init(pci_bus, bs_table, 1);
+    pci_piix3_ide_init(pci_bus, bs_table, -1, irq);
+    /* FIXME: wire up interrupts.  */
+    i8042_init(NULL/*1*/, NULL/*12*/, 0x60);
+    floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table);
+    nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59);
     sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device,
                          KERNEL_LOAD_ADDR, kernel_size,
                          kernel_cmdline,
diff --git a/hw/tcx.c b/hw/tcx.c
index a1a6b68..9a72d6a 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -1,8 +1,8 @@
 /*
  * QEMU TCX Frame buffer
- * 
+ *
  * Copyright (c) 2003-2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -22,44 +22,31 @@
  * THE SOFTWARE.
  */
 #include "vl.h"
+#include "pixel_ops.h"
 
 #define MAXX 1024
 #define MAXY 768
 #define TCX_DAC_NREGS 16
+#define TCX_THC_NREGS_8  0x081c
+#define TCX_THC_NREGS_24 0x1000
+#define TCX_TEC_NREGS    0x1000
 
 typedef struct TCXState {
-    uint32_t addr;
+    target_phys_addr_t addr;
     DisplayState *ds;
     uint8_t *vram;
-    ram_addr_t vram_offset;
-    uint16_t width, height;
+    uint32_t *vram24, *cplane;
+    ram_addr_t vram_offset, vram24_offset, cplane_offset;
+    uint16_t width, height, depth;
     uint8_t r[256], g[256], b[256];
     uint32_t palette[256];
     uint8_t dac_index, dac_state;
 } TCXState;
 
 static void tcx_screen_dump(void *opaque, const char *filename);
-
-/* XXX: unify with vga draw line functions */
-static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
-{
-    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
-}
-
-static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
-{
-    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
-}
-
-static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
-{
-    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
-}
-
-static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
-{
-    return (r << 16) | (g << 8) | b;
-}
+static void tcx24_screen_dump(void *opaque, const char *filename);
+static void tcx_invalidate_display(void *opaque);
+static void tcx24_invalidate_display(void *opaque);
 
 static void update_palette_entries(TCXState *s, int start, int end)
 {
@@ -71,19 +58,32 @@
             s->palette[i] = rgb_to_pixel8(s->r[i], s->g[i], s->b[i]);
             break;
         case 15:
-            s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
+            if (s->ds->bgr)
+                s->palette[i] = rgb_to_pixel15bgr(s->r[i], s->g[i], s->b[i]);
+            else
+                s->palette[i] = rgb_to_pixel15(s->r[i], s->g[i], s->b[i]);
             break;
         case 16:
-            s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
+            if (s->ds->bgr)
+                s->palette[i] = rgb_to_pixel16bgr(s->r[i], s->g[i], s->b[i]);
+            else
+                s->palette[i] = rgb_to_pixel16(s->r[i], s->g[i], s->b[i]);
             break;
         case 32:
-            s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
+            if (s->ds->bgr)
+                s->palette[i] = rgb_to_pixel32bgr(s->r[i], s->g[i], s->b[i]);
+            else
+                s->palette[i] = rgb_to_pixel32(s->r[i], s->g[i], s->b[i]);
             break;
         }
     }
+    if (s->depth == 24)
+        tcx24_invalidate_display(s);
+    else
+        tcx_invalidate_display(s);
 }
 
-static void tcx_draw_line32(TCXState *s1, uint8_t *d, 
+static void tcx_draw_line32(TCXState *s1, uint8_t *d,
 			    const uint8_t *s, int width)
 {
     int x;
@@ -96,7 +96,7 @@
     }
 }
 
-static void tcx_draw_line16(TCXState *s1, uint8_t *d, 
+static void tcx_draw_line16(TCXState *s1, uint8_t *d,
 			    const uint8_t *s, int width)
 {
     int x;
@@ -109,7 +109,7 @@
     }
 }
 
-static void tcx_draw_line8(TCXState *s1, uint8_t *d, 
+static void tcx_draw_line8(TCXState *s1, uint8_t *d,
 			   const uint8_t *s, int width)
 {
     int x;
@@ -121,6 +121,57 @@
     }
 }
 
+static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
+                                     const uint8_t *s, int width,
+                                     const uint32_t *cplane,
+                                     const uint32_t *s24)
+{
+    int x;
+    uint8_t val;
+    uint32_t *p = (uint32_t *)d;
+    uint32_t dval;
+
+    for(x = 0; x < width; x++, s++, s24++) {
+        if ((bswap32(*cplane++) & 0xff000000) == 0x03000000) { // 24-bit direct
+            dval = bswap32(*s24) & 0x00ffffff;
+        } else {
+            val = *s;
+            dval = s1->palette[val];
+        }
+        *p++ = dval;
+    }
+}
+
+static inline int check_dirty(TCXState *ts, ram_addr_t page, ram_addr_t page24,
+                              ram_addr_t cpage)
+{
+    int ret;
+    unsigned int off;
+
+    ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+    for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
+        ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
+        ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
+    }
+    return ret;
+}
+
+static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
+                               ram_addr_t page_max, ram_addr_t page24,
+                              ram_addr_t cpage)
+{
+    cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
+                                    VGA_DIRTY_FLAG);
+    page_min -= ts->vram_offset;
+    page_max -= ts->vram_offset;
+    cpu_physical_memory_reset_dirty(page24 + page_min * 4,
+                                    page24 + page_max * 4 + TARGET_PAGE_SIZE,
+                                    VGA_DIRTY_FLAG);
+    cpu_physical_memory_reset_dirty(cpage + page_min * 4,
+                                    cpage + page_max * 4 + TARGET_PAGE_SIZE,
+                                    VGA_DIRTY_FLAG);
+}
+
 /* Fixed line length 1024 allows us to do nice tricks not possible on
    VGA... */
 static void tcx_update_display(void *opaque)
@@ -129,7 +180,7 @@
     ram_addr_t page, page_min, page_max;
     int y, y_start, dd, ds;
     uint8_t *d, *s;
-    void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
+    void (*f)(TCXState *s1, uint8_t *dst, const uint8_t *src, int width);
 
     if (ts->ds->depth == 0)
 	return;
@@ -157,7 +208,7 @@
     case 0:
 	return;
     }
-    
+
     for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
 	if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
 	    if (y_start < 0)
@@ -181,7 +232,7 @@
 	} else {
             if (y_start >= 0) {
                 /* flush to display */
-                dpy_update(ts->ds, 0, y_start, 
+                dpy_update(ts->ds, 0, y_start,
                            ts->width, y - y_start);
                 y_start = -1;
             }
@@ -191,7 +242,7 @@
     }
     if (y_start >= 0) {
 	/* flush to display */
-	dpy_update(ts->ds, 0, y_start, 
+	dpy_update(ts->ds, 0, y_start,
 		   ts->width, y - y_start);
     }
     /* reset modified pages */
@@ -201,6 +252,82 @@
     }
 }
 
+static void tcx24_update_display(void *opaque)
+{
+    TCXState *ts = opaque;
+    ram_addr_t page, page_min, page_max, cpage, page24;
+    int y, y_start, dd, ds;
+    uint8_t *d, *s;
+    uint32_t *cptr, *s24;
+
+    if (ts->ds->depth != 32)
+            return;
+    page = ts->vram_offset;
+    page24 = ts->vram24_offset;
+    cpage = ts->cplane_offset;
+    y_start = -1;
+    page_min = 0xffffffff;
+    page_max = 0;
+    d = ts->ds->data;
+    s = ts->vram;
+    s24 = ts->vram24;
+    cptr = ts->cplane;
+    dd = ts->ds->linesize;
+    ds = 1024;
+
+    for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
+            page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
+        if (check_dirty(ts, page, page24, cpage)) {
+            if (y_start < 0)
+                y_start = y;
+            if (page < page_min)
+                page_min = page;
+            if (page > page_max)
+                page_max = page;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+            tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+            d += dd;
+            s += ds;
+            cptr += ds;
+            s24 += ds;
+        } else {
+            if (y_start >= 0) {
+                /* flush to display */
+                dpy_update(ts->ds, 0, y_start,
+                           ts->width, y - y_start);
+                y_start = -1;
+            }
+            d += dd * 4;
+            s += ds * 4;
+            cptr += ds * 4;
+            s24 += ds * 4;
+        }
+    }
+    if (y_start >= 0) {
+        /* flush to display */
+        dpy_update(ts->ds, 0, y_start,
+                   ts->width, y - y_start);
+    }
+    /* reset modified pages */
+    if (page_min <= page_max) {
+        reset_dirty(ts, page_min, page_max, page24, cpage);
+    }
+}
+
 static void tcx_invalidate_display(void *opaque)
 {
     TCXState *s = opaque;
@@ -211,14 +338,25 @@
     }
 }
 
+static void tcx24_invalidate_display(void *opaque)
+{
+    TCXState *s = opaque;
+    int i;
+
+    tcx_invalidate_display(s);
+    for (i = 0; i < MAXX*MAXY * 4; i += TARGET_PAGE_SIZE) {
+        cpu_physical_memory_set_dirty(s->vram24_offset + i);
+        cpu_physical_memory_set_dirty(s->cplane_offset + i);
+    }
+}
+
 static void tcx_save(QEMUFile *f, void *opaque)
 {
     TCXState *s = opaque;
-    
-    qemu_put_be32s(f, (uint32_t *)&s->addr);
-    qemu_put_be32s(f, (uint32_t *)&s->vram);
+
     qemu_put_be16s(f, (uint16_t *)&s->height);
     qemu_put_be16s(f, (uint16_t *)&s->width);
+    qemu_put_be16s(f, (uint16_t *)&s->depth);
     qemu_put_buffer(f, s->r, 256);
     qemu_put_buffer(f, s->g, 256);
     qemu_put_buffer(f, s->b, 256);
@@ -229,20 +367,30 @@
 static int tcx_load(QEMUFile *f, void *opaque, int version_id)
 {
     TCXState *s = opaque;
-    
-    if (version_id != 1)
+    uint32_t dummy;
+
+    if (version_id != 3 && version_id != 4)
         return -EINVAL;
 
-    qemu_get_be32s(f, (uint32_t *)&s->addr);
-    qemu_get_be32s(f, (uint32_t *)&s->vram);
+    if (version_id == 3) {
+        qemu_get_be32s(f, (uint32_t *)&dummy);
+        qemu_get_be32s(f, (uint32_t *)&dummy);
+        qemu_get_be32s(f, (uint32_t *)&dummy);
+    }
     qemu_get_be16s(f, (uint16_t *)&s->height);
     qemu_get_be16s(f, (uint16_t *)&s->width);
+    qemu_get_be16s(f, (uint16_t *)&s->depth);
     qemu_get_buffer(f, s->r, 256);
     qemu_get_buffer(f, s->g, 256);
     qemu_get_buffer(f, s->b, 256);
     qemu_get_8s(f, &s->dac_index);
     qemu_get_8s(f, &s->dac_state);
     update_palette_entries(s, 0, 256);
+    if (s->depth == 24)
+        tcx24_invalidate_display(s);
+    else
+        tcx_invalidate_display(s);
+
     return 0;
 }
 
@@ -257,8 +405,8 @@
     s->r[255] = s->g[255] = s->b[255] = 255;
     update_palette_entries(s, 0, 256);
     memset(s->vram, 0, MAXX*MAXY);
-    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
-                                    VGA_DIRTY_FLAG);
+    cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
+                                    MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
     s->dac_index = 0;
     s->dac_state = 0;
 }
@@ -294,6 +442,7 @@
 	case 2:
 	    s->b[s->dac_index] = val >> 24;
             update_palette_entries(s, s->dac_index, s->dac_index + 1);
+            s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
 	default:
 	    s->dac_state = 0;
 	    break;
@@ -317,29 +466,87 @@
     tcx_dac_writel,
 };
 
-void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
-	      unsigned long vram_offset, int vram_size, int width, int height)
+static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
+{
+    return 0;
+}
+
+static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
+                             uint32_t val)
+{
+}
+
+static CPUReadMemoryFunc *tcx_dummy_read[3] = {
+    tcx_dummy_readl,
+    tcx_dummy_readl,
+    tcx_dummy_readl,
+};
+
+static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
+    tcx_dummy_writel,
+    tcx_dummy_writel,
+    tcx_dummy_writel,
+};
+
+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)
 {
     TCXState *s;
-    int io_memory;
+    int io_memory, dummy_memory;
+    int size;
 
     s = qemu_mallocz(sizeof(TCXState));
     if (!s)
         return;
     s->ds = ds;
     s->addr = addr;
-    s->vram = vram_base;
     s->vram_offset = vram_offset;
     s->width = width;
     s->height = height;
+    s->depth = depth;
 
-    cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
+    // 8-bit plane
+    s->vram = vram_base;
+    size = vram_size;
+    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 + 0x200000, TCX_DAC_NREGS, io_memory);
+    cpu_register_physical_memory(addr + 0x00200000ULL, TCX_DAC_NREGS, io_memory);
 
-    graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
-                         tcx_screen_dump, s);
-    register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
+    dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write,
+                                          s);
+    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 + 0x02000000ULL, size, vram_offset);
+        vram_offset += size;
+        vram_base += size;
+
+        // Control plane
+        size = vram_size * 4;
+        s->cplane = (uint32_t *)vram_base;
+        s->cplane_offset = vram_offset;
+        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 + 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, 4, tcx_save, tcx_load, s);
     qemu_register_reset(tcx_reset, s);
     tcx_reset(s);
     dpy_resize(s->ds, width, height);
@@ -372,5 +579,38 @@
     return;
 }
 
+static void tcx24_screen_dump(void *opaque, const char *filename)
+{
+    TCXState *s = opaque;
+    FILE *f;
+    uint8_t *d, *d1, v;
+    uint32_t *s24, *cptr, dval;
+    int y, x;
 
-
+    f = fopen(filename, "wb");
+    if (!f)
+        return;
+    fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+    d1 = s->vram;
+    s24 = s->vram24;
+    cptr = s->cplane;
+    for(y = 0; y < s->height; y++) {
+        d = d1;
+        for(x = 0; x < s->width; x++, d++, s24++) {
+            if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
+                dval = *s24 & 0x00ffffff;
+                fputc((dval >> 16) & 0xff, f);
+                fputc((dval >> 8) & 0xff, f);
+                fputc(dval & 0xff, f);
+            } else {
+                v = *d;
+                fputc(s->r[v], f);
+                fputc(s->g[v], f);
+                fputc(s->b[v], f);
+            }
+        }
+        d1 += MAXX;
+    }
+    fclose(f);
+    return;
+}
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
index 6448a6f..8728f11 100644
--- a/hw/unin_pci.c
+++ b/hw/unin_pci.c
@@ -2,7 +2,7 @@
  * QEMU Uninorth PCI host (for all Mac99 and newer machines)
  *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -146,12 +146,12 @@
     return (irq_num + (pci_dev->devfn >> 3)) & 3;
 }
 
-static void pci_unin_set_irq(void *pic, int irq_num, int level)
+static void pci_unin_set_irq(qemu_irq *pic, int irq_num, int level)
 {
-    openpic_set_irq(pic, irq_num + 8, level);
+    qemu_set_irq(pic[irq_num + 8], level);
 }
 
-PCIBus *pci_pmac_init(void *pic)
+PCIBus *pci_pmac_init(qemu_irq *pic)
 {
     UNINState *s;
     PCIDevice *d;
@@ -163,13 +163,13 @@
     s->bus = pci_register_bus(pci_unin_set_irq, pci_unin_map_irq,
                               pic, 11 << 3, 4);
 
-    pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read, 
+    pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
                                             pci_unin_main_config_write, s);
     pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read,
                                           pci_unin_main_write, s);
     cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config);
     cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data);
-    d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice), 
+    d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice),
                             11 << 3, NULL, NULL);
     d->config[0x00] = 0x6b; // vendor_id : Apple
     d->config[0x01] = 0x10;
@@ -217,7 +217,7 @@
 #if 0 // XXX: not needed for now
     /* Uninorth AGP bus */
     s = &pci_bridge[1];
-    pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, 
+    pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
                                             pci_unin_config_write, s);
     pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
                                           pci_unin_write, s);
@@ -242,7 +242,7 @@
 #if 0 // XXX: not needed for now
     /* Uninorth internal bus */
     s = &pci_bridge[2];
-    pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read, 
+    pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
                                             pci_unin_config_write, s);
     pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
                                           pci_unin_write, s);
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index bde3a7c..aebcf03 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -1,8 +1,9 @@
 /*
  * QEMU USB HID devices
- * 
+ *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ * Copyright (c) 2007 OpenMoko, Inc.  (andrew@openedhand.com)
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -27,26 +28,50 @@
 #define GET_REPORT   0xa101
 #define GET_IDLE     0xa102
 #define GET_PROTOCOL 0xa103
+#define SET_REPORT   0x2109
 #define SET_IDLE     0x210a
 #define SET_PROTOCOL 0x210b
 
-#define USB_MOUSE  1
-#define USB_TABLET 2
+/* HID descriptor types */
+#define USB_DT_HID    0x21
+#define USB_DT_REPORT 0x22
+#define USB_DT_PHY    0x23
+
+#define USB_MOUSE     1
+#define USB_TABLET    2
+#define USB_KEYBOARD  3
 
 typedef struct USBMouseState {
-    USBDevice dev;
     int dx, dy, dz, buttons_state;
     int x, y;
-    int kind;
     int mouse_grabbed;
     QEMUPutMouseEntry *eh_entry;
 } USBMouseState;
 
+typedef struct USBKeyboardState {
+    uint16_t modifiers;
+    uint8_t leds;
+    uint8_t key[16];
+    int keys;
+} USBKeyboardState;
+
+typedef struct USBHIDState {
+    USBDevice dev;
+    union {
+        USBMouseState ptr;
+        USBKeyboardState kbd;
+    };
+    int kind;
+    int protocol;
+    int idle;
+    int changed;
+} USBHIDState;
+
 /* mostly the same values as the Bochs USB Mouse device */
 static const uint8_t qemu_mouse_dev_descriptor[] = {
 	0x12,       /*  u8 bLength; */
 	0x01,       /*  u8 bDescriptorType; Device */
-	0x10, 0x00, /*  u16 bcdUSB; v1.0 */
+	0x00, 0x01, /*  u16 bcdUSB; v1.0 */
 
 	0x00,	    /*  u8  bDeviceClass; */
 	0x00,	    /*  u8  bDeviceSubClass; */
@@ -71,13 +96,13 @@
 	0x01,       /*  u8  bNumInterfaces; (1) */
 	0x01,       /*  u8  bConfigurationValue; */
 	0x04,       /*  u8  iConfiguration; */
-	0xa0,       /*  u8  bmAttributes; 
+	0xa0,       /*  u8  bmAttributes;
 				 Bit 7: must be set,
 				     6: Self-powered,
 				     5: Remote wakeup,
 				     4..0: resvd */
 	50,         /*  u8  MaxPower; */
-      
+
 	/* USB 1.1:
 	 * USB 2.0, single TT organization (mandatory):
 	 *	one interface, protocol 0
@@ -98,8 +123,8 @@
 	0x03,       /*  u8  if_bInterfaceClass; */
 	0x01,       /*  u8  if_bInterfaceSubClass; */
 	0x02,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
-	0x05,       /*  u8  if_iInterface; */
-     
+	0x07,       /*  u8  if_iInterface; */
+
         /* HID descriptor */
         0x09,        /*  u8  bLength; */
         0x21,        /*  u8 bDescriptorType; */
@@ -125,14 +150,14 @@
 	0x22, 0x00, /*  u16 wTotalLength; */
 	0x01,       /*  u8  bNumInterfaces; (1) */
 	0x01,       /*  u8  bConfigurationValue; */
-	0x04,       /*  u8  iConfiguration; */
-	0xa0,       /*  u8  bmAttributes; 
+	0x05,       /*  u8  iConfiguration; */
+	0xa0,       /*  u8  bmAttributes;
 				 Bit 7: must be set,
 				     6: Self-powered,
 				     5: Remote wakeup,
 				     4..0: resvd */
 	50,         /*  u8  MaxPower; */
-      
+
 	/* USB 1.1:
 	 * USB 2.0, single TT organization (mandatory):
 	 *	one interface, protocol 0
@@ -153,7 +178,7 @@
 	0x03,       /*  u8  if_bInterfaceClass; */
 	0x01,       /*  u8  if_bInterfaceSubClass; */
 	0x02,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
-	0x05,       /*  u8  if_iInterface; */
+	0x07,       /*  u8  if_iInterface; */
 
         /* HID descriptor */
         0x09,        /*  u8  bLength; */
@@ -170,15 +195,70 @@
 	0x81,       /*  u8  ep_bEndpointAddress; IN Endpoint 1 */
  	0x03,       /*  u8  ep_bmAttributes; Interrupt */
  	0x08, 0x00, /*  u16 ep_wMaxPacketSize; */
-	0x03,       /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
+	0x0a,       /*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
+};
+
+static const uint8_t qemu_keyboard_config_descriptor[] = {
+    /* one configuration */
+    0x09,		/*  u8  bLength; */
+    USB_DT_CONFIG,	/*  u8  bDescriptorType; Configuration */
+    0x22, 0x00,		/*  u16 wTotalLength; */
+    0x01,		/*  u8  bNumInterfaces; (1) */
+    0x01,		/*  u8  bConfigurationValue; */
+    0x06,		/*  u8  iConfiguration; */
+    0xa0,		/*  u8  bmAttributes;
+				Bit 7: must be set,
+				    6: Self-powered,
+				    5: Remote wakeup,
+				    4..0: resvd */
+    0x32,		/*  u8  MaxPower; */
+
+    /* USB 1.1:
+     * USB 2.0, single TT organization (mandatory):
+     *	one interface, protocol 0
+     *
+     * USB 2.0, multiple TT organization (optional):
+     *	two interfaces, protocols 1 (like single TT)
+     *	and 2 (multiple TT mode) ... config is
+     *	sometimes settable
+     *	NOT IMPLEMENTED
+     */
+
+    /* one interface */
+    0x09,		/*  u8  if_bLength; */
+    USB_DT_INTERFACE,	/*  u8  if_bDescriptorType; Interface */
+    0x00,		/*  u8  if_bInterfaceNumber; */
+    0x00,		/*  u8  if_bAlternateSetting; */
+    0x01,		/*  u8  if_bNumEndpoints; */
+    0x03,		/*  u8  if_bInterfaceClass; HID */
+    0x01,		/*  u8  if_bInterfaceSubClass; Boot */
+    0x01,		/*  u8  if_bInterfaceProtocol; Keyboard */
+    0x07,		/*  u8  if_iInterface; */
+
+    /* HID descriptor */
+    0x09,		/*  u8  bLength; */
+    USB_DT_HID,		/*  u8  bDescriptorType; */
+    0x11, 0x01,		/*  u16 HID_class */
+    0x00,		/*  u8  country_code */
+    0x01,		/*  u8  num_descriptors */
+    USB_DT_REPORT,	/*  u8  type; Report */
+    0x3f, 0x00,		/*  u16 len */
+
+    /* one endpoint (status change endpoint) */
+    0x07,		/*  u8  ep_bLength; */
+    USB_DT_ENDPOINT,	/*  u8  ep_bDescriptorType; Endpoint */
+    USB_DIR_IN | 0x01,	/*  u8  ep_bEndpointAddress; IN Endpoint 1 */
+    0x03,		/*  u8  ep_bmAttributes; Interrupt */
+    0x08, 0x00,		/*  u16 ep_wMaxPacketSize; */
+    0x0a,		/*  u8  ep_bInterval; (255ms -- usb 2.0 spec) */
 };
 
 static const uint8_t qemu_mouse_hid_report_descriptor[] = {
-    0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01, 
+    0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
     0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
-    0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01, 
+    0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
     0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
-    0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81, 
+    0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x15, 0x81,
     0x25, 0x7F, 0x75, 0x08, 0x95, 0x02, 0x81, 0x06,
     0xC0, 0xC0,
 };
@@ -223,26 +303,155 @@
         0xC0,       /* End Collection */
 };
 
+static const uint8_t qemu_keyboard_hid_report_descriptor[] = {
+    0x05, 0x01,		/* Usage Page (Generic Desktop) */
+    0x09, 0x06,		/* Usage (Keyboard) */
+    0xa1, 0x01,		/* Collection (Application) */
+    0x75, 0x01,		/*   Report Size (1) */
+    0x95, 0x08,		/*   Report Count (8) */
+    0x05, 0x07,		/*   Usage Page (Key Codes) */
+    0x19, 0xe0,		/*   Usage Minimum (224) */
+    0x29, 0xe7,		/*   Usage Maximum (231) */
+    0x15, 0x00,		/*   Logical Minimum (0) */
+    0x25, 0x01,		/*   Logical Maximum (1) */
+    0x81, 0x02,		/*   Input (Data, Variable, Absolute) */
+    0x95, 0x01,		/*   Report Count (1) */
+    0x75, 0x08,		/*   Report Size (8) */
+    0x81, 0x01,		/*   Input (Constant) */
+    0x95, 0x05,		/*   Report Count (5) */
+    0x75, 0x01,		/*   Report Size (1) */
+    0x05, 0x08,		/*   Usage Page (LEDs) */
+    0x19, 0x01,		/*   Usage Minimum (1) */
+    0x29, 0x05,		/*   Usage Maximum (5) */
+    0x91, 0x02,		/*   Output (Data, Variable, Absolute) */
+    0x95, 0x01,		/*   Report Count (1) */
+    0x75, 0x03,		/*   Report Size (3) */
+    0x91, 0x01,		/*   Output (Constant) */
+    0x95, 0x06,		/*   Report Count (6) */
+    0x75, 0x08,		/*   Report Size (8) */
+    0x15, 0x00,		/*   Logical Minimum (0) */
+    0x25, 0xff,		/*   Logical Maximum (255) */
+    0x05, 0x07,		/*   Usage Page (Key Codes) */
+    0x19, 0x00,		/*   Usage Minimum (0) */
+    0x29, 0xff,		/*   Usage Maximum (255) */
+    0x81, 0x00,		/*   Input (Data, Array) */
+    0xc0,		/* End Collection */
+};
+
+#define USB_HID_USAGE_ERROR_ROLLOVER	0x01
+#define USB_HID_USAGE_POSTFAIL		0x02
+#define USB_HID_USAGE_ERROR_UNDEFINED	0x03
+
+/* Indices are QEMU keycodes, values are from HID Usage Table.  Indices
+ * above 0x80 are for keys that come after 0xe0 or 0xe1+0x1d or 0xe1+0x9d.  */
+static const uint8_t usb_hid_usage_keys[0x100] = {
+    0x00, 0x29, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x25, 0x26, 0x27, 0x2d, 0x2e, 0x2a, 0x2b,
+    0x14, 0x1a, 0x08, 0x15, 0x17, 0x1c, 0x18, 0x0c,
+    0x12, 0x13, 0x2f, 0x30, 0x28, 0xe0, 0x04, 0x16,
+    0x07, 0x09, 0x0a, 0x0b, 0x0d, 0x0e, 0x0f, 0x33,
+    0x34, 0x35, 0xe1, 0x31, 0x1d, 0x1b, 0x06, 0x19,
+    0x05, 0x11, 0x10, 0x36, 0x37, 0x38, 0xe5, 0x55,
+    0xe2, 0x2c, 0x32, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x40, 0x41, 0x42, 0x43, 0x53, 0x47, 0x5f,
+    0x60, 0x61, 0x56, 0x5c, 0x5d, 0x5e, 0x57, 0x59,
+    0x5a, 0x5b, 0x62, 0x63, 0x00, 0x00, 0x00, 0x44,
+    0x45, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+    0xe8, 0xe9, 0x71, 0x72, 0x73, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0xe7, 0x65,
+
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x58, 0xe4, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x46,
+    0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x4a,
+    0x52, 0x4b, 0x00, 0x50, 0x00, 0x4f, 0x00, 0x4d,
+    0x51, 0x4e, 0x49, 0x4c, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
 static void usb_mouse_event(void *opaque,
                             int dx1, int dy1, int dz1, int buttons_state)
 {
-    USBMouseState *s = opaque;
+    USBHIDState *hs = opaque;
+    USBMouseState *s = &hs->ptr;
 
     s->dx += dx1;
     s->dy += dy1;
     s->dz += dz1;
     s->buttons_state = buttons_state;
+    hs->changed = 1;
 }
 
 static void usb_tablet_event(void *opaque,
 			     int x, int y, int dz, int buttons_state)
 {
-    USBMouseState *s = opaque;
+    USBHIDState *hs = opaque;
+    USBMouseState *s = &hs->ptr;
 
     s->x = x;
     s->y = y;
     s->dz += dz;
     s->buttons_state = buttons_state;
+    hs->changed = 1;
+}
+
+static void usb_keyboard_event(void *opaque, int keycode)
+{
+    USBHIDState *hs = opaque;
+    USBKeyboardState *s = &hs->kbd;
+    uint8_t hid_code, key;
+    int i;
+
+    key = keycode & 0x7f;
+    hid_code = usb_hid_usage_keys[key | ((s->modifiers >> 1) & (1 << 7))];
+    s->modifiers &= ~(1 << 8);
+
+    hs->changed = 1;
+
+    switch (hid_code) {
+    case 0x00:
+        return;
+
+    case 0xe0:
+        if (s->modifiers & (1 << 9)) {
+            s->modifiers ^= 3 << 8;
+            return;
+        }
+    case 0xe1 ... 0xe7:
+        if (keycode & (1 << 7)) {
+            s->modifiers &= ~(1 << (hid_code & 0x0f));
+            return;
+        }
+    case 0xe8 ... 0xef:
+        s->modifiers |= 1 << (hid_code & 0x0f);
+        return;
+    }
+
+    if (keycode & (1 << 7)) {
+        for (i = s->keys - 1; i >= 0; i --)
+            if (s->key[i] == hid_code) {
+                s->key[i] = s->key[-- s->keys];
+                s->key[s->keys] = 0x00;
+                return;
+            }
+    } else {
+        for (i = s->keys - 1; i >= 0; i --)
+            if (s->key[i] == hid_code)
+                return;
+        if (s->keys < sizeof(s->key))
+            s->key[s->keys ++] = hid_code;
+    }
 }
 
 static inline int int_clamp(int val, int vmin, int vmax)
@@ -255,16 +464,17 @@
         return val;
 }
 
-static int usb_mouse_poll(USBMouseState *s, uint8_t *buf, int len)
+static int usb_mouse_poll(USBHIDState *hs, uint8_t *buf, int len)
 {
     int dx, dy, dz, b, l;
+    USBMouseState *s = &hs->ptr;
 
     if (!s->mouse_grabbed) {
-	s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s,
+	s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, hs,
                                                   0, "QEMU USB Mouse");
 	s->mouse_grabbed = 1;
     }
-    
+
     dx = int_clamp(s->dx, -128, 127);
     dy = int_clamp(s->dy, -128, 127);
     dz = int_clamp(s->dz, -128, 127);
@@ -272,7 +482,7 @@
     s->dx -= dx;
     s->dy -= dy;
     s->dz -= dz;
-    
+
     b = 0;
     if (s->buttons_state & MOUSE_EVENT_LBUTTON)
         b |= 0x01;
@@ -280,7 +490,7 @@
         b |= 0x02;
     if (s->buttons_state & MOUSE_EVENT_MBUTTON)
         b |= 0x04;
-    
+
     buf[0] = b;
     buf[1] = dx;
     buf[2] = dy;
@@ -292,16 +502,17 @@
     return l;
 }
 
-static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
+static int usb_tablet_poll(USBHIDState *hs, uint8_t *buf, int len)
 {
     int dz, b, l;
+    USBMouseState *s = &hs->ptr;
 
     if (!s->mouse_grabbed) {
-	s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, s,
+	s->eh_entry = qemu_add_mouse_event_handler(usb_tablet_event, hs,
                                                   1, "QEMU USB Tablet");
 	s->mouse_grabbed = 1;
     }
-    
+
     dz = int_clamp(s->dz, -128, 127);
     s->dz -= dz;
 
@@ -326,22 +537,59 @@
     return l;
 }
 
-static void usb_mouse_handle_reset(USBDevice *dev)
+static int usb_keyboard_poll(USBKeyboardState *s, uint8_t *buf, int len)
 {
-    USBMouseState *s = (USBMouseState *)dev;
+    if (len < 2)
+        return 0;
 
-    s->dx = 0;
-    s->dy = 0;
-    s->dz = 0;
-    s->x = 0;
-    s->y = 0;
-    s->buttons_state = 0;
+    buf[0] = s->modifiers & 0xff;
+    buf[1] = 0;
+    if (s->keys > 6)
+        memset(buf + 2, USB_HID_USAGE_ERROR_ROLLOVER, MIN(8, len) - 2);
+    else
+        memcpy(buf + 2, s->key, MIN(8, len) - 2);
+
+    return MIN(8, len);
 }
 
-static int usb_mouse_handle_control(USBDevice *dev, int request, int value,
+static int usb_keyboard_write(USBKeyboardState *s, uint8_t *buf, int len)
+{
+    if (len > 0) {
+        /* 0x01: Num Lock LED
+         * 0x02: Caps Lock LED
+         * 0x04: Scroll Lock LED
+         * 0x08: Compose LED
+         * 0x10: Kana LED */
+        s->leds = buf[0];
+    }
+    return 0;
+}
+
+static void usb_mouse_handle_reset(USBDevice *dev)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+
+    s->ptr.dx = 0;
+    s->ptr.dy = 0;
+    s->ptr.dz = 0;
+    s->ptr.x = 0;
+    s->ptr.y = 0;
+    s->ptr.buttons_state = 0;
+    s->protocol = 1;
+}
+
+static void usb_keyboard_handle_reset(USBDevice *dev)
+{
+    USBHIDState *s = (USBHIDState *)dev;
+
+    qemu_add_kbd_event_handler(usb_keyboard_event, s);
+    s->protocol = 1;
+}
+
+static int usb_hid_handle_control(USBDevice *dev, int request, int value,
                                   int index, int length, uint8_t *data)
 {
-    USBMouseState *s = (USBMouseState *)dev;
+    USBHIDState *s = (USBHIDState *)dev;
     int ret = 0;
 
     switch(request) {
@@ -374,20 +622,24 @@
     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
         switch(value >> 8) {
         case USB_DT_DEVICE:
-            memcpy(data, qemu_mouse_dev_descriptor, 
+            memcpy(data, qemu_mouse_dev_descriptor,
                    sizeof(qemu_mouse_dev_descriptor));
             ret = sizeof(qemu_mouse_dev_descriptor);
             break;
         case USB_DT_CONFIG:
 	    if (s->kind == USB_MOUSE) {
-		memcpy(data, qemu_mouse_config_descriptor, 
+		memcpy(data, qemu_mouse_config_descriptor,
 		       sizeof(qemu_mouse_config_descriptor));
 		ret = sizeof(qemu_mouse_config_descriptor);
 	    } else if (s->kind == USB_TABLET) {
-		memcpy(data, qemu_tablet_config_descriptor, 
+		memcpy(data, qemu_tablet_config_descriptor,
 		       sizeof(qemu_tablet_config_descriptor));
 		ret = sizeof(qemu_tablet_config_descriptor);
-	    }		
+            } else if (s->kind == USB_KEYBOARD) {
+                memcpy(data, qemu_keyboard_config_descriptor,
+                       sizeof(qemu_keyboard_config_descriptor));
+                ret = sizeof(qemu_keyboard_config_descriptor);
+            }
             break;
         case USB_DT_STRING:
             switch(value & 0xff) {
@@ -405,10 +657,7 @@
                 break;
             case 2:
                 /* product description */
-		if (s->kind == USB_MOUSE)
-		    ret = set_usb_string(data, "QEMU USB Mouse");
-		else if (s->kind == USB_TABLET)
-		    ret = set_usb_string(data, "QEMU USB Tablet");
+                ret = set_usb_string(data, s->dev.devname);
                 break;
             case 3:
                 /* vendor description */
@@ -418,6 +667,12 @@
                 ret = set_usb_string(data, "HID Mouse");
                 break;
             case 5:
+                ret = set_usb_string(data, "HID Tablet");
+                break;
+            case 6:
+                ret = set_usb_string(data, "HID Keyboard");
+                break;
+            case 7:
                 ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
                 break;
             default:
@@ -447,26 +702,55 @@
         switch(value >> 8) {
         case 0x22:
 	    if (s->kind == USB_MOUSE) {
-		memcpy(data, qemu_mouse_hid_report_descriptor, 
+		memcpy(data, qemu_mouse_hid_report_descriptor,
 		       sizeof(qemu_mouse_hid_report_descriptor));
 		ret = sizeof(qemu_mouse_hid_report_descriptor);
 	    } else if (s->kind == USB_TABLET) {
-		memcpy(data, qemu_tablet_hid_report_descriptor, 
+		memcpy(data, qemu_tablet_hid_report_descriptor,
 		       sizeof(qemu_tablet_hid_report_descriptor));
 		ret = sizeof(qemu_tablet_hid_report_descriptor);
-	    }
-	    break;
+            } else if (s->kind == USB_KEYBOARD) {
+                memcpy(data, qemu_keyboard_hid_report_descriptor,
+                       sizeof(qemu_keyboard_hid_report_descriptor));
+                ret = sizeof(qemu_keyboard_hid_report_descriptor);
+            }
+            break;
         default:
             goto fail;
         }
         break;
     case GET_REPORT:
 	if (s->kind == USB_MOUSE)
-	    ret = usb_mouse_poll(s, data, length);
+            ret = usb_mouse_poll(s, data, length);
 	else if (s->kind == USB_TABLET)
-	    ret = usb_tablet_poll(s, data, length);
+            ret = usb_tablet_poll(s, data, length);
+        else if (s->kind == USB_KEYBOARD)
+            ret = usb_keyboard_poll(&s->kbd, data, length);
+        break;
+    case SET_REPORT:
+        if (s->kind == USB_KEYBOARD)
+            ret = usb_keyboard_write(&s->kbd, data, length);
+        else
+            goto fail;
+        break;
+    case GET_PROTOCOL:
+        if (s->kind != USB_KEYBOARD)
+            goto fail;
+        ret = 1;
+        data[0] = s->protocol;
+        break;
+    case SET_PROTOCOL:
+        if (s->kind != USB_KEYBOARD)
+            goto fail;
+        ret = 0;
+        s->protocol = value;
+        break;
+    case GET_IDLE:
+        ret = 1;
+        data[0] = s->idle;
         break;
     case SET_IDLE:
+        s->idle = value;
         ret = 0;
         break;
     default:
@@ -477,18 +761,24 @@
     return ret;
 }
 
-static int usb_mouse_handle_data(USBDevice *dev, USBPacket *p)
+static int usb_hid_handle_data(USBDevice *dev, USBPacket *p)
 {
-    USBMouseState *s = (USBMouseState *)dev;
+    USBHIDState *s = (USBHIDState *)dev;
     int ret = 0;
 
     switch(p->pid) {
     case USB_TOKEN_IN:
         if (p->devep == 1) {
-	    if (s->kind == USB_MOUSE)
-		ret = usb_mouse_poll(s, p->data, p->len);
-	    else if (s->kind == USB_TABLET)
-		ret = usb_tablet_poll(s, p->data, p->len);
+            /* TODO: Implement finite idle delays.  */
+            if (!(s->changed || s->idle))
+                return USB_RET_NAK;
+            s->changed = 0;
+            if (s->kind == USB_MOUSE)
+                ret = usb_mouse_poll(s, p->data, p->len);
+            else if (s->kind == USB_TABLET)
+                ret = usb_tablet_poll(s, p->data, p->len);
+            else if (s->kind == USB_KEYBOARD)
+                ret = usb_keyboard_poll(&s->kbd, p->data, p->len);
         } else {
             goto fail;
         }
@@ -502,29 +792,33 @@
     return ret;
 }
 
-static void usb_mouse_handle_destroy(USBDevice *dev)
+static void usb_hid_handle_destroy(USBDevice *dev)
 {
-    USBMouseState *s = (USBMouseState *)dev;
+    USBHIDState *s = (USBHIDState *)dev;
 
-    qemu_remove_mouse_event_handler(s->eh_entry);
+    if (s->kind != USB_KEYBOARD)
+        qemu_remove_mouse_event_handler(s->ptr.eh_entry);
+    /* TODO: else */
     qemu_free(s);
 }
 
 USBDevice *usb_tablet_init(void)
 {
-    USBMouseState *s;
+    USBHIDState *s;
 
-    s = qemu_mallocz(sizeof(USBMouseState));
+    s = qemu_mallocz(sizeof(USBHIDState));
     if (!s)
         return NULL;
     s->dev.speed = USB_SPEED_FULL;
     s->dev.handle_packet = usb_generic_handle_packet;
 
     s->dev.handle_reset = usb_mouse_handle_reset;
-    s->dev.handle_control = usb_mouse_handle_control;
-    s->dev.handle_data = usb_mouse_handle_data;
-    s->dev.handle_destroy = usb_mouse_handle_destroy;
+    s->dev.handle_control = usb_hid_handle_control;
+    s->dev.handle_data = usb_hid_handle_data;
+    s->dev.handle_destroy = usb_hid_handle_destroy;
     s->kind = USB_TABLET;
+    /* Force poll routine to be run and grab input the first time.  */
+    s->changed = 1;
 
     pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
 
@@ -533,21 +827,44 @@
 
 USBDevice *usb_mouse_init(void)
 {
-    USBMouseState *s;
+    USBHIDState *s;
 
-    s = qemu_mallocz(sizeof(USBMouseState));
+    s = qemu_mallocz(sizeof(USBHIDState));
     if (!s)
         return NULL;
     s->dev.speed = USB_SPEED_FULL;
     s->dev.handle_packet = usb_generic_handle_packet;
 
     s->dev.handle_reset = usb_mouse_handle_reset;
-    s->dev.handle_control = usb_mouse_handle_control;
-    s->dev.handle_data = usb_mouse_handle_data;
-    s->dev.handle_destroy = usb_mouse_handle_destroy;
+    s->dev.handle_control = usb_hid_handle_control;
+    s->dev.handle_data = usb_hid_handle_data;
+    s->dev.handle_destroy = usb_hid_handle_destroy;
     s->kind = USB_MOUSE;
+    /* Force poll routine to be run and grab input the first time.  */
+    s->changed = 1;
 
     pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
 
     return (USBDevice *)s;
 }
+
+USBDevice *usb_keyboard_init(void)
+{
+    USBHIDState *s;
+
+    s = qemu_mallocz(sizeof(USBHIDState));
+    if (!s)
+        return NULL;
+    s->dev.speed = USB_SPEED_FULL;
+    s->dev.handle_packet = usb_generic_handle_packet;
+
+    s->dev.handle_reset = usb_keyboard_handle_reset;
+    s->dev.handle_control = usb_hid_handle_control;
+    s->dev.handle_data = usb_hid_handle_data;
+    s->dev.handle_destroy = usb_hid_handle_destroy;
+    s->kind = USB_KEYBOARD;
+
+    pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Keyboard");
+
+    return (USBDevice *) s;
+}
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 651dac2..1dcac3c 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -2,7 +2,7 @@
  * QEMU USB HUB emulation
  *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -112,13 +112,13 @@
 	0x01,       /*  u8  bNumInterfaces; (1) */
 	0x01,       /*  u8  bConfigurationValue; */
 	0x00,       /*  u8  iConfiguration; */
-	0xc0,       /*  u8  bmAttributes; 
+	0xc0,       /*  u8  bmAttributes;
 				 Bit 7: must be set,
 				     6: Self-powered,
 				     5: Remote wakeup,
 				     4..0: resvd */
 	0x00,       /*  u8  MaxPower; */
-      
+
 	/* USB 1.1:
 	 * USB 2.0, single TT organization (mandatory):
 	 *	one interface, protocol 0
@@ -140,7 +140,7 @@
 	0x00,       /*  u8  if_bInterfaceSubClass; */
 	0x00,       /*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
 	0x00,       /*  u8  if_iInterface; */
-     
+
 	/* one endpoint (status change endpoint) */
 	0x07,       /*  u8  ep_bLength; */
 	0x05,       /*  u8  ep_bDescriptorType; Endpoint */
@@ -167,11 +167,11 @@
 {
     USBHubState *s = port1->opaque;
     USBHubPort *port = &s->ports[port1->index];
-    
+
     if (dev) {
         if (port->port.dev)
             usb_attach(port1, NULL);
-        
+
         port->wPortStatus |= PORT_STAT_CONNECTION;
         port->wPortChange |= PORT_STAT_C_CONNECTION;
         if (dev->speed == USB_SPEED_LOW)
@@ -244,12 +244,12 @@
     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
         switch(value >> 8) {
         case USB_DT_DEVICE:
-            memcpy(data, qemu_hub_dev_descriptor, 
+            memcpy(data, qemu_hub_dev_descriptor,
                    sizeof(qemu_hub_dev_descriptor));
             ret = sizeof(qemu_hub_dev_descriptor);
             break;
         case USB_DT_CONFIG:
-            memcpy(data, qemu_hub_config_descriptor, 
+            memcpy(data, qemu_hub_config_descriptor,
                    sizeof(qemu_hub_config_descriptor));
 
             /* status change endpoint size based on number
@@ -401,7 +401,7 @@
     case GetHubDescriptor:
         {
             unsigned int n, limit, var_hub_size = 0;
-            memcpy(data, qemu_hub_hub_descriptor, 
+            memcpy(data, qemu_hub_hub_descriptor,
                    sizeof(qemu_hub_hub_descriptor));
             data[2] = s->nb_ports;
 
@@ -504,8 +504,8 @@
     if (dev->state == USB_STATE_DEFAULT &&
         dev->addr != 0 &&
         p->devaddr != dev->addr &&
-        (p->pid == USB_TOKEN_SETUP || 
-         p->pid == USB_TOKEN_OUT || 
+        (p->pid == USB_TOKEN_SETUP ||
+         p->pid == USB_TOKEN_OUT ||
          p->pid == USB_TOKEN_IN)) {
         /* broadcast the packet to the devices */
         return usb_hub_broadcast_packet(s, p);
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index 4530a1c..b1ad9ec 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * USB Mass Storage Device emulation
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -66,7 +66,7 @@
 static const uint8_t qemu_msd_dev_descriptor[] = {
 	0x12,       /*  u8 bLength; */
 	0x01,       /*  u8 bDescriptorType; Device */
-	0x10, 0x00, /*  u16 bcdUSB; v1.0 */
+	0x00, 0x01, /*  u16 bcdUSB; v1.0 */
 
 	0x00,	    /*  u8  bDeviceClass; */
 	0x00,	    /*  u8  bDeviceSubClass; */
@@ -93,13 +93,13 @@
 	0x01,       /*  u8  bNumInterfaces; (1) */
 	0x01,       /*  u8  bConfigurationValue; */
 	0x00,       /*  u8  iConfiguration; */
-	0xc0,       /*  u8  bmAttributes; 
+	0xc0,       /*  u8  bmAttributes;
 				 Bit 7: must be set,
 				     6: Self-powered,
 				     5: Remote wakeup,
 				     4..0: resvd */
 	0x00,       /*  u8  MaxPower; */
-      
+
 	/* one interface */
 	0x09,       /*  u8  if_bLength; */
 	0x04,       /*  u8  if_bDescriptorType; Interface */
@@ -110,7 +110,7 @@
 	0x06,       /*  u8  if_bInterfaceSubClass; SCSI */
 	0x50,       /*  u8  if_bInterfaceProtocol; Bulk Only */
 	0x00,       /*  u8  if_iInterface; */
-     
+
 	/* Bulk-In endpoint */
 	0x07,       /*  u8  ep_bLength; */
 	0x05,       /*  u8  ep_bDescriptorType; Endpoint */
@@ -259,12 +259,12 @@
     case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
         switch(value >> 8) {
         case USB_DT_DEVICE:
-            memcpy(data, qemu_msd_dev_descriptor, 
+            memcpy(data, qemu_msd_dev_descriptor,
                    sizeof(qemu_msd_dev_descriptor));
             ret = sizeof(qemu_msd_dev_descriptor);
             break;
         case USB_DT_CONFIG:
-            memcpy(data, qemu_msd_config_descriptor, 
+            memcpy(data, qemu_msd_config_descriptor,
                    sizeof(qemu_msd_config_descriptor));
             ret = sizeof(qemu_msd_config_descriptor);
             break;
@@ -522,6 +522,8 @@
     bdrv = bdrv_new("usb");
     if (bdrv_open(bdrv, filename, 0) < 0)
         goto fail;
+    if (qemu_key_check(bdrv, filename))
+        goto fail;
     s->bs = bdrv;
 
     s->dev.speed = USB_SPEED_FULL;
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index de113e9..2d5af7d 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -2,6 +2,7 @@
  * QEMU USB OHCI Emulation
  * Copyright (c) 2004 Gianni Tedesco
  * Copyright (c) 2006 CodeSourcery
+ * Copyright (c) 2006 Openedhand Ltd.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -52,11 +53,18 @@
     uint32_t ctrl;
 } OHCIPort;
 
+enum ohci_type {
+    OHCI_TYPE_PCI,
+    OHCI_TYPE_PXA
+};
+
 typedef struct {
-    struct PCIDevice pci_dev;
+    qemu_irq irq;
+    enum ohci_type type;
     target_phys_addr_t mem_base;
     int mem;
     int num_ports;
+    const char *name;
 
     QEMUTimer *eof_timer;
     int64_t sof_time;
@@ -90,6 +98,12 @@
     uint32_t rhstatus;
     OHCIPort rhport[OHCI_MAX_PORTS];
 
+    /* PXA27x Non-OHCI events */
+    uint32_t hstatus;
+    uint32_t hmask;
+    uint32_t hreset;
+    uint32_t htest;
+
     /* Active packets.  */
     uint32_t old_ctl;
     USBPacket usb_packet;
@@ -106,6 +120,8 @@
     uint32_t done;
 };
 
+static void ohci_bus_stop(OHCIState *ohci);
+
 /* Bitfields for the first word of an Endpoint Desciptor.  */
 #define OHCI_ED_FA_SHIFT  0
 #define OHCI_ED_FA_MASK   (0x7f<<OHCI_ED_FA_SHIFT)
@@ -256,6 +272,8 @@
 #define OHCI_CC_BUFFEROVERRUN       0xc
 #define OHCI_CC_BUFFERUNDERRUN      0xd
 
+#define OHCI_HRESET_FSBIR       (1 << 0)
+
 /* Update IRQ levels */
 static inline void ohci_intr_update(OHCIState *ohci)
 {
@@ -265,7 +283,7 @@
         (ohci->intr_status & ohci->intr))
         level = 1;
 
-    pci_set_irq(&ohci->pci_dev, 0, level);
+    qemu_set_irq(ohci->irq, level);
 }
 
 /* Set an interrupt */
@@ -295,6 +313,11 @@
         else
             port->ctrl &= ~OHCI_PORT_LSDA;
         port->port.dev = dev;
+
+        /* notify of remote-wakeup */
+        if ((s->ctl & OHCI_CTL_HCFS) == OHCI_USB_SUSPEND)
+            ohci_set_interrupt(s, OHCI_INTR_RD);
+
         /* send the attach message */
         usb_send_msg(dev, USB_MSG_ATTACH);
         dprintf("usb-ohci: Attached port %d\n", port1->index);
@@ -323,11 +346,13 @@
 }
 
 /* Reset the controller */
-static void ohci_reset(OHCIState *ohci)
+static void ohci_reset(void *opaque)
 {
+    OHCIState *ohci = opaque;
     OHCIPort *port;
     int i;
 
+    ohci_bus_stop(ohci);
     ohci->ctl = 0;
     ohci->old_ctl = 0;
     ohci->status = 0;
@@ -367,7 +392,7 @@
         usb_cancel_packet(&ohci->usb_packet);
         ohci->async_td = 0;
     }
-    dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name);
+    dprintf("usb-ohci: Reset %s\n", ohci->name);
 }
 
 /* Get an array of dwords from main memory */
@@ -795,13 +820,12 @@
                     ohci);
 
     if (ohci->eof_timer == NULL) {
-        fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n",
-            ohci->pci_dev.name);
+        fprintf(stderr, "usb-ohci: %s: qemu_new_timer failed\n", ohci->name);
         /* TODO: Signal unrecoverable error */
         return 0;
     }
 
-    dprintf("usb-ohci: %s: USB Operational\n", ohci->pci_dev.name);
+    dprintf("usb-ohci: %s: USB Operational\n", ohci->name);
 
     ohci_sof(ohci);
 
@@ -813,6 +837,7 @@
 {
     if (ohci->eof_timer)
         qemu_del_timer(ohci->eof_timer);
+    ohci->eof_timer = NULL;
 }
 
 /* Sets a flag in a port status register but only set it if the port is
@@ -854,7 +879,7 @@
 
     if (val != ohci->fi) {
         dprintf("usb-ohci: %s: FrameInterval = 0x%x (%u)\n",
-            ohci->pci_dev.name, ohci->fi, ohci->fi);
+            ohci->name, ohci->fi, ohci->fi);
     }
 
     ohci->fi = val;
@@ -892,13 +917,14 @@
         break;
     case OHCI_USB_SUSPEND:
         ohci_bus_stop(ohci);
-        dprintf("usb-ohci: %s: USB Suspended\n", ohci->pci_dev.name);
+        dprintf("usb-ohci: %s: USB Suspended\n", ohci->name);
         break;
     case OHCI_USB_RESUME:
-        dprintf("usb-ohci: %s: USB Resume\n", ohci->pci_dev.name);
+        dprintf("usb-ohci: %s: USB Resume\n", ohci->name);
         break;
     case OHCI_USB_RESET:
-        dprintf("usb-ohci: %s: USB Reset\n", ohci->pci_dev.name);
+        ohci_reset(ohci);
+        dprintf("usb-ohci: %s: USB Reset\n", ohci->name);
         break;
     }
 }
@@ -1086,6 +1112,19 @@
     case 20: /* HcRhStatus */
         return ohci->rhstatus;
 
+    /* PXA27x specific registers */
+    case 24: /* HcStatus */
+        return ohci->hstatus & ohci->hmask;
+
+    case 25: /* HcHReset */
+        return ohci->hreset;
+
+    case 26: /* HcHInterruptEnable */
+        return ohci->hmask;
+
+    case 27: /* HcHInterruptTest */
+        return ohci->htest;
+
     default:
         fprintf(stderr, "ohci_read: Bad offset %x\n", (int)addr);
         return 0xffffffff;
@@ -1187,6 +1226,24 @@
         ohci_set_hub_status(ohci, val);
         break;
 
+    /* PXA27x specific registers */
+    case 24: /* HcStatus */
+        ohci->hstatus &= ~(val & ohci->hmask);
+
+    case 25: /* HcHReset */
+        ohci->hreset = val & ~OHCI_HRESET_FSBIR;
+        if (val & OHCI_HRESET_FSBIR)
+            ohci_reset(ohci);
+        break;
+
+    case 26: /* HcHInterruptEnable */
+        ohci->hmask = val;
+        break;
+
+    case 27: /* HcHInterruptTest */
+        ohci->htest = val;
+        break;
+
     default:
         fprintf(stderr, "ohci_write: Bad offset %x\n", (int)addr);
         break;
@@ -1207,22 +1264,11 @@
     ohci_mem_write
 };
 
-static void ohci_mapfunc(PCIDevice *pci_dev, int i,
-            uint32_t addr, uint32_t size, int type)
+static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
+            qemu_irq irq, enum ohci_type type, const char *name)
 {
-    OHCIState *ohci = (OHCIState *)pci_dev;
-    ohci->mem_base = addr;
-    cpu_register_physical_memory(addr, size, ohci->mem);
-}
-
-void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn)
-{
-    OHCIState *ohci;
-    int vid = 0x106b;
-    int did = 0x003f;
     int i;
 
-
     if (usb_frame_time == 0) {
 #if OHCI_TIME_WARP
         usb_frame_time = ticks_per_sec;
@@ -1239,8 +1285,43 @@
                 usb_frame_time, usb_bit_time);
     }
 
-    ohci = (OHCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci),
-                                            devfn, NULL, NULL);
+    ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
+    ohci->name = name;
+
+    ohci->irq = irq;
+    ohci->type = type;
+
+    ohci->num_ports = num_ports;
+    for (i = 0; i < num_ports; i++) {
+        qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
+    }
+
+    ohci->async_td = 0;
+    qemu_register_reset(ohci_reset, ohci);
+    ohci_reset(ohci);
+}
+
+typedef struct {
+    PCIDevice pci_dev;
+    OHCIState state;
+} OHCIPCIState;
+
+static void ohci_mapfunc(PCIDevice *pci_dev, int i,
+            uint32_t addr, uint32_t size, int type)
+{
+    OHCIPCIState *ohci = (OHCIPCIState *)pci_dev;
+    ohci->state.mem_base = addr;
+    cpu_register_physical_memory(addr, size, ohci->state.mem);
+}
+
+void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn)
+{
+    OHCIPCIState *ohci;
+    int vid = 0x106b;
+    int did = 0x003f;
+
+    ohci = (OHCIPCIState *)pci_register_device(bus, "OHCI USB", sizeof(*ohci),
+                                               devfn, NULL, NULL);
     if (ohci == NULL) {
         fprintf(stderr, "usb-ohci: Failed to register PCI device\n");
         return;
@@ -1255,16 +1336,21 @@
     ohci->pci_dev.config[0x0b] = 0xc;
     ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
 
-    ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
+    usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
+                  OHCI_TYPE_PCI, ohci->pci_dev.name);
 
     pci_register_io_region((struct PCIDevice *)ohci, 0, 256,
                            PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
+}
 
-    ohci->num_ports = num_ports;
-    for (i = 0; i < num_ports; i++) {
-        qemu_register_usb_port(&ohci->rhport[i].port, ohci, i, ohci_attach);
-    }
+void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
+                       qemu_irq irq)
+{
+    OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
 
-    ohci->async_td = 0;
-    ohci_reset(ohci);
+    usb_ohci_init(ohci, num_ports, devfn, irq,
+                  OHCI_TYPE_PXA, "OHCI USB");
+    ohci->mem_base = base;
+
+    cpu_register_physical_memory(ohci->mem_base, 0x1000, ohci->mem);
 }
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index ccdd30e..8c3cb01 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -1,8 +1,8 @@
 /*
  * USB UHCI controller emulation
- * 
+ *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -26,6 +26,8 @@
 //#define DEBUG
 //#define DEBUG_PACKET
 
+#define UHCI_CMD_FGR      (1 << 4)
+#define UHCI_CMD_EGSM     (1 << 3)
 #define UHCI_CMD_GRESET   (1 << 2)
 #define UHCI_CMD_HCRESET  (1 << 1)
 #define UHCI_CMD_RS       (1 << 0)
@@ -82,7 +84,7 @@
     /* For simplicity of implementation we only allow a single pending USB
        request.  This means all usb traffic on this controller is effectively
        suspended until that transfer completes.  When the transfer completes
-       the next transfer from that queue will be processed.  However 
+       the next transfer from that queue will be processed.  However
        other queues will not be processed until the next frame.  The solution
        is to allow multiple pending requests.  */
     uint32_t async_qh;
@@ -117,7 +119,7 @@
     } else {
         level = 0;
     }
-    pci_set_irq(&s->dev, 3, level);
+    qemu_set_irq(s->dev.irq[3], level);
 }
 
 static void uhci_reset(UHCIState *s)
@@ -199,7 +201,7 @@
 static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
 {
     UHCIState *s = opaque;
-    
+
     addr &= 0x1f;
     switch(addr) {
     case 0x0c:
@@ -228,7 +230,7 @@
 static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
 {
     UHCIState *s = opaque;
-    
+
     addr &= 0x1f;
 #ifdef DEBUG
     printf("uhci writew port=0x%04x val=0x%04x\n", addr, val);
@@ -293,7 +295,7 @@
             dev = port->port.dev;
             if (dev) {
                 /* port reset */
-                if ( (val & UHCI_PORT_RESET) && 
+                if ( (val & UHCI_PORT_RESET) &&
                      !(port->ctrl & UHCI_PORT_RESET) ) {
                     usb_send_msg(dev, USB_MSG_RESET);
                 }
@@ -330,7 +332,7 @@
             UHCIPort *port;
             int n;
             n = (addr >> 1) & 7;
-            if (n >= NB_PORTS) 
+            if (n >= NB_PORTS)
                 goto read_default;
             port = &s->ports[n];
             val = port->ctrl;
@@ -379,6 +381,21 @@
     return val;
 }
 
+/* signal resume if controller suspended */
+static void uhci_resume (void *opaque)
+{
+    UHCIState *s = (UHCIState *)opaque;
+
+    if (!s)
+        return;
+
+    if (s->cmd & UHCI_CMD_EGSM) {
+        s->cmd |= UHCI_CMD_FGR;
+        s->status |= UHCI_STS_RD;
+        uhci_update_irq(s);
+    }
+}
+
 static void uhci_attach(USBPort *port1, USBDevice *dev)
 {
     UHCIState *s = port1->opaque;
@@ -396,6 +413,9 @@
             port->ctrl |= UHCI_PORT_LSDA;
         else
             port->ctrl &= ~UHCI_PORT_LSDA;
+
+        uhci_resume(s);
+
         port->port.dev = dev;
         /* send the attach message */
         usb_send_msg(dev, USB_MSG_ATTACH);
@@ -410,6 +430,9 @@
             port->ctrl &= ~UHCI_PORT_EN;
             port->ctrl |= UHCI_PORT_ENC;
         }
+
+        uhci_resume(s);
+
         dev = port->port.dev;
         if (dev) {
             /* send the detach message */
@@ -487,7 +510,7 @@
     if (td->ctrl & TD_CTRL_IOC) {
         *int_mask |= 0x01;
     }
-    
+
     if (!(td->ctrl & TD_CTRL_ACTIVE))
         return 1;
 
@@ -555,8 +578,11 @@
         td->ctrl &= ~TD_CTRL_ACTIVE;
     if (ret >= 0) {
         td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
-        td->ctrl &= ~TD_CTRL_ACTIVE;
-        if (pid == USB_TOKEN_IN && 
+        /* The NAK bit may have been set by a previous frame, so clear it
+           here.  The docs are somewhat unclear, but win2k relies on this
+           behavior.  */
+        td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);
+        if (pid == USB_TOKEN_IN &&
             (td->ctrl & TD_CTRL_SPD) &&
             len < max_len) {
             *int_mask |= 0x02;
@@ -581,7 +607,7 @@
                     uhci_update_irq(s);
                 }
             }
-            td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | 
+            td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
                 (err << TD_CTRL_ERROR_SHIFT);
             return 1;
         case USB_RET_NAK:
@@ -623,7 +649,7 @@
     le32_to_cpus(&qh.el_link);
     /* Re-process the queue containing the async packet.  */
     while (1) {
-        cpu_physical_memory_read(qh.el_link & ~0xf, 
+        cpu_physical_memory_read(qh.el_link & ~0xf,
                                  (uint8_t *)&td, sizeof(td));
         le32_to_cpus(&td.link);
         le32_to_cpus(&td.ctrl);
@@ -634,8 +660,8 @@
         /* update the status bits of the TD */
         if (old_td_ctrl != td.ctrl) {
             val = cpu_to_le32(td.ctrl);
-            cpu_physical_memory_write((qh.el_link & ~0xf) + 4, 
-                                      (const uint8_t *)&val, 
+            cpu_physical_memory_write((qh.el_link & ~0xf) + 4,
+                                      (const uint8_t *)&val,
                                       sizeof(val));
         }
         if (ret < 0)
@@ -647,8 +673,8 @@
             /* update qh element link */
             qh.el_link = td.link;
             val = cpu_to_le32(qh.el_link);
-            cpu_physical_memory_write((link & ~0xf) + 4, 
-                                      (const uint8_t *)&val, 
+            cpu_physical_memory_write((link & ~0xf) + 4,
+                                      (const uint8_t *)&val,
                                       sizeof(val));
             if (!(qh.el_link & 4))
                 break;
@@ -716,7 +742,7 @@
                 /* TD */
                 if (--cnt == 0)
                     break;
-                cpu_physical_memory_read(qh.el_link & ~0xf, 
+                cpu_physical_memory_read(qh.el_link & ~0xf,
                                          (uint8_t *)&td, sizeof(td));
                 le32_to_cpus(&td.link);
                 le32_to_cpus(&td.ctrl);
@@ -727,8 +753,8 @@
                 /* update the status bits of the TD */
                 if (old_td_ctrl != td.ctrl) {
                     val = cpu_to_le32(td.ctrl);
-                    cpu_physical_memory_write((qh.el_link & ~0xf) + 4, 
-                                              (const uint8_t *)&val, 
+                    cpu_physical_memory_write((qh.el_link & ~0xf) + 4,
+                                              (const uint8_t *)&val,
                                               sizeof(val));
                 }
                 if (ret < 0)
@@ -739,8 +765,8 @@
                     /* update qh element link */
                     qh.el_link = td.link;
                     val = cpu_to_le32(qh.el_link);
-                    cpu_physical_memory_write((link & ~0xf) + 4, 
-                                              (const uint8_t *)&val, 
+                    cpu_physical_memory_write((link & ~0xf) + 4,
+                                              (const uint8_t *)&val,
                                               sizeof(val));
                     if (qh.el_link & 4) {
                         /* depth first */
@@ -766,8 +792,8 @@
                 /* update the status bits of the TD */
                 if (old_td_ctrl != td.ctrl) {
                     val = cpu_to_le32(td.ctrl);
-                    cpu_physical_memory_write((link & ~0xf) + 4, 
-                                              (const uint8_t *)&val, 
+                    cpu_physical_memory_write((link & ~0xf) + 4,
+                                              (const uint8_t *)&val,
                                               sizeof(val));
                 }
                 if (ret < 0)
@@ -794,12 +820,12 @@
         s->async_qh = 0;
     }
     /* prepare the timer for the next frame */
-    expire_time = qemu_get_clock(vm_clock) + 
+    expire_time = qemu_get_clock(vm_clock) +
         (ticks_per_sec / FRAME_TIMER_FREQ);
     qemu_mod_timer(s->frame_timer, expire_time);
 }
 
-static void uhci_map(PCIDevice *pci_dev, int region_num, 
+static void uhci_map(PCIDevice *pci_dev, int region_num,
                     uint32_t addr, uint32_t size, int type)
 {
     UHCIState *s = (UHCIState *)pci_dev;
@@ -812,7 +838,7 @@
     register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
 }
 
-void usb_uhci_init(PCIBus *bus, int devfn)
+void usb_uhci_piix3_init(PCIBus *bus, int devfn)
 {
     UHCIState *s;
     uint8_t *pci_conf;
@@ -833,7 +859,7 @@
     pci_conf[0x0e] = 0x00; // header_type
     pci_conf[0x3d] = 4; // interrupt pin 3
     pci_conf[0x60] = 0x10; // release number
-    
+
     for(i = 0; i < NB_PORTS; i++) {
         qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
     }
@@ -843,8 +869,44 @@
 
     /* Use region 4 for consistency with real hardware.  BSD guests seem
        to rely on this.  */
-    pci_register_io_region(&s->dev, 4, 0x20, 
+    pci_register_io_region(&s->dev, 4, 0x20,
+                           PCI_ADDRESS_SPACE_IO, uhci_map);
+}
+
+void usb_uhci_piix4_init(PCIBus *bus, int devfn)
+{
+    UHCIState *s;
+    uint8_t *pci_conf;
+    int i;
+
+    s = (UHCIState *)pci_register_device(bus,
+                                        "USB-UHCI", sizeof(UHCIState),
+                                        devfn, NULL, NULL);
+    pci_conf = s->dev.config;
+    pci_conf[0x00] = 0x86;
+    pci_conf[0x01] = 0x80;
+    pci_conf[0x02] = 0x12;
+    pci_conf[0x03] = 0x71;
+    pci_conf[0x08] = 0x01; // revision number
+    pci_conf[0x09] = 0x00;
+    pci_conf[0x0a] = 0x03;
+    pci_conf[0x0b] = 0x0c;
+    pci_conf[0x0e] = 0x00; // header_type
+    pci_conf[0x3d] = 4; // interrupt pin 3
+    pci_conf[0x60] = 0x10; // release number
+
+    for(i = 0; i < NB_PORTS; i++) {
+        qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
+    }
+    s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
+
+    uhci_reset(s);
+
+    /* Use region 4 for consistency with real hardware.  BSD guests seem
+       to rely on this.  */
+    pci_register_io_region(&s->dev, 4, 0x20,
                            PCI_ADDRESS_SPACE_IO, uhci_map);
 
     register_savevm("uhci", 0, 1, uhci_save, uhci_load, s);
 }
+
diff --git a/hw/usb-wacom.c b/hw/usb-wacom.c
new file mode 100644
index 0000000..99b8f9e
--- /dev/null
+++ b/hw/usb-wacom.c
@@ -0,0 +1,412 @@
+/*
+ * Wacom PenPartner USB tablet emulation.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Author: Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * Based on hw/usb-hid.c:
+ * Copyright (c) 2005 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+/* Interface requests */
+#define WACOM_GET_REPORT	0x2101
+#define WACOM_SET_REPORT	0x2109
+
+/* HID interface requests */
+#define HID_GET_REPORT		0xa101
+#define HID_GET_IDLE		0xa102
+#define HID_GET_PROTOCOL	0xa103
+#define HID_SET_IDLE		0x210a
+#define HID_SET_PROTOCOL	0x210b
+
+typedef struct USBWacomState {
+    USBDevice dev;
+    QEMUPutMouseEntry *eh_entry;
+    int dx, dy, dz, buttons_state;
+    int x, y;
+    int mouse_grabbed;
+    enum {
+        WACOM_MODE_HID = 1,
+        WACOM_MODE_WACOM = 2,
+    } mode;
+} USBWacomState;
+
+static const uint8_t qemu_wacom_dev_descriptor[] = {
+    0x12,	/*  u8 bLength; */
+    0x01,	/*  u8 bDescriptorType; Device */
+    0x10, 0x10,	/*  u16 bcdUSB; v1.10 */
+
+    0x00,	/*  u8  bDeviceClass; */
+    0x00,	/*  u8  bDeviceSubClass; */
+    0x00,	/*  u8  bDeviceProtocol; [ low/full speeds only ] */
+    0x08,	/*  u8  bMaxPacketSize0; 8 Bytes */
+
+    0x6a, 0x05,	/*  u16 idVendor; */
+    0x00, 0x00,	/*  u16 idProduct; */
+    0x10, 0x42,	/*  u16 bcdDevice */
+
+    0x01,	/*  u8  iManufacturer; */
+    0x02,	/*  u8  iProduct; */
+    0x00,	/*  u8  iSerialNumber; */
+    0x01,	/*  u8  bNumConfigurations; */
+};
+
+static const uint8_t qemu_wacom_config_descriptor[] = {
+    /* one configuration */
+    0x09,	/*  u8  bLength; */
+    0x02,	/*  u8  bDescriptorType; Configuration */
+    0x22, 0x00,	/*  u16 wTotalLength; */
+    0x01,	/*  u8  bNumInterfaces; (1) */
+    0x01,	/*  u8  bConfigurationValue; */
+    0x00,	/*  u8  iConfiguration; */
+    0x80,	/*  u8  bmAttributes;
+				 Bit 7: must be set,
+				     6: Self-powered,
+				     5: Remote wakeup,
+				     4..0: resvd */
+    40,		/*  u8  MaxPower; */
+
+    /* one interface */
+    0x09,	/*  u8  if_bLength; */
+    0x04,	/*  u8  if_bDescriptorType; Interface */
+    0x00,	/*  u8  if_bInterfaceNumber; */
+    0x00,	/*  u8  if_bAlternateSetting; */
+    0x01,	/*  u8  if_bNumEndpoints; */
+    0x03,	/*  u8  if_bInterfaceClass; HID */
+    0x01,	/*  u8  if_bInterfaceSubClass; Boot */
+    0x02,	/*  u8  if_bInterfaceProtocol; [usb1.1 or single tt] */
+    0x00,	/*  u8  if_iInterface; */
+
+    /* HID descriptor */
+    0x09,	/*  u8  bLength; */
+    0x21,	/*  u8  bDescriptorType; */
+    0x01, 0x10,	/*  u16 HID_class */
+    0x00,	/*  u8  country_code */
+    0x01,	/*  u8  num_descriptors */
+    0x22,	/*  u8  type; Report */
+    0x6e, 0x00,	/*  u16 len */
+
+    /* one endpoint (status change endpoint) */
+    0x07,	/*  u8  ep_bLength; */
+    0x05,	/*  u8  ep_bDescriptorType; Endpoint */
+    0x81,	/*  u8  ep_bEndpointAddress; IN Endpoint 1 */
+    0x03,	/*  u8  ep_bmAttributes; Interrupt */
+    0x08, 0x00,	/*  u16 ep_wMaxPacketSize; */
+    0x0a,	/*  u8  ep_bInterval; */
+};
+
+static void usb_mouse_event(void *opaque,
+                            int dx1, int dy1, int dz1, int buttons_state)
+{
+    USBWacomState *s = opaque;
+
+    s->dx += dx1;
+    s->dy += dy1;
+    s->dz += dz1;
+    s->buttons_state = buttons_state;
+}
+
+static void usb_wacom_event(void *opaque,
+                            int x, int y, int dz, int buttons_state)
+{
+    USBWacomState *s = opaque;
+
+    s->x = x;
+    s->y = y;
+    s->dz += dz;
+    s->buttons_state = buttons_state;
+}
+
+static inline int int_clamp(int val, int vmin, int vmax)
+{
+    if (val < vmin)
+        return vmin;
+    else if (val > vmax)
+        return vmax;
+    else
+        return val;
+}
+
+static int usb_mouse_poll(USBWacomState *s, uint8_t *buf, int len)
+{
+    int dx, dy, dz, b, l;
+
+    if (!s->mouse_grabbed) {
+        s->eh_entry = qemu_add_mouse_event_handler(usb_mouse_event, s, 0,
+                        "QEMU PenPartner tablet");
+        s->mouse_grabbed = 1;
+    }
+
+    dx = int_clamp(s->dx, -128, 127);
+    dy = int_clamp(s->dy, -128, 127);
+    dz = int_clamp(s->dz, -128, 127);
+
+    s->dx -= dx;
+    s->dy -= dy;
+    s->dz -= dz;
+
+    b = 0;
+    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+        b |= 0x01;
+    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+        b |= 0x02;
+    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+        b |= 0x04;
+
+    buf[0] = b;
+    buf[1] = dx;
+    buf[2] = dy;
+    l = 3;
+    if (len >= 4) {
+        buf[3] = dz;
+        l = 4;
+    }
+    return l;
+}
+
+static int usb_wacom_poll(USBWacomState *s, uint8_t *buf, int len)
+{
+    int b;
+
+    if (!s->mouse_grabbed) {
+        s->eh_entry = qemu_add_mouse_event_handler(usb_wacom_event, s, 1,
+                        "QEMU PenPartner tablet");
+        s->mouse_grabbed = 1;
+    }
+
+    b = 0;
+    if (s->buttons_state & MOUSE_EVENT_LBUTTON)
+        b |= 0x01;
+    if (s->buttons_state & MOUSE_EVENT_RBUTTON)
+        b |= 0x02;
+    if (s->buttons_state & MOUSE_EVENT_MBUTTON)
+        b |= 0x04;
+
+    if (len < 7)
+        return 0;
+
+    buf[0] = s->mode;
+    buf[5] = 0x00;
+    if (b) {
+        buf[1] = s->x & 0xff;
+        buf[2] = s->x >> 8;
+        buf[3] = s->y & 0xff;
+        buf[4] = s->y >> 8;
+        buf[6] = 0;
+    } else {
+        buf[1] = 0;
+        buf[2] = 0;
+        buf[3] = 0;
+        buf[4] = 0;
+        buf[6] = (unsigned char) -127;
+    }
+
+    return 7;
+}
+
+static void usb_wacom_handle_reset(USBDevice *dev)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+
+    s->dx = 0;
+    s->dy = 0;
+    s->dz = 0;
+    s->x = 0;
+    s->y = 0;
+    s->buttons_state = 0;
+    s->mode = WACOM_MODE_HID;
+}
+
+static int usb_wacom_handle_control(USBDevice *dev, int request, int value,
+                                    int index, int length, uint8_t *data)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+    int ret = 0;
+
+    switch (request) {
+    case DeviceRequest | USB_REQ_GET_STATUS:
+        data[0] = (1 << USB_DEVICE_SELF_POWERED) |
+            (dev->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP);
+        data[1] = 0x00;
+        ret = 2;
+        break;
+    case DeviceOutRequest | USB_REQ_CLEAR_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 0;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_FEATURE:
+        if (value == USB_DEVICE_REMOTE_WAKEUP) {
+            dev->remote_wakeup = 1;
+        } else {
+            goto fail;
+        }
+        ret = 0;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_ADDRESS:
+        dev->addr = value;
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+        switch (value >> 8) {
+        case USB_DT_DEVICE:
+            memcpy(data, qemu_wacom_dev_descriptor,
+                   sizeof(qemu_wacom_dev_descriptor));
+            ret = sizeof(qemu_wacom_dev_descriptor);
+            break;
+        case USB_DT_CONFIG:
+       	    memcpy(data, qemu_wacom_config_descriptor,
+                   sizeof(qemu_wacom_config_descriptor));
+            ret = sizeof(qemu_wacom_config_descriptor);
+            break;
+        case USB_DT_STRING:
+            switch (value & 0xff) {
+            case 0:
+                /* language ids */
+                data[0] = 4;
+                data[1] = 3;
+                data[2] = 0x09;
+                data[3] = 0x04;
+                ret = 4;
+                break;
+            case 1:
+                /* serial number */
+                ret = set_usb_string(data, "1");
+                break;
+            case 2:
+		ret = set_usb_string(data, "Wacom PenPartner");
+                break;
+            case 3:
+                /* vendor description */
+                ret = set_usb_string(data, "QEMU " QEMU_VERSION);
+                break;
+            case 4:
+                ret = set_usb_string(data, "Wacom Tablet");
+                break;
+            case 5:
+                ret = set_usb_string(data, "Endpoint1 Interrupt Pipe");
+                break;
+            default:
+                goto fail;
+            }
+            break;
+        default:
+            goto fail;
+        }
+        break;
+    case DeviceRequest | USB_REQ_GET_CONFIGURATION:
+        data[0] = 1;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_CONFIGURATION:
+        ret = 0;
+        break;
+    case DeviceRequest | USB_REQ_GET_INTERFACE:
+        data[0] = 0;
+        ret = 1;
+        break;
+    case DeviceOutRequest | USB_REQ_SET_INTERFACE:
+        ret = 0;
+        break;
+    case WACOM_SET_REPORT:
+        qemu_remove_mouse_event_handler(s->eh_entry);
+        s->mouse_grabbed = 0;
+        s->mode = data[0];
+        ret = 0;
+        break;
+    case WACOM_GET_REPORT:
+        data[0] = 0;
+        data[1] = s->mode;
+        ret = 2;
+        break;
+    /* USB HID requests */
+    case HID_GET_REPORT:
+        if (s->mode == WACOM_MODE_HID)
+            ret = usb_mouse_poll(s, data, length);
+        else if (s->mode == WACOM_MODE_WACOM)
+            ret = usb_wacom_poll(s, data, length);
+        break;
+    case HID_SET_IDLE:
+        ret = 0;
+        break;
+    default:
+    fail:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static int usb_wacom_handle_data(USBDevice *dev, USBPacket *p)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+    int ret = 0;
+
+    switch (p->pid) {
+    case USB_TOKEN_IN:
+        if (p->devep == 1) {
+            if (s->mode == WACOM_MODE_HID)
+                ret = usb_mouse_poll(s, p->data, p->len);
+            else if (s->mode == WACOM_MODE_WACOM)
+                ret = usb_wacom_poll(s, p->data, p->len);
+            break;
+        }
+        /* Fall through.  */
+    case USB_TOKEN_OUT:
+    default:
+        ret = USB_RET_STALL;
+        break;
+    }
+    return ret;
+}
+
+static void usb_wacom_handle_destroy(USBDevice *dev)
+{
+    USBWacomState *s = (USBWacomState *) dev;
+
+    qemu_remove_mouse_event_handler(s->eh_entry);
+    qemu_free(s);
+}
+
+USBDevice *usb_wacom_init(void)
+{
+    USBWacomState *s;
+
+    s = qemu_mallocz(sizeof(USBWacomState));
+    if (!s)
+        return NULL;
+    s->dev.speed = USB_SPEED_FULL;
+    s->dev.handle_packet = usb_generic_handle_packet;
+
+    s->dev.handle_reset = usb_wacom_handle_reset;
+    s->dev.handle_control = usb_wacom_handle_control;
+    s->dev.handle_data = usb_wacom_handle_data;
+    s->dev.handle_destroy = usb_wacom_handle_destroy;
+
+    pstrcpy(s->dev.devname, sizeof(s->dev.devname),
+            "QEMU PenPartner Tablet");
+
+    return (USBDevice *) s;
+}
diff --git a/hw/usb.c b/hw/usb.c
index efbc6db..75e5a80 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -2,7 +2,7 @@
  * QEMU USB emulation
  *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -31,7 +31,7 @@
 /**********************/
 /* generic USB device helpers (you are not forced to use them when
    writing your USB device driver, but they help handling the
-   protocol) 
+   protocol)
 */
 
 #define SETUP_STATE_IDLE 0
@@ -66,7 +66,7 @@
         s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6];
         s->setup_index = 0;
         if (s->setup_buf[0] & USB_DIR_IN) {
-            ret = s->handle_control(s, 
+            ret = s->handle_control(s,
                                     (s->setup_buf[0] << 8) | s->setup_buf[1],
                                     (s->setup_buf[3] << 8) | s->setup_buf[2],
                                     (s->setup_buf[5] << 8) | s->setup_buf[4],
@@ -93,7 +93,7 @@
             case SETUP_STATE_ACK:
                 if (!(s->setup_buf[0] & USB_DIR_IN)) {
                     s->setup_state = SETUP_STATE_IDLE;
-                    ret = s->handle_control(s, 
+                    ret = s->handle_control(s,
                                       (s->setup_buf[0] << 8) | s->setup_buf[1],
                                       (s->setup_buf[3] << 8) | s->setup_buf[2],
                                       (s->setup_buf[5] << 8) | s->setup_buf[4],
@@ -140,7 +140,7 @@
                     s->setup_state = SETUP_STATE_IDLE;
                     /* transfer OK */
                 } else {
-                    /* ignore additionnal output */
+                    /* ignore additional output */
                 }
                 break;
             case SETUP_STATE_DATA:
diff --git a/hw/usb.h b/hw/usb.h
index ed8890e..c5d24f1 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -1,8 +1,8 @@
 /*
  * QEMU USB API
- * 
+ *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -30,7 +30,7 @@
 #define USB_MSG_DETACH   0x101
 #define USB_MSG_RESET    0x102
 
-#define USB_RET_NODEV  (-1) 
+#define USB_RET_NODEV  (-1)
 #define USB_RET_NAK    (-2)
 #define USB_RET_STALL  (-3)
 #define USB_RET_BABBLE (-4)
@@ -119,7 +119,7 @@
     void (*handle_destroy)(USBDevice *dev);
 
     int speed;
-    
+
     /* The following fields are used by the generic USB device
        layer. They are here just to avoid creating a new structure for
        them. */
@@ -129,7 +129,7 @@
     int (*handle_data)(USBDevice *dev, USBPacket *p);
     uint8_t addr;
     char devname[32];
-    
+
     int state;
     uint8_t setup_buf[8];
     uint8_t data_buf[1024];
@@ -164,7 +164,7 @@
     USBCallback *complete_cb;
     void *complete_opaque;
     USBCallback *cancel_cb;
-    void * *cancel_opaque;
+    void *cancel_opaque;
 };
 
 /* Defer completion of a USB packet.  The hadle_packet routine should then
@@ -203,10 +203,13 @@
 USBDevice *usb_hub_init(int nb_ports);
 
 /* usb-uhci.c */
-void usb_uhci_init(PCIBus *bus, int devfn);
+void usb_uhci_piix3_init(PCIBus *bus, int devfn);
+void usb_uhci_piix4_init(PCIBus *bus, int devfn);
 
 /* usb-ohci.c */
-void usb_ohci_init(struct PCIBus *bus, int num_ports, int devfn);
+void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn);
+void usb_ohci_init_pxa(target_phys_addr_t base, int num_ports, int devfn,
+                       qemu_irq irq);
 
 /* usb-linux.c */
 USBDevice *usb_host_device_open(const char *devname);
@@ -215,6 +218,10 @@
 /* usb-hid.c */
 USBDevice *usb_mouse_init(void);
 USBDevice *usb_tablet_init(void);
+USBDevice *usb_keyboard_init(void);
 
 /* usb-msd.c */
 USBDevice *usb_msd_init(const char *filename);
+
+/* usb-wacom.c */
+USBDevice *usb_wacom_init(void);
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
index 32854c2..68f18ef 100644
--- a/hw/versatile_pci.c
+++ b/hw/versatile_pci.c
@@ -1,4 +1,4 @@
-/* 
+/*
  * ARM Versatile/PB PCI host controller
  *
  * Copyright (c) 2006 CodeSourcery.
@@ -84,12 +84,12 @@
     return irq_num;
 }
 
-static void pci_vpb_set_irq(void *pic, int irq_num, int level)
+static void pci_vpb_set_irq(qemu_irq *pic, int irq_num, int level)
 {
-    pic_set_irq_new(pic, pci_vpb_irq + irq_num, level);
+    qemu_set_irq(pic[pci_vpb_irq + irq_num], level);
 }
 
-PCIBus *pci_vpb_init(void *pic, int irq, int realview)
+PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview)
 {
     PCIBus *s;
     PCIDevice *d;
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
index bc42472..2e3dedd 100644
--- a/hw/versatilepb.c
+++ b/hw/versatilepb.c
@@ -1,7 +1,7 @@
-/* 
+/*
  * ARM Versatile Platform/Application Baseboard System emulation.
  *
- * Copyright (c) 2005-2006 CodeSourcery.
+ * Copyright (c) 2005-2007 CodeSourcery.
  * Written by Paul Brook
  *
  * This code is licenced under the GPL.
@@ -14,12 +14,11 @@
 
 typedef struct vpb_sic_state
 {
-  arm_pic_handler handler;
   uint32_t base;
   uint32_t level;
   uint32_t mask;
   uint32_t pic_enable;
-  void *parent;
+  qemu_irq *parent;
   int irq;
 } vpb_sic_state;
 
@@ -28,7 +27,7 @@
     uint32_t flags;
 
     flags = s->level & s->mask;
-    pic_set_irq_new(s->parent, s->irq, flags != 0);
+    qemu_set_irq(s->parent[s->irq], flags != 0);
 }
 
 static void vpb_sic_update_pic(vpb_sic_state *s)
@@ -40,7 +39,7 @@
         mask = 1u << i;
         if (!(s->pic_enable & mask))
             continue;
-        pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
+        qemu_set_irq(s->parent[i], (s->level & mask) != 0);
     }
 }
 
@@ -52,7 +51,7 @@
     else
         s->level &= ~(1u << irq);
     if (s->pic_enable & (1u << irq))
-        pic_set_irq_new(s->parent, irq, level);
+        qemu_set_irq(s->parent[irq], level);
     vpb_sic_update(s);
 }
 
@@ -126,23 +125,24 @@
    vpb_sic_write
 };
 
-static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
+static qemu_irq *vpb_sic_init(uint32_t base, qemu_irq *parent, int irq)
 {
     vpb_sic_state *s;
+    qemu_irq *qi;
     int iomemtype;
 
     s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
     if (!s)
         return NULL;
-    s->handler = vpb_sic_set_irq;
+    qi = qemu_allocate_irqs(vpb_sic_set_irq, s, 32);
     s->base = base;
     s->parent = parent;
     s->irq = irq;
     iomemtype = cpu_register_io_memory(0, vpb_sic_readfn,
                                        vpb_sic_writefn, s);
-    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+    cpu_register_physical_memory(base, 0x00001000, iomemtype);
     /* ??? Save/restore.  */
-    return s;
+    return qi;
 }
 
 /* Board init.  */
@@ -154,11 +154,12 @@
 static void versatile_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, int board_id)
+                     const char *initrd_filename, const char *cpu_model,
+                     int board_id)
 {
     CPUState *env;
-    void *pic;
-    void *sic;
+    qemu_irq *pic;
+    qemu_irq *sic;
     void *scsi_hba;
     PCIBus *pci_bus;
     NICInfo *nd;
@@ -166,17 +167,19 @@
     int done_smc = 0;
 
     env = cpu_init();
-    cpu_arm_set_model(env, ARM_CPUID_ARM926);
+    if (!cpu_model)
+        cpu_model = "arm926";
+    cpu_arm_set_model(env, cpu_model);
     /* ??? RAM shoud repeat to fill physical memory space.  */
     /* SDRAM at address zero.  */
     cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
 
     arm_sysctl_init(0x10000000, 0x41007004);
     pic = arm_pic_init_cpu(env);
-    pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
+    pic = pl190_init(0x10140000, pic[0], pic[1]);
     sic = vpb_sic_init(0x10003000, pic, 31);
-    pl050_init(0x10006000, sic, 3, 0);
-    pl050_init(0x10007000, sic, 4, 1);
+    pl050_init(0x10006000, sic[3], 0);
+    pl050_init(0x10007000, sic[4], 1);
 
     pci_bus = pci_vpb_init(sic, 27, 0);
     /* The Versatile PCI bridge does not provide access to PCI IO space,
@@ -186,13 +189,13 @@
         if (!nd->model)
             nd->model = done_smc ? "rtl8139" : "smc91c111";
         if (strcmp(nd->model, "smc91c111") == 0) {
-            smc91c111_init(nd, 0x10010000, sic, 25);
+            smc91c111_init(nd, 0x10010000, sic[25]);
         } else {
             pci_nic_init(pci_bus, nd, -1);
         }
     }
     if (usb_enabled) {
-        usb_ohci_init(pci_bus, 3, -1);
+        usb_ohci_init_pci(pci_bus, 3, -1);
     }
     scsi_hba = lsi_scsi_init(pci_bus, -1);
     for (n = 0; n < MAX_DISKS; n++) {
@@ -201,18 +204,27 @@
         }
     }
 
-    pl011_init(0x101f1000, pic, 12, serial_hds[0]);
-    pl011_init(0x101f2000, pic, 13, serial_hds[1]);
-    pl011_init(0x101f3000, pic, 14, serial_hds[2]);
-    pl011_init(0x10009000, sic, 6, serial_hds[3]);
+    pl011_init(0x101f1000, pic[12], serial_hds[0]);
+    pl011_init(0x101f2000, pic[13], serial_hds[1]);
+    pl011_init(0x101f3000, pic[14], serial_hds[2]);
+    pl011_init(0x10009000, sic[6], serial_hds[3]);
 
-    pl080_init(0x10130000, pic, 17, 8);
-    sp804_init(0x101e2000, pic, 4);
-    sp804_init(0x101e3000, pic, 5);
+    pl080_init(0x10130000, pic[17], 8);
+    sp804_init(0x101e2000, pic[4]);
+    sp804_init(0x101e3000, pic[5]);
 
     /* The versatile/PB actually has a modified Color LCD controller
        that includes hardware cursor support from the PL111.  */
-    pl110_init(ds, 0x10120000, pic, 16, 1);
+    pl110_init(ds, 0x10120000, pic[16], 1);
+
+    pl181_init(0x10005000, sd_bdrv, sic[22], sic[1]);
+#if 0
+    /* Disabled because there's no way of specifying a block device.  */
+    pl181_init(0x1000b000, NULL, sic, 23, 2);
+#endif
+
+    /* Add PL031 Real Time Clock. */
+    pl031_init(0x101e8000,pic[10]);
 
     /* Memory map for Versatile/PB:  */
     /* 0x10000000 System registers.  */
@@ -220,13 +232,13 @@
     /* 0x10002000 Serial bus interface.  */
     /*  0x10003000 Secondary interrupt controller.  */
     /* 0x10004000 AACI (audio).  */
-    /* 0x10005000 MMCI0.  */
+    /*  0x10005000 MMCI0.  */
     /*  0x10006000 KMI0 (keyboard).  */
     /*  0x10007000 KMI1 (mouse).  */
     /* 0x10008000 Character LCD Interface.  */
     /*  0x10009000 UART3.  */
     /* 0x1000a000 Smart card 1.  */
-    /* 0x1000b000 MMCI1.  */
+    /*  0x1000b000 MMCI1.  */
     /*  0x10010000 Ethernet.  */
     /* 0x10020000 USB.  */
     /* 0x10100000 SSMC.  */
@@ -251,29 +263,29 @@
     /* 0x101f4000 SSPI.  */
 
     arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
-                    initrd_filename, board_id);
+                    initrd_filename, board_id, 0x0);
 }
 
 static void vpb_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 *initrd_filename, const char *cpu_model)
 {
     versatile_init(ram_size, vga_ram_size, boot_device,
                    ds, fd_filename, snapshot,
                    kernel_filename, kernel_cmdline,
-                   initrd_filename, 0x183);
+                   initrd_filename, cpu_model, 0x183);
 }
 
 static void vab_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 *initrd_filename, const char *cpu_model)
 {
     versatile_init(ram_size, vga_ram_size, boot_device,
                    ds, fd_filename, snapshot,
                    kernel_filename, kernel_cmdline,
-                   initrd_filename, 0x25e);
+                   initrd_filename, cpu_model, 0x25e);
 }
 
 QEMUMachine versatilepb_machine = {
diff --git a/hw/vga.c b/hw/vga.c
index b01fe45..b309369 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -1,8 +1,8 @@
 /*
  * QEMU VGA Emulator.
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -23,6 +23,7 @@
  */
 #include "vl.h"
 #include "vga_int.h"
+#include "pixel_ops.h"
 
 #include <sys/mman.h>
 
@@ -167,7 +168,7 @@
             break;
         case 0x3c1:
             index = s->ar_index & 0x1f;
-            if (index < 21) 
+            if (index < 21)
                 val = s->ar[index];
             else
                 val = 0;
@@ -348,7 +349,7 @@
         case 0x09:
         case 0x0c:
         case 0x0d:
-        case 0x12: /* veritcal display end */
+        case 0x12: /* vertical display end */
             s->cr[s->cr_index] = val;
             break;
         default:
@@ -391,11 +392,11 @@
                 val = VBE_DISPI_MAX_BPP;
                 break;
             default:
-                val = s->vbe_regs[s->vbe_index]; 
+                val = s->vbe_regs[s->vbe_index];
                 break;
             }
         } else {
-            val = s->vbe_regs[s->vbe_index]; 
+            val = s->vbe_regs[s->vbe_index];
         }
     } else {
         val = 0;
@@ -443,7 +444,7 @@
         case VBE_DISPI_INDEX_BPP:
             if (val == 0)
                 val = 8;
-            if (val == 4 || val == 8 || val == 15 || 
+            if (val == 4 || val == 8 || val == 15 ||
                 val == 16 || val == 24 || val == 32) {
                 s->vbe_regs[s->vbe_index] = val;
             }
@@ -462,26 +463,26 @@
                 !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
                 int h, shift_control;
 
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = 
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
                     s->vbe_regs[VBE_DISPI_INDEX_XRES];
-                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = 
+                s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
                     s->vbe_regs[VBE_DISPI_INDEX_YRES];
                 s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
                 s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
-                
+
                 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
                     s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
                 else
-                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] * 
+                    s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
                         ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
                 s->vbe_start_addr = 0;
 
                 /* clear the screen (should be done in BIOS) */
                 if (!(val & VBE_DISPI_NOCLEARMEM)) {
-                    memset(s->vram_ptr, 0, 
+                    memset(s->vram_ptr, 0,
                            s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
                 }
-                
+
                 /* we initialize the VGA graphic mode (should be done
                    in BIOS) */
                 s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
@@ -492,13 +493,13 @@
                 /* height (only meaningful if < 1024) */
                 h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
                 s->cr[0x12] = h;
-                s->cr[0x07] = (s->cr[0x07] & ~0x42) | 
+                s->cr[0x07] = (s->cr[0x07] & ~0x42) |
                     ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
                 /* line compare to 1023 */
                 s->cr[0x18] = 0xff;
                 s->cr[0x07] |= 0x10;
                 s->cr[0x09] |= 0x40;
-                
+
                 if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
                     shift_control = 0;
                     s->sr[0x01] &= ~8; /* no double line */
@@ -563,7 +564,7 @@
     VGAState *s = opaque;
     int memory_map_mode, plane;
     uint32_t ret;
-    
+
     /* convert to VGA memory offset */
     memory_map_mode = (s->gr[6] >> 2) & 3;
     addr &= 0x1ffff;
@@ -587,7 +588,7 @@
             return 0xff;
         break;
     }
-    
+
     if (s->sr[4] & 0x08) {
         /* chain 4 mode : simplest access */
         ret = s->vram_ptr[addr];
@@ -677,7 +678,7 @@
             return;
         break;
     }
-    
+
     if (s->sr[4] & 0x08) {
         /* chain 4 mode : simplest access */
         plane = addr & 3;
@@ -768,11 +769,11 @@
         mask = s->sr[2];
         s->plane_updated |= mask; /* only used to detect font change */
         write_mask = mask16[mask];
-        ((uint32_t *)s->vram_ptr)[addr] = 
-            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) | 
+        ((uint32_t *)s->vram_ptr)[addr] =
+            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
             (val & write_mask);
 #ifdef DEBUG_VGA_MEM
-            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n", 
+            printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
                    addr * 4, write_mask, val);
 #endif
             cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
@@ -809,42 +810,25 @@
                              const uint8_t *font_ptr, int h,
                              uint32_t fgcol, uint32_t bgcol);
 typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
-                                  const uint8_t *font_ptr, int h, 
+                                  const uint8_t *font_ptr, int h,
                                   uint32_t fgcol, uint32_t bgcol, int dup9);
-typedef void vga_draw_line_func(VGAState *s1, uint8_t *d, 
+typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
                                 const uint8_t *s, int width);
 
-static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
-{
-    return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
-}
-
-static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
-{
-    return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
-}
-
-static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
-{
-    return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
-}
-
-static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
-{
-    return (r << 16) | (g << 8) | b;
-}
-
-static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b)
-{
-    return (b << 16) | (g << 8) | r;
-}
-
 #define DEPTH 8
 #include "vga_template.h"
 
 #define DEPTH 15
 #include "vga_template.h"
 
+#define BGR_FORMAT
+#define DEPTH 15
+#include "vga_template.h"
+
+#define DEPTH 16
+#include "vga_template.h"
+
+#define BGR_FORMAT
 #define DEPTH 16
 #include "vga_template.h"
 
@@ -872,6 +856,15 @@
     return col;
 }
 
+static unsigned int rgb_to_pixel15bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel15bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
 static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
 {
     unsigned int col;
@@ -880,6 +873,15 @@
     return col;
 }
 
+static unsigned int rgb_to_pixel16bgr_dup(unsigned int r, unsigned int g,
+                                          unsigned int b)
+{
+    unsigned int col;
+    col = rgb_to_pixel16bgr(r, g, b);
+    col |= col << 16;
+    return col;
+}
+
 static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
 {
     unsigned int col;
@@ -909,8 +911,8 @@
         else
             v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
         v = v * 3;
-        col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
-                              c6_to_8(s->palette[v + 1]), 
+        col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                              c6_to_8(s->palette[v + 1]),
                               c6_to_8(s->palette[v + 2]));
         if (col != palette[i]) {
             full_update = 1;
@@ -931,12 +933,12 @@
     v = 0;
     for(i = 0; i < 256; i++) {
         if (s->dac_8bit) {
-          col = s->rgb_to_pixel(s->palette[v], 
-                                s->palette[v + 1], 
+          col = s->rgb_to_pixel(s->palette[v],
+                                s->palette[v + 1],
                                 s->palette[v + 2]);
         } else {
-          col = s->rgb_to_pixel(c6_to_8(s->palette[v]), 
-                                c6_to_8(s->palette[v + 1]), 
+          col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
+                                c6_to_8(s->palette[v + 1]),
                                 c6_to_8(s->palette[v + 2]));
         }
         if (col != palette[i]) {
@@ -948,8 +950,8 @@
     return full_update;
 }
 
-static void vga_get_offsets(VGAState *s, 
-                            uint32_t *pline_offset, 
+static void vga_get_offsets(VGAState *s,
+                            uint32_t *pline_offset,
                             uint32_t *pstart_addr,
                             uint32_t *pline_compare)
 {
@@ -961,7 +963,7 @@
         line_compare = 65535;
     } else
 #endif
-    {  
+    {
         /* compute line_offset in bytes */
         line_offset = s->cr[0x13];
         line_offset <<= 3;
@@ -970,7 +972,7 @@
         start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
 
         /* line compare */
-        line_compare = s->cr[0x18] | 
+        line_compare = s->cr[0x18] |
             ((s->cr[0x07] & 0x10) << 4) |
             ((s->cr[0x09] & 0x40) << 3);
     }
@@ -984,7 +986,7 @@
 {
     int full_update;
     uint32_t start_addr, line_offset, line_compare;
-    
+
     full_update = 0;
 
     s->get_offsets(s, &line_offset, &start_addr, &line_compare);
@@ -1000,7 +1002,7 @@
     return full_update;
 }
 
-#define NB_DEPTHS 5
+#define NB_DEPTHS 7
 
 static inline int get_depth_index(DisplayState *s)
 {
@@ -1009,9 +1011,15 @@
     case 8:
         return 0;
     case 15:
-        return 1;
+        if (s->bgr)
+            return 5;
+        else
+            return 1;
     case 16:
-        return 2;
+        if (s->bgr)
+            return 6;
+        else
+            return 2;
     case 32:
         if (s->bgr)
             return 4;
@@ -1026,6 +1034,8 @@
     vga_draw_glyph8_16,
     vga_draw_glyph8_32,
     vga_draw_glyph8_32,
+    vga_draw_glyph8_16,
+    vga_draw_glyph8_16,
 };
 
 static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
@@ -1034,6 +1044,8 @@
     vga_draw_glyph16_16,
     vga_draw_glyph16_32,
     vga_draw_glyph16_32,
+    vga_draw_glyph16_16,
+    vga_draw_glyph16_16,
 };
 
 static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
@@ -1042,8 +1054,10 @@
     vga_draw_glyph9_16,
     vga_draw_glyph9_32,
     vga_draw_glyph9_32,
+    vga_draw_glyph9_16,
+    vga_draw_glyph9_16,
 };
-    
+
 static const uint8_t cursor_glyph[32 * 4] = {
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
@@ -1061,13 +1075,13 @@
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};    
+};
 
-/* 
- * Text mode update 
+/*
+ * Text mode update
  * Missing:
  * - double scan
- * - double width 
+ * - double width
  * - underline
  * - flashing
  */
@@ -1086,7 +1100,7 @@
 
     full_update |= update_palette16(s);
     palette = s->last_palette;
-    
+
     /* compute font data address (in plane 2) */
     v = s->sr[3];
     offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
@@ -1126,8 +1140,8 @@
         /* ugly hack for CGA 160x100x16 - explain me the logic */
         height = 100;
     } else {
-        height = s->cr[0x12] | 
-            ((s->cr[0x07] & 0x02) << 7) | 
+        height = s->cr[0x12] |
+            ((s->cr[0x07] & 0x02) << 7) |
             ((s->cr[0x07] & 0x40) << 3);
         height = (height + 1) / cheight;
     }
@@ -1162,14 +1176,14 @@
         s->cursor_end = s->cr[0xb];
     }
     cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
-    
+
     depth_index = get_depth_index(s->ds);
     if (cw == 16)
         vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
     else
         vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
     vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
-    
+
     dest = s->ds->data;
     linesize = s->ds->linesize;
     ch_attr_ptr = s->last_ch_attr;
@@ -1198,13 +1212,13 @@
                 bgcol = palette[cattr >> 4];
                 fgcol = palette[cattr & 0x0f];
                 if (cw != 9) {
-                    vga_draw_glyph8(d1, linesize, 
+                    vga_draw_glyph8(d1, linesize,
                                     font_ptr, cheight, fgcol, bgcol);
                 } else {
                     dup9 = 0;
                     if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
                         dup9 = 1;
-                    vga_draw_glyph9(d1, linesize, 
+                    vga_draw_glyph9(d1, linesize,
                                     font_ptr, cheight, fgcol, bgcol, dup9);
                 }
                 if (src == cursor_ptr &&
@@ -1220,10 +1234,10 @@
                         h = line_last - line_start + 1;
                         d = d1 + linesize * line_start;
                         if (cw != 9) {
-                            vga_draw_glyph8(d, linesize, 
+                            vga_draw_glyph8(d, linesize,
                                             cursor_glyph, h, fgcol, bgcol);
                         } else {
-                            vga_draw_glyph9(d, linesize, 
+                            vga_draw_glyph9(d, linesize,
                                             cursor_glyph, h, fgcol, bgcol, 1);
                         }
                     }
@@ -1234,7 +1248,7 @@
             ch_attr_ptr++;
         }
         if (cx_max != -1) {
-            dpy_update(s->ds, cx_min * cw, cy * cheight, 
+            dpy_update(s->ds, cx_min * cw, cy * cheight,
                        (cx_max - cx_min + 1) * cw, cheight);
         }
         dest += linesize * cheight;
@@ -1262,60 +1276,80 @@
     vga_draw_line2_16,
     vga_draw_line2_32,
     vga_draw_line2_32,
+    vga_draw_line2_16,
+    vga_draw_line2_16,
 
     vga_draw_line2d2_8,
     vga_draw_line2d2_16,
     vga_draw_line2d2_16,
     vga_draw_line2d2_32,
     vga_draw_line2d2_32,
+    vga_draw_line2d2_16,
+    vga_draw_line2d2_16,
 
     vga_draw_line4_8,
     vga_draw_line4_16,
     vga_draw_line4_16,
     vga_draw_line4_32,
     vga_draw_line4_32,
+    vga_draw_line4_16,
+    vga_draw_line4_16,
 
     vga_draw_line4d2_8,
     vga_draw_line4d2_16,
     vga_draw_line4d2_16,
     vga_draw_line4d2_32,
     vga_draw_line4d2_32,
+    vga_draw_line4d2_16,
+    vga_draw_line4d2_16,
 
     vga_draw_line8d2_8,
     vga_draw_line8d2_16,
     vga_draw_line8d2_16,
     vga_draw_line8d2_32,
     vga_draw_line8d2_32,
+    vga_draw_line8d2_16,
+    vga_draw_line8d2_16,
 
     vga_draw_line8_8,
     vga_draw_line8_16,
     vga_draw_line8_16,
     vga_draw_line8_32,
     vga_draw_line8_32,
+    vga_draw_line8_16,
+    vga_draw_line8_16,
 
     vga_draw_line15_8,
     vga_draw_line15_15,
     vga_draw_line15_16,
     vga_draw_line15_32,
     vga_draw_line15_32bgr,
+    vga_draw_line15_15bgr,
+    vga_draw_line15_16bgr,
 
     vga_draw_line16_8,
     vga_draw_line16_15,
     vga_draw_line16_16,
     vga_draw_line16_32,
     vga_draw_line16_32bgr,
+    vga_draw_line16_15bgr,
+    vga_draw_line16_16bgr,
 
     vga_draw_line24_8,
     vga_draw_line24_15,
     vga_draw_line24_16,
     vga_draw_line24_32,
     vga_draw_line24_32bgr,
+    vga_draw_line24_15bgr,
+    vga_draw_line24_16bgr,
 
     vga_draw_line32_8,
     vga_draw_line32_15,
     vga_draw_line32_16,
     vga_draw_line32_32,
     vga_draw_line32_32bgr,
+    vga_draw_line32_15bgr,
+    vga_draw_line32_16bgr,
 };
 
 typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
@@ -1326,6 +1360,8 @@
     rgb_to_pixel16_dup,
     rgb_to_pixel32_dup,
     rgb_to_pixel32bgr_dup,
+    rgb_to_pixel15bgr_dup,
+    rgb_to_pixel16bgr_dup,
 };
 
 static int vga_get_bpp(VGAState *s)
@@ -1334,7 +1370,7 @@
 #ifdef CONFIG_BOCHS_VBE
     if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
         ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
-    } else 
+    } else
 #endif
     {
         ret = 0;
@@ -1345,17 +1381,17 @@
 static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
 {
     int width, height;
-    
+
 #ifdef CONFIG_BOCHS_VBE
     if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
         width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
         height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
-    } else 
+    } else
 #endif
     {
         width = (s->cr[0x01] + 1) * 8;
-        height = s->cr[0x12] | 
-            ((s->cr[0x07] & 0x02) << 7) | 
+        height = s->cr[0x12] |
+            ((s->cr[0x07] & 0x02) << 7) |
             ((s->cr[0x07] & 0x40) << 3);
         height = (height + 1);
     }
@@ -1395,7 +1431,7 @@
 extern int kvm_allowed;
 #endif
 
-/* 
+/*
  * graphic modes
  */
 static void vga_draw_graphic(VGAState *s, int full_update)
@@ -1407,7 +1443,7 @@
     uint32_t v, addr1, addr;
     long page0, page1, page_min, page_max;
     vga_draw_line_func *vga_draw_line;
-    
+
 #ifdef USE_KVM
 
     /* HACK ALERT */
@@ -1443,7 +1479,7 @@
         s->shift_control = shift_control;
         s->double_scan = double_scan;
     }
-    
+
     if (shift_control == 0) {
         full_update |= update_palette16(s);
         if (s->sr[0x01] & 8) {
@@ -1498,7 +1534,7 @@
     }
     if (s->cursor_invalidate)
         s->cursor_invalidate(s);
-    
+
     line_offset = s->line_offset;
 #if 0
     printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
@@ -1525,7 +1561,7 @@
         }
         page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
         page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
-        update = full_update | 
+        update = full_update |
             cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
             cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
 #ifdef USE_KVM
@@ -1536,7 +1572,7 @@
 #endif
         if ((page1 - page0) > TARGET_PAGE_SIZE) {
             /* if wide line, can use another page */
-            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE, 
+            update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
                                                     VGA_DIRTY_FLAG);
 #ifdef USE_KVM
 	    if (kvm_allowed)
@@ -1558,7 +1594,7 @@
         } else {
             if (y_start >= 0) {
                 /* flush to display */
-                dpy_update(s->ds, 0, y_start, 
+                dpy_update(s->ds, 0, y_start,
                            disp_width, y - y_start);
                 y_start = -1;
             }
@@ -1579,7 +1615,7 @@
     }
     if (y_start >= 0) {
         /* flush to display */
-        dpy_update(s->ds, 0, y_start, 
+        dpy_update(s->ds, 0, y_start,
                    disp_width, y - y_start);
     }
     /* reset modified pages */
@@ -1599,7 +1635,7 @@
         return;
     if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
         return;
-    if (s->ds->depth == 8) 
+    if (s->ds->depth == 8)
         val = s->rgb_to_pixel(0, 0, 0);
     else
         val = 0;
@@ -1609,13 +1645,13 @@
         memset(d, val, w);
         d += s->ds->linesize;
     }
-    dpy_update(s->ds, 0, 0, 
+    dpy_update(s->ds, 0, 0,
                s->last_scr_width, s->last_scr_height);
 }
 
 #define GMODE_TEXT     0
 #define GMODE_GRAPH    1
-#define GMODE_BLANK 2 
+#define GMODE_BLANK 2
 
 static void vga_update_display(void *opaque)
 {
@@ -1625,9 +1661,9 @@
     if (s->ds->depth == 0) {
         /* nothing to do */
     } else {
-        s->rgb_to_pixel = 
+        s->rgb_to_pixel =
             rgb_to_pixel_dup_table[get_depth_index(s->ds)];
-        
+
         full_update = 0;
         if (!(s->ar_index & 0x20)) {
             graphic_mode = GMODE_BLANK;
@@ -1657,7 +1693,7 @@
 static void vga_invalidate_display(void *opaque)
 {
     VGAState *s = (VGAState *)opaque;
-    
+
     s->last_width = -1;
     s->last_height = -1;
 }
@@ -1786,7 +1822,7 @@
     VGAState vga_state;
 } PCIVGAState;
 
-static void vga_map(PCIDevice *pci_dev, int region_num, 
+static void vga_map(PCIDevice *pci_dev, int region_num,
                     uint32_t addr, uint32_t size, int type)
 {
     PCIVGAState *d = (PCIVGAState *)pci_dev;
@@ -1833,7 +1869,7 @@
 }
 
 /* when used on xen/kvm environment, the vga_ram_base is not used */
-void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
+void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
                      unsigned long vga_ram_offset, int vga_ram_size)
 {
     int i, j, v, b;
@@ -1877,12 +1913,13 @@
     s->get_bpp = vga_get_bpp;
     s->get_offsets = vga_get_offsets;
     s->get_resolution = vga_get_resolution;
-    graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
-                         vga_screen_dump, s);
+    s->update = vga_update_display;
+    s->invalidate = vga_invalidate_display;
+    s->screen_dump = vga_screen_dump;
 }
 
 /* used by both ISA and PCI */
-static void vga_init(VGAState *s)
+void vga_init(VGAState *s)
 {
     int vga_io_memory;
 
@@ -1918,7 +1955,7 @@
     register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
 
     register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
-    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s); 
+    register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
 #else
     register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
     register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
@@ -1929,11 +1966,86 @@
 #endif /* CONFIG_BOCHS_VBE */
 
     vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
-    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000, 
+    cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
                                  vga_io_memory);
 }
 
-int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, 
+/* Memory mapped interface */
+static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+    VGAState *s = opaque;
+
+    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xff;
+}
+
+static void vga_mm_writeb (void *opaque,
+                           target_phys_addr_t addr, uint32_t value)
+{
+    VGAState *s = opaque;
+
+    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xff);
+}
+
+static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+    VGAState *s = opaque;
+
+    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xffff;
+}
+
+static void vga_mm_writew (void *opaque,
+                           target_phys_addr_t addr, uint32_t value)
+{
+    VGAState *s = opaque;
+
+    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xffff);
+}
+
+static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+    VGAState *s = opaque;
+
+    return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift);
+}
+
+static void vga_mm_writel (void *opaque,
+                           target_phys_addr_t addr, uint32_t value)
+{
+    VGAState *s = opaque;
+
+    vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
+    &vga_mm_readb,
+    &vga_mm_readw,
+    &vga_mm_readl,
+};
+
+static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
+    &vga_mm_writeb,
+    &vga_mm_writew,
+    &vga_mm_writel,
+};
+
+static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
+                        target_phys_addr_t ctrl_base, int it_shift)
+{
+    int s_ioport_ctrl, vga_io_memory;
+
+    s->base_ctrl = ctrl_base;
+    s->it_shift = it_shift;
+    s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
+    vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
+
+    register_savevm("vga", 0, 2, vga_save, vga_load, s);
+
+    cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
+    s->bank_offset = 0;
+    cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
+}
+
+int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
                  unsigned long vga_ram_offset, int vga_ram_size)
 {
     VGAState *s;
@@ -1945,44 +2057,73 @@
     vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
     vga_init(s);
 
+    graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
+
 #ifdef CONFIG_BOCHS_VBE
     /* XXX: use optimized standard vga accesses */
-    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 
+    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
                                  vga_ram_size, vga_ram_offset);
 #endif
     return 0;
 }
 
-int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
+int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
+                    unsigned long vga_ram_offset, int vga_ram_size,
+                    target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
+                    int it_shift)
+{
+    VGAState *s;
+
+    s = qemu_mallocz(sizeof(VGAState));
+    if (!s)
+        return -1;
+
+    vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
+    vga_mm_init(s, vram_base, ctrl_base, it_shift);
+
+    graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
+
+#ifdef CONFIG_BOCHS_VBE
+    /* XXX: use optimized standard vga accesses */
+    cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+                                 vga_ram_size, vga_ram_offset);
+#endif
+    return 0;
+}
+
+int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
                  unsigned long vga_ram_offset, int vga_ram_size,
                  unsigned long vga_bios_offset, int vga_bios_size)
 {
     PCIVGAState *d;
     VGAState *s;
     uint8_t *pci_conf;
-    
-    d = (PCIVGAState *)pci_register_device(bus, "VGA", 
+
+    d = (PCIVGAState *)pci_register_device(bus, "VGA",
                                            sizeof(PCIVGAState),
                                            -1, NULL, NULL);
     if (!d)
         return -1;
     s = &d->vga_state;
-    
+
     vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
     vga_init(s);
+
+    graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
+
     s->pci_dev = &d->dev;
-    
+
     pci_conf = d->dev.config;
     pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
     pci_conf[0x01] = 0x12;
     pci_conf[0x02] = 0x11;
     pci_conf[0x03] = 0x11;
-    pci_conf[0x0a] = 0x00; // VGA controller 
+    pci_conf[0x0a] = 0x00; // VGA controller
     pci_conf[0x0b] = 0x03;
     pci_conf[0x0e] = 0x00; // header_type
-    
+
     /* XXX: vga_ram_size must be a power of two */
-    pci_register_io_region(&d->dev, 0, vga_ram_size, 
+    pci_register_io_region(&d->dev, 0, vga_ram_size,
                            PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
     if (vga_bios_size != 0) {
         unsigned int bios_total_size;
@@ -1992,7 +2133,7 @@
         bios_total_size = 1;
         while (bios_total_size < vga_bios_size)
             bios_total_size <<= 1;
-        pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size, 
+        pci_register_io_region(&d->dev, PCI_ROM_SLOT, bios_total_size,
                                PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
     }
     return 0;
@@ -2028,7 +2169,7 @@
 
 static int vga_save_w, vga_save_h;
 
-static void vga_save_dpy_update(DisplayState *s, 
+static void vga_save_dpy_update(DisplayState *s,
                                 int x, int y, int w, int h)
 {
 }
@@ -2045,8 +2186,8 @@
 {
 }
 
-static int ppm_save(const char *filename, uint8_t *data, 
-                    int w, int h, int linesize)
+int ppm_save(const char *filename, uint8_t *data,
+             int w, int h, int linesize)
 {
     FILE *f;
     uint8_t *d, *d1;
@@ -2080,7 +2221,7 @@
 {
     VGAState *s = (VGAState *)opaque;
     DisplayState *saved_ds, ds1, *ds = &ds1;
-    
+
     /* XXX: this is a little hackish */
     vga_invalidate_display(s);
     saved_ds = s->ds;
@@ -2094,9 +2235,9 @@
     s->ds = ds;
     s->graphic_mode = -1;
     vga_update_display(s);
-    
+
     if (ds->data) {
-        ppm_save(filename, ds->data, vga_save_w, vga_save_h, 
+        ppm_save(filename, ds->data, vga_save_w, vga_save_h,
                  s->ds->linesize);
         qemu_free(ds->data);
     }
diff --git a/hw/vga_int.h b/hw/vga_int.h
index 1512e77..b10bcd5 100644
--- a/hw/vga_int.h
+++ b/hw/vga_int.h
@@ -1,8 +1,8 @@
 /*
  * QEMU internal VGA defines.
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -45,20 +45,20 @@
 #define VBE_DISPI_INDEX_X_OFFSET        0x8
 #define VBE_DISPI_INDEX_Y_OFFSET        0x9
 #define VBE_DISPI_INDEX_NB              0xa
-      
+
 #define VBE_DISPI_ID0                   0xB0C0
 #define VBE_DISPI_ID1                   0xB0C1
 #define VBE_DISPI_ID2                   0xB0C2
 #define VBE_DISPI_ID3                   0xB0C3
 #define VBE_DISPI_ID4                   0xB0C4
-  
+
 #define VBE_DISPI_DISABLED              0x00
 #define VBE_DISPI_ENABLED               0x01
 #define VBE_DISPI_GETCAPS               0x02
 #define VBE_DISPI_8BIT_DAC              0x20
 #define VBE_DISPI_LFB_ENABLED           0x40
 #define VBE_DISPI_NOCLEARMEM            0x80
-  
+
 #define VBE_DISPI_LFB_PHYSICAL_ADDRESS  0xE0000000
 
 #ifdef CONFIG_BOCHS_VBE
@@ -85,6 +85,8 @@
     unsigned int vram_size;                                             \
     unsigned long bios_offset;                                          \
     unsigned int bios_size;                                             \
+    target_phys_addr_t base_ctrl;                                       \
+    int it_shift;                                                       \
     PCIDevice *pci_dev;                                                 \
     uint32_t latch;                                                     \
     uint8_t sr_index;                                                   \
@@ -134,6 +136,9 @@
     uint32_t cursor_offset;                                             \
     unsigned int (*rgb_to_pixel)(unsigned int r,                        \
                                  unsigned int g, unsigned b);           \
+    vga_hw_update_ptr update;                                           \
+    vga_hw_invalidate_ptr invalidate;                                   \
+    vga_hw_screen_dump_ptr screen_dump;                                 \
     /* hardware mouse cursor support */                                 \
     uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32];                  \
     void (*cursor_invalidate)(struct VGAState *s);                      \
@@ -167,22 +172,25 @@
     return (v << 2) | (b << 1) | b;
 }
 
-void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base, 
+void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
                      unsigned long vga_ram_offset, int vga_ram_size);
+void vga_init(VGAState *s);
 uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
 void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
 void vga_invalidate_scanlines(VGAState *s, int y1, int y2);
+int ppm_save(const char *filename, uint8_t *data,
+             int w, int h, int linesize);
 
-void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1, 
-                            int poffset, int w, 
+void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
+                            int poffset, int w,
                             unsigned int color0, unsigned int color1,
                             unsigned int color_xor);
-void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1, 
-                             int poffset, int w, 
+void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1,
+                             int poffset, int w,
                              unsigned int color0, unsigned int color1,
                              unsigned int color_xor);
-void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1, 
-                             int poffset, int w, 
+void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
+                             int poffset, int w,
                              unsigned int color0, unsigned int color1,
                              unsigned int color_xor);
 
diff --git a/hw/vga_template.h b/hw/vga_template.h
index e7e8cb8..0bc2e80 100644
--- a/hw/vga_template.h
+++ b/hw/vga_template.h
@@ -1,8 +1,8 @@
 /*
  * QEMU VGA Emulator templates
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -24,13 +24,13 @@
 
 #if DEPTH == 8
 #define BPP 1
-#define PIXEL_TYPE uint8_t 
+#define PIXEL_TYPE uint8_t
 #elif DEPTH == 15 || DEPTH == 16
 #define BPP 2
-#define PIXEL_TYPE uint16_t 
+#define PIXEL_TYPE uint16_t
 #elif DEPTH == 32
 #define BPP 4
-#define PIXEL_TYPE uint32_t 
+#define PIXEL_TYPE uint32_t
 #else
 #error unsupport depth
 #endif
@@ -43,9 +43,9 @@
 
 #if DEPTH != 15 && !defined(BGR_FORMAT)
 
-static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d, 
+static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
                                                      uint32_t font_data,
-                                                     uint32_t xorcol, 
+                                                     uint32_t xorcol,
                                                      uint32_t bgcol)
 {
 #if BPP == 1
@@ -73,7 +73,7 @@
                                           uint32_t fgcol, uint32_t bgcol)
 {
     uint32_t font_data, xorcol;
-    
+
     xorcol = bgcol ^ fgcol;
     do {
         font_data = font_ptr[0];
@@ -88,15 +88,15 @@
                                           uint32_t fgcol, uint32_t bgcol)
 {
     uint32_t font_data, xorcol;
-    
+
     xorcol = bgcol ^ fgcol;
     do {
         font_data = font_ptr[0];
-        glue(vga_draw_glyph_line_, DEPTH)(d, 
-                                          expand4to8[font_data >> 4], 
+        glue(vga_draw_glyph_line_, DEPTH)(d,
+                                          expand4to8[font_data >> 4],
                                           xorcol, bgcol);
-        glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP, 
-                                          expand4to8[font_data & 0x0f], 
+        glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
+                                          expand4to8[font_data & 0x0f],
                                           xorcol, bgcol);
         font_ptr += 4;
         d += linesize;
@@ -104,11 +104,11 @@
 }
 
 static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
-                                          const uint8_t *font_ptr, int h, 
+                                          const uint8_t *font_ptr, int h,
                                           uint32_t fgcol, uint32_t bgcol, int dup9)
 {
     uint32_t font_data, xorcol, v;
-    
+
     xorcol = bgcol ^ fgcol;
     do {
         font_data = font_ptr[0];
@@ -120,7 +120,7 @@
             ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
         else
             ((uint8_t *)d)[8] = bgcol;
-        
+
 #elif BPP == 2
         cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
         cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
@@ -151,10 +151,10 @@
     } while (--h);
 }
 
-/* 
+/*
  * 4 color mode
  */
-static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d,
                                          const uint8_t *s, int width)
 {
     uint32_t plane_mask, *palette, data, v;
@@ -193,10 +193,10 @@
 ((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
 #endif
 
-/* 
+/*
  * 4 color mode, dup2 horizontal
  */
-static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d,
                                            const uint8_t *s, int width)
 {
     uint32_t plane_mask, *palette, data, v;
@@ -226,10 +226,10 @@
     }
 }
 
-/* 
+/*
  * 16 color mode
  */
-static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d,
                                          const uint8_t *s, int width)
 {
     uint32_t plane_mask, data, v, *palette;
@@ -258,10 +258,10 @@
     }
 }
 
-/* 
+/*
  * 16 color mode, dup2 horizontal
  */
-static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d,
                                            const uint8_t *s, int width)
 {
     uint32_t plane_mask, data, v, *palette;
@@ -290,12 +290,12 @@
     }
 }
 
-/* 
+/*
  * 256 color mode, double pixels
  *
  * XXX: add plane_mask support (never used in standard VGA modes)
  */
-static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d,
                                            const uint8_t *s, int width)
 {
     uint32_t *palette;
@@ -313,12 +313,12 @@
     }
 }
 
-/* 
+/*
  * standard 256 color mode
  *
  * XXX: add plane_mask support (never used in standard VGA modes)
  */
-static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
                                          const uint8_t *s, int width)
 {
     uint32_t *palette;
@@ -340,10 +340,10 @@
     }
 }
 
-void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1, 
-                                        const uint8_t *src1, 
+void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
+                                        const uint8_t *src1,
                                         int poffset, int w,
-                                        unsigned int color0, 
+                                        unsigned int color0,
                                         unsigned int color1,
                                         unsigned int color_xor)
 {
@@ -411,10 +411,10 @@
 
 /* XXX: optimize */
 
-/* 
+/*
  * 15 bit color
  */
-static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
                                           const uint8_t *s, int width)
 {
 #if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
@@ -433,13 +433,13 @@
         s += 2;
         d += BPP;
     } while (--w != 0);
-#endif    
+#endif
 }
 
-/* 
+/*
  * 16 bit color
  */
-static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
                                           const uint8_t *s, int width)
 {
 #if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
@@ -458,13 +458,13 @@
         s += 2;
         d += BPP;
     } while (--w != 0);
-#endif    
+#endif
 }
 
-/* 
+/*
  * 24 bit color
  */
-static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
                                           const uint8_t *s, int width)
 {
     int w;
@@ -487,10 +487,10 @@
     } while (--w != 0);
 }
 
-/* 
+/*
  * 32 bit color
  */
-static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d, 
+static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
                                           const uint8_t *s, int width)
 {
 #if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
diff --git a/hw/vmmouse.c b/hw/vmmouse.c
new file mode 100644
index 0000000..3c4f667
--- /dev/null
+++ b/hw/vmmouse.c
@@ -0,0 +1,288 @@
+/*
+ * QEMU VMMouse emulation
+ *
+ * Copyright (C) 2007 Anthony Liguori <anthony@codemonkey.ws>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+/* debug only vmmouse */
+//#define DEBUG_VMMOUSE
+
+/* VMMouse Commands */
+#define VMMOUSE_GETVERSION	10
+#define VMMOUSE_DATA		39
+#define VMMOUSE_STATUS		40
+#define VMMOUSE_COMMAND		41
+
+#define VMMOUSE_READ_ID			0x45414552
+#define VMMOUSE_DISABLE			0x000000f5
+#define VMMOUSE_REQUEST_RELATIVE	0x4c455252
+#define VMMOUSE_REQUEST_ABSOLUTE	0x53424152
+
+#define VMMOUSE_QUEUE_SIZE	1024
+
+#define VMMOUSE_VERSION		0x3442554a
+
+#ifdef DEBUG_VMMOUSE
+#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+typedef struct _VMMouseState
+{
+    uint32_t queue[VMMOUSE_QUEUE_SIZE];
+    uint16_t nb_queue;
+    uint16_t status;
+    uint8_t absolute;
+    QEMUPutMouseEntry *entry;
+    void *ps2_mouse;
+} VMMouseState;
+
+static uint32_t vmmouse_get_status(VMMouseState *s)
+{
+    DPRINTF("vmmouse_get_status()\n");
+    return (s->status << 16) | s->nb_queue;
+}
+
+static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state)
+{
+    VMMouseState *s = opaque;
+    int buttons = 0;
+
+    if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
+        return;
+
+    DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
+            x, y, dz, buttons_state);
+
+    if ((buttons_state & MOUSE_EVENT_LBUTTON))
+        buttons |= 0x20;
+    if ((buttons_state & MOUSE_EVENT_RBUTTON))
+        buttons |= 0x10;
+    if ((buttons_state & MOUSE_EVENT_MBUTTON))
+        buttons |= 0x08;
+
+    if (s->absolute) {
+        x <<= 1;
+        y <<= 1;
+    }
+
+    s->queue[s->nb_queue++] = buttons;
+    s->queue[s->nb_queue++] = x;
+    s->queue[s->nb_queue++] = y;
+    s->queue[s->nb_queue++] = dz;
+
+    /* need to still generate PS2 events to notify driver to
+       read from queue */
+    ps2_mouse_fake_event(s->ps2_mouse);
+}
+
+static void vmmouse_update_handler(VMMouseState *s)
+{
+    if (s->entry) {
+        qemu_remove_mouse_event_handler(s->entry);
+        s->entry = NULL;
+    }
+    if (s->status == 0)
+        s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
+                                                s, s->absolute,
+                                                "vmmouse");
+}
+
+static void vmmouse_read_id(VMMouseState *s)
+{
+    DPRINTF("vmmouse_read_id()\n");
+
+    if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
+        return;
+
+    s->queue[s->nb_queue++] = VMMOUSE_VERSION;
+    s->status = 0;
+    vmmouse_update_handler(s);
+}
+
+static void vmmouse_request_relative(VMMouseState *s)
+{
+    DPRINTF("vmmouse_request_relative()\n");
+    s->absolute = 0;
+    vmmouse_update_handler(s);
+}
+
+static void vmmouse_request_absolute(VMMouseState *s)
+{
+    DPRINTF("vmmouse_request_absolute()\n");
+    s->absolute = 1;
+    vmmouse_update_handler(s);
+}
+
+static void vmmouse_disable(VMMouseState *s)
+{
+    DPRINTF("vmmouse_disable()\n");
+    s->status = 0xffff;
+    vmmouse_update_handler(s);
+}
+
+static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
+{
+    int i;
+
+    DPRINTF("vmmouse_data(%d)\n", size);
+
+    if (size == 0 || size > 6 || size > s->nb_queue) {
+        printf("vmmouse: driver requested too much data %d\n", size);
+        s->status = 0xffff;
+        vmmouse_update_handler(s);
+        return;
+    }
+
+    for (i = 0; i < size; i++)
+        data[i] = s->queue[i];
+
+    s->nb_queue -= size;
+    if (s->nb_queue)
+        memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
+}
+
+static void vmmouse_get_data(uint32_t *data)
+{
+    CPUState *env = cpu_single_env;
+
+    data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
+    data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
+    data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
+
+    DPRINTF("get_data = {%x, %x, %x, %x, %x, %x}\n",
+            data[0], data[1], data[2], data[3], data[4], data[5]);
+}
+
+static void vmmouse_set_data(const uint32_t *data)
+{
+    CPUState *env = cpu_single_env;
+
+    DPRINTF("set_data = {%x, %x, %x, %x, %x, %x}\n",
+            data[0], data[1], data[2], data[3], data[4], data[5]);
+
+    env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
+    env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
+    env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
+}
+
+static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
+{
+    VMMouseState *s = opaque;
+    uint32_t data[6];
+    uint16_t command;
+
+    vmmouse_get_data(data);
+
+    command = data[2] & 0xFFFF;
+
+    switch (command) {
+    case VMMOUSE_STATUS:
+        data[0] = vmmouse_get_status(s);
+        break;
+    case VMMOUSE_COMMAND:
+        switch (data[1]) {
+        case VMMOUSE_DISABLE:
+            vmmouse_disable(s);
+            break;
+        case VMMOUSE_READ_ID:
+            vmmouse_read_id(s);
+            break;
+        case VMMOUSE_REQUEST_RELATIVE:
+            vmmouse_request_relative(s);
+            break;
+        case VMMOUSE_REQUEST_ABSOLUTE:
+            vmmouse_request_absolute(s);
+            break;
+        default:
+            printf("vmmouse: unknown command %x\n", data[1]);
+            break;
+        }
+        break;
+    case VMMOUSE_DATA:
+        vmmouse_data(s, data, data[1]);
+        break;
+    default:
+        printf("vmmouse: unknown command %x\n", command);
+        break;
+    }
+
+    vmmouse_set_data(data);
+    return data[0];
+}
+
+static void vmmouse_save(QEMUFile *f, void *opaque)
+{
+    VMMouseState *s = opaque;
+    int i;
+
+    qemu_put_be32(f, VMMOUSE_QUEUE_SIZE);
+    for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++)
+        qemu_put_be32s(f, &s->queue[i]);
+    qemu_put_be16s(f, &s->nb_queue);
+    qemu_put_be16s(f, &s->status);
+    qemu_put_8s(f, &s->absolute);
+}
+
+static int vmmouse_load(QEMUFile *f, void *opaque, int version_id)
+{
+    VMMouseState *s = opaque;
+    int i;
+
+    if (version_id != 0)
+        return -EINVAL;
+
+    if (qemu_get_be32(f) != VMMOUSE_QUEUE_SIZE)
+        return -EINVAL;
+    for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++)
+        qemu_get_be32s(f, &s->queue[i]);
+    qemu_get_be16s(f, &s->nb_queue);
+    qemu_get_be16s(f, &s->status);
+    qemu_get_8s(f, &s->absolute);
+
+    vmmouse_update_handler(s);
+
+    return 0;
+}
+
+void *vmmouse_init(void *m)
+{
+    VMMouseState *s = NULL;
+
+    DPRINTF("vmmouse_init\n");
+
+    s = qemu_mallocz(sizeof(VMMouseState));
+    if (!s)
+        return NULL;
+
+    s->status = 0xffff;
+    s->ps2_mouse = m;
+
+    vmport_register(VMMOUSE_STATUS, vmmouse_ioport_read, s);
+    vmport_register(VMMOUSE_COMMAND, vmmouse_ioport_read, s);
+    vmport_register(VMMOUSE_DATA, vmmouse_ioport_read, s);
+    register_savevm("vmmouse", 0, 0, vmmouse_save, vmmouse_load, s);
+
+    return s;
+}
+
diff --git a/hw/vmport.c b/hw/vmport.c
new file mode 100644
index 0000000..e477fe8
--- /dev/null
+++ b/hw/vmport.c
@@ -0,0 +1,96 @@
+/*
+ * QEMU VMPort emulation
+ *
+ * Copyright (C) 2007 Hervé Poussineau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+#include "cpu-all.h"
+
+#define VMPORT_CMD_GETVERSION 0x0a
+#define VMPORT_CMD_GETRAMSIZE 0x14
+
+#define VMPORT_ENTRIES 0x2c
+#define VMPORT_MAGIC   0x564D5868
+
+typedef struct _VMPortState
+{
+    CPUState *env;
+    IOPortReadFunc *func[VMPORT_ENTRIES];
+    void *opaque[VMPORT_ENTRIES];
+} VMPortState;
+
+static VMPortState port_state;
+
+void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque)
+{
+    if (command >= VMPORT_ENTRIES)
+        return;
+
+    port_state.func[command] = func;
+    port_state.opaque[command] = opaque;
+}
+
+static uint32_t vmport_ioport_read(void *opaque, uint32_t addr)
+{
+    VMPortState *s = opaque;
+    unsigned char command;
+    target_ulong eax;
+
+    eax = s->env->regs[R_EAX];
+    if (eax != VMPORT_MAGIC)
+        return eax;
+
+    command = s->env->regs[R_ECX];
+    if (command >= VMPORT_ENTRIES)
+        return eax;
+    if (!s->func[command])
+    {
+        printf("vmport: unknown command %x\n", command);
+        return eax;
+    }
+
+    return s->func[command](s->opaque[command], addr);
+}
+
+static uint32_t vmport_cmd_get_version(void *opaque, uint32_t addr)
+{
+    CPUState *env = opaque;
+    env->regs[R_EBX] = VMPORT_MAGIC;
+    return 6;
+}
+
+static uint32_t vmport_cmd_ram_size(void *opaque, uint32_t addr)
+{
+    CPUState *env = opaque;
+    env->regs[R_EBX] = 0x1177;
+    return ram_size;
+}
+
+void vmport_init(CPUState *env)
+{
+    port_state.env = env;
+
+    register_ioport_read(0x5658, 1, 4, vmport_ioport_read, &port_state);
+
+    /* Register some generic port commands */
+    vmport_register(VMPORT_CMD_GETVERSION, vmport_cmd_get_version, env);
+    vmport_register(VMPORT_CMD_GETRAMSIZE, vmport_cmd_ram_size, env);
+}
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
new file mode 100644
index 0000000..e850952
--- /dev/null
+++ b/hw/vmware_vga.c
@@ -0,0 +1,1193 @@
+/*
+ * QEMU VMware-SVGA "chipset".
+ *
+ * Copyright (c) 2007 Andrzej Zaborowski  <balrog@zabor.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+#define VERBOSE
+#define EMBED_STDVGA
+#undef DIRECT_VRAM
+#define HW_RECT_ACCEL
+#define HW_FILL_ACCEL
+#define HW_MOUSE_ACCEL
+
+#ifdef EMBED_STDVGA
+# include "vga_int.h"
+#endif
+
+struct vmsvga_state_s {
+#ifdef EMBED_STDVGA
+    VGA_STATE_COMMON
+#endif
+
+    int width;
+    int height;
+    int invalidated;
+    int depth;
+    int bypp;
+    int enable;
+    int config;
+    struct {
+        int id;
+        int x;
+        int y;
+        int on;
+    } cursor;
+
+#ifndef EMBED_STDVGA
+    DisplayState *ds;
+    int vram_size;
+#endif
+    uint8_t *vram;
+
+    int index;
+    int scratch_size;
+    uint32_t *scratch;
+    int new_width;
+    int new_height;
+    uint32_t guest;
+    uint32_t svgaid;
+    uint32_t wred;
+    uint32_t wgreen;
+    uint32_t wblue;
+    int syncing;
+    int fb_size;
+
+    union {
+        uint32_t *fifo;
+        struct __attribute__((__packed__)) {
+            uint32_t min;
+            uint32_t max;
+            uint32_t next_cmd;
+            uint32_t stop;
+            /* Add registers here when adding capabilities.  */
+            uint32_t fifo[0];
+        } *cmd;
+    };
+
+#define REDRAW_FIFO_LEN	512
+    struct vmsvga_rect_s {
+        int x, y, w, h;
+    } redraw_fifo[REDRAW_FIFO_LEN];
+    int redraw_fifo_first, redraw_fifo_last;
+};
+
+struct pci_vmsvga_state_s {
+    PCIDevice card;
+    struct vmsvga_state_s chip;
+};
+
+#define SVGA_MAGIC		0x900000UL
+#define SVGA_MAKE_ID(ver)	(SVGA_MAGIC << 8 | (ver))
+#define SVGA_ID_0		SVGA_MAKE_ID(0)
+#define SVGA_ID_1		SVGA_MAKE_ID(1)
+#define SVGA_ID_2		SVGA_MAKE_ID(2)
+
+#define SVGA_LEGACY_BASE_PORT	0x4560
+#define SVGA_INDEX_PORT		0x0
+#define SVGA_VALUE_PORT		0x1
+#define SVGA_BIOS_PORT		0x2
+
+#define SVGA_VERSION_2
+
+#ifdef SVGA_VERSION_2
+# define SVGA_ID		SVGA_ID_2
+# define SVGA_IO_BASE		SVGA_LEGACY_BASE_PORT
+# define SVGA_IO_MUL		1
+# define SVGA_FIFO_SIZE		0x10000
+# define SVGA_MEM_BASE		0xe0000000
+# define SVGA_PCI_DEVICE_ID	PCI_DEVICE_ID_VMWARE_SVGA2
+#else
+# define SVGA_ID		SVGA_ID_1
+# define SVGA_IO_BASE		SVGA_LEGACY_BASE_PORT
+# define SVGA_IO_MUL		4
+# define SVGA_FIFO_SIZE		0x10000
+# define SVGA_MEM_BASE		0xe0000000
+# define SVGA_PCI_DEVICE_ID	PCI_DEVICE_ID_VMWARE_SVGA
+#endif
+
+enum {
+    /* ID 0, 1 and 2 registers */
+    SVGA_REG_ID = 0,
+    SVGA_REG_ENABLE = 1,
+    SVGA_REG_WIDTH = 2,
+    SVGA_REG_HEIGHT = 3,
+    SVGA_REG_MAX_WIDTH = 4,
+    SVGA_REG_MAX_HEIGHT = 5,
+    SVGA_REG_DEPTH = 6,
+    SVGA_REG_BITS_PER_PIXEL = 7,	/* Current bpp in the guest */
+    SVGA_REG_PSEUDOCOLOR = 8,
+    SVGA_REG_RED_MASK = 9,
+    SVGA_REG_GREEN_MASK = 10,
+    SVGA_REG_BLUE_MASK = 11,
+    SVGA_REG_BYTES_PER_LINE = 12,
+    SVGA_REG_FB_START = 13,
+    SVGA_REG_FB_OFFSET = 14,
+    SVGA_REG_VRAM_SIZE = 15,
+    SVGA_REG_FB_SIZE = 16,
+
+    /* ID 1 and 2 registers */
+    SVGA_REG_CAPABILITIES = 17,
+    SVGA_REG_MEM_START = 18,		/* Memory for command FIFO */
+    SVGA_REG_MEM_SIZE = 19,
+    SVGA_REG_CONFIG_DONE = 20,		/* Set when memory area configured */
+    SVGA_REG_SYNC = 21,			/* Write to force synchronization */
+    SVGA_REG_BUSY = 22,			/* Read to check if sync is done */
+    SVGA_REG_GUEST_ID = 23,		/* Set guest OS identifier */
+    SVGA_REG_CURSOR_ID = 24,		/* ID of cursor */
+    SVGA_REG_CURSOR_X = 25,		/* Set cursor X position */
+    SVGA_REG_CURSOR_Y = 26,		/* Set cursor Y position */
+    SVGA_REG_CURSOR_ON = 27,		/* Turn cursor on/off */
+    SVGA_REG_HOST_BITS_PER_PIXEL = 28,	/* Current bpp in the host */
+    SVGA_REG_SCRATCH_SIZE = 29,		/* Number of scratch registers */
+    SVGA_REG_MEM_REGS = 30,		/* Number of FIFO registers */
+    SVGA_REG_NUM_DISPLAYS = 31,		/* Number of guest displays */
+    SVGA_REG_PITCHLOCK = 32,		/* Fixed pitch for all modes */
+
+    SVGA_PALETTE_BASE = 1024,		/* Base of SVGA color map */
+    SVGA_PALETTE_END  = SVGA_PALETTE_BASE + 767,
+    SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + 768,
+};
+
+#define SVGA_CAP_NONE			0
+#define SVGA_CAP_RECT_FILL		(1 << 0)
+#define SVGA_CAP_RECT_COPY		(1 << 1)
+#define SVGA_CAP_RECT_PAT_FILL		(1 << 2)
+#define SVGA_CAP_LEGACY_OFFSCREEN	(1 << 3)
+#define SVGA_CAP_RASTER_OP		(1 << 4)
+#define SVGA_CAP_CURSOR			(1 << 5)
+#define SVGA_CAP_CURSOR_BYPASS		(1 << 6)
+#define SVGA_CAP_CURSOR_BYPASS_2	(1 << 7)
+#define SVGA_CAP_8BIT_EMULATION		(1 << 8)
+#define SVGA_CAP_ALPHA_CURSOR		(1 << 9)
+#define SVGA_CAP_GLYPH			(1 << 10)
+#define SVGA_CAP_GLYPH_CLIPPING		(1 << 11)
+#define SVGA_CAP_OFFSCREEN_1		(1 << 12)
+#define SVGA_CAP_ALPHA_BLEND		(1 << 13)
+#define SVGA_CAP_3D			(1 << 14)
+#define SVGA_CAP_EXTENDED_FIFO		(1 << 15)
+#define SVGA_CAP_MULTIMON		(1 << 16)
+#define SVGA_CAP_PITCHLOCK		(1 << 17)
+
+/*
+ * FIFO offsets (seen as an array of 32-bit words)
+ */
+enum {
+    /*
+     * The original defined FIFO offsets
+     */
+    SVGA_FIFO_MIN = 0,
+    SVGA_FIFO_MAX,	/* The distance from MIN to MAX must be at least 10K */
+    SVGA_FIFO_NEXT_CMD,
+    SVGA_FIFO_STOP,
+
+    /*
+     * Additional offsets added as of SVGA_CAP_EXTENDED_FIFO
+     */
+    SVGA_FIFO_CAPABILITIES = 4,
+    SVGA_FIFO_FLAGS,
+    SVGA_FIFO_FENCE,
+    SVGA_FIFO_3D_HWVERSION,
+    SVGA_FIFO_PITCHLOCK,
+};
+
+#define SVGA_FIFO_CAP_NONE		0
+#define SVGA_FIFO_CAP_FENCE		(1 << 0)
+#define SVGA_FIFO_CAP_ACCELFRONT	(1 << 1)
+#define SVGA_FIFO_CAP_PITCHLOCK		(1 << 2)
+
+#define SVGA_FIFO_FLAG_NONE		0
+#define SVGA_FIFO_FLAG_ACCELFRONT	(1 << 0)
+
+/* These values can probably be changed arbitrarily.  */
+#define SVGA_SCRATCH_SIZE		0x8000
+#define SVGA_MAX_WIDTH			2360
+#define SVGA_MAX_HEIGHT			1770
+
+#ifdef VERBOSE
+# define GUEST_OS_BASE		0x5001
+static const char *vmsvga_guest_id[] = {
+    [0x00 ... 0x15] = "an unknown OS",
+    [0x00] = "Dos",
+    [0x01] = "Windows 3.1",
+    [0x02] = "Windows 95",
+    [0x03] = "Windows 98",
+    [0x04] = "Windows ME",
+    [0x05] = "Windows NT",
+    [0x06] = "Windows 2000",
+    [0x07] = "Linux",
+    [0x08] = "OS/2",
+    [0x0a] = "BSD",
+    [0x0b] = "Whistler",
+    [0x15] = "Windows 2003",
+};
+#endif
+
+enum {
+    SVGA_CMD_INVALID_CMD = 0,
+    SVGA_CMD_UPDATE = 1,
+    SVGA_CMD_RECT_FILL = 2,
+    SVGA_CMD_RECT_COPY = 3,
+    SVGA_CMD_DEFINE_BITMAP = 4,
+    SVGA_CMD_DEFINE_BITMAP_SCANLINE = 5,
+    SVGA_CMD_DEFINE_PIXMAP = 6,
+    SVGA_CMD_DEFINE_PIXMAP_SCANLINE = 7,
+    SVGA_CMD_RECT_BITMAP_FILL = 8,
+    SVGA_CMD_RECT_PIXMAP_FILL = 9,
+    SVGA_CMD_RECT_BITMAP_COPY = 10,
+    SVGA_CMD_RECT_PIXMAP_COPY = 11,
+    SVGA_CMD_FREE_OBJECT = 12,
+    SVGA_CMD_RECT_ROP_FILL = 13,
+    SVGA_CMD_RECT_ROP_COPY = 14,
+    SVGA_CMD_RECT_ROP_BITMAP_FILL = 15,
+    SVGA_CMD_RECT_ROP_PIXMAP_FILL = 16,
+    SVGA_CMD_RECT_ROP_BITMAP_COPY = 17,
+    SVGA_CMD_RECT_ROP_PIXMAP_COPY = 18,
+    SVGA_CMD_DEFINE_CURSOR = 19,
+    SVGA_CMD_DISPLAY_CURSOR = 20,
+    SVGA_CMD_MOVE_CURSOR = 21,
+    SVGA_CMD_DEFINE_ALPHA_CURSOR = 22,
+    SVGA_CMD_DRAW_GLYPH = 23,
+    SVGA_CMD_DRAW_GLYPH_CLIPPED = 24,
+    SVGA_CMD_UPDATE_VERBOSE = 25,
+    SVGA_CMD_SURFACE_FILL = 26,
+    SVGA_CMD_SURFACE_COPY = 27,
+    SVGA_CMD_SURFACE_ALPHA_BLEND = 28,
+    SVGA_CMD_FRONT_ROP_FILL = 29,
+    SVGA_CMD_FENCE = 30,
+};
+
+/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */
+enum {
+    SVGA_CURSOR_ON_HIDE = 0,
+    SVGA_CURSOR_ON_SHOW = 1,
+    SVGA_CURSOR_ON_REMOVE_FROM_FB = 2,
+    SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
+};
+
+static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
+                int x, int y, int w, int h)
+{
+#ifndef DIRECT_VRAM
+    int line = h;
+    int bypl = s->bypp * s->width;
+    int width = s->bypp * w;
+    int start = s->bypp * x + bypl * y;
+    uint8_t *src = s->vram + start;
+    uint8_t *dst = s->ds->data + start;
+
+    for (; line > 0; line --, src += bypl, dst += bypl)
+        memcpy(dst, src, width);
+#endif
+
+    dpy_update(s->ds, x, y, w, h);
+}
+
+static inline void vmsvga_update_screen(struct vmsvga_state_s *s)
+{
+#ifndef DIRECT_VRAM
+    memcpy(s->ds->data, s->vram, s->bypp * s->width * s->height);
+#endif
+
+    dpy_update(s->ds, 0, 0, s->width, s->height);
+}
+
+#ifdef DIRECT_VRAM
+# define vmsvga_update_rect_delayed	vmsvga_update_rect
+#else
+static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s,
+                int x, int y, int w, int h)
+{
+    struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last ++];
+    s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1;
+    rect->x = x;
+    rect->y = y;
+    rect->w = w;
+    rect->h = h;
+}
+#endif
+
+static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
+{
+    struct vmsvga_rect_s *rect;
+    if (s->invalidated) {
+        s->redraw_fifo_first = s->redraw_fifo_last;
+        return;
+    }
+    /* Overlapping region updates can be optimised out here - if someone
+     * knows a smart algorithm to do that, please share.  */
+    while (s->redraw_fifo_first != s->redraw_fifo_last) {
+        rect = &s->redraw_fifo[s->redraw_fifo_first ++];
+        s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1;
+        vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h);
+    }
+}
+
+#ifdef HW_RECT_ACCEL
+static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
+                int x0, int y0, int x1, int y1, int w, int h)
+{
+# ifdef DIRECT_VRAM
+    uint8_t *vram = s->ds->data;
+# else
+    uint8_t *vram = s->vram;
+# endif
+    int bypl = s->bypp * s->width;
+    int width = s->bypp * w;
+    int line = h;
+    uint8_t *ptr[2];
+
+# ifdef DIRECT_VRAM
+    if (s->ds->dpy_copy)
+        s->ds->dpy_copy(s->ds, x0, y0, x1, y1, w, h);
+    else
+# endif
+    {
+        if (y1 > y0) {
+            ptr[0] = vram + s->bypp * x0 + bypl * (y0 + h - 1);
+            ptr[1] = vram + s->bypp * x1 + bypl * (y1 + h - 1);
+            for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl)
+                memmove(ptr[1], ptr[0], width);
+        } else {
+            ptr[0] = vram + s->bypp * x0 + bypl * y0;
+            ptr[1] = vram + s->bypp * x1 + bypl * y1;
+            for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl)
+                memmove(ptr[1], ptr[0], width);
+        }
+    }
+
+    vmsvga_update_rect_delayed(s, x1, y1, w, h);
+}
+#endif
+
+#ifdef HW_FILL_ACCEL
+static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
+                uint32_t c, int x, int y, int w, int h)
+{
+# ifdef DIRECT_VRAM
+    uint8_t *vram = s->ds->data;
+# else
+    uint8_t *vram = s->vram;
+# endif
+    int bypp = s->bypp;
+    int bypl = bypp * s->width;
+    int width = bypp * w;
+    int line = h;
+    int column;
+    uint8_t *fst = vram + bypp * x + bypl * y;
+    uint8_t *dst;
+    uint8_t *src;
+    uint8_t col[4];
+
+# ifdef DIRECT_VRAM
+    if (s->ds->dpy_fill)
+        s->ds->dpy_fill(s->ds, x, y, w, h, c);
+    else
+# endif
+    {
+        col[0] = c;
+        col[1] = c >> 8;
+        col[2] = c >> 16;
+        col[3] = c >> 24;
+
+        if (line --) {
+            dst = fst;
+            src = col;
+            for (column = width; column > 0; column --) {
+                *(dst ++) = *(src ++);
+                if (src - col == bypp)
+                    src = col;
+            }
+            dst = fst;
+            for (; line > 0; line --) {
+                dst += bypl;
+                memcpy(dst, fst, width);
+            }
+        }
+    }
+
+    vmsvga_update_rect_delayed(s, x, y, w, h);
+}
+#endif
+
+struct vmsvga_cursor_definition_s {
+    int width;
+    int height;
+    int id;
+    int bpp;
+    int hot_x;
+    int hot_y;
+    uint32_t mask[1024];
+    uint32_t image[1024];
+};
+
+#define SVGA_BITMAP_SIZE(w, h)		((((w) + 31) >> 5) * (h))
+#define SVGA_PIXMAP_SIZE(w, h, bpp)	(((((w) * (bpp)) + 31) >> 5) * (h))
+
+#ifdef HW_MOUSE_ACCEL
+static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
+                struct vmsvga_cursor_definition_s *c)
+{
+    int i;
+    for (i = SVGA_BITMAP_SIZE(c->width, c->height) - 1; i >= 0; i --)
+        c->mask[i] = ~c->mask[i];
+
+    if (s->ds->cursor_define)
+        s->ds->cursor_define(c->width, c->height, c->bpp, c->hot_x, c->hot_y,
+                        (uint8_t *) c->image, (uint8_t *) c->mask);
+}
+#endif
+
+static inline int vmsvga_fifo_empty(struct vmsvga_state_s *s)
+{
+    if (!s->config || !s->enable)
+        return 1;
+    return (s->cmd->next_cmd == s->cmd->stop);
+}
+
+static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
+{
+    uint32_t cmd = s->fifo[s->cmd->stop >> 2];
+    s->cmd->stop += 4;
+    if (s->cmd->stop >= s->cmd->max)
+        s->cmd->stop = s->cmd->min;
+    return cmd;
+}
+
+static void vmsvga_fifo_run(struct vmsvga_state_s *s)
+{
+    uint32_t cmd, colour;
+    int args = 0;
+    int x, y, dx, dy, width, height;
+    struct vmsvga_cursor_definition_s cursor;
+    while (!vmsvga_fifo_empty(s))
+        switch (cmd = vmsvga_fifo_read(s)) {
+        case SVGA_CMD_UPDATE:
+        case SVGA_CMD_UPDATE_VERBOSE:
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+            vmsvga_update_rect_delayed(s, x, y, width, height);
+            break;
+
+        case SVGA_CMD_RECT_FILL:
+            colour = vmsvga_fifo_read(s);
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+#ifdef HW_FILL_ACCEL
+            vmsvga_fill_rect(s, colour, x, y, width, height);
+            break;
+#else
+            goto badcmd;
+#endif
+
+        case SVGA_CMD_RECT_COPY:
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            dx = vmsvga_fifo_read(s);
+            dy = vmsvga_fifo_read(s);
+            width = vmsvga_fifo_read(s);
+            height = vmsvga_fifo_read(s);
+#ifdef HW_RECT_ACCEL
+            vmsvga_copy_rect(s, x, y, dx, dy, width, height);
+            break;
+#else
+            goto badcmd;
+#endif
+
+        case SVGA_CMD_DEFINE_CURSOR:
+            cursor.id = vmsvga_fifo_read(s);
+            cursor.hot_x = vmsvga_fifo_read(s);
+            cursor.hot_y = vmsvga_fifo_read(s);
+            cursor.width = x = vmsvga_fifo_read(s);
+            cursor.height = y = vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            cursor.bpp = vmsvga_fifo_read(s);
+            for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++)
+                cursor.mask[args] = vmsvga_fifo_read(s);
+            for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args ++)
+                cursor.image[args] = vmsvga_fifo_read(s);
+#ifdef HW_MOUSE_ACCEL
+            vmsvga_cursor_define(s, &cursor);
+            break;
+#else
+            args = 0;
+            goto badcmd;
+#endif
+
+        /*
+         * Other commands that we at least know the number of arguments
+         * for so we can avoid FIFO desync if driver uses them illegally.
+         */
+        case SVGA_CMD_DEFINE_ALPHA_CURSOR:
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            x = vmsvga_fifo_read(s);
+            y = vmsvga_fifo_read(s);
+            args = x * y;
+            goto badcmd;
+        case SVGA_CMD_RECT_ROP_FILL:
+            args = 6;
+            goto badcmd;
+        case SVGA_CMD_RECT_ROP_COPY:
+            args = 7;
+            goto badcmd;
+        case SVGA_CMD_DRAW_GLYPH_CLIPPED:
+            vmsvga_fifo_read(s);
+            vmsvga_fifo_read(s);
+            args = 7 + (vmsvga_fifo_read(s) >> 2);
+            goto badcmd;
+        case SVGA_CMD_SURFACE_ALPHA_BLEND:
+            args = 12;
+            goto badcmd;
+
+        /*
+         * Other commands that are not listed as depending on any
+         * CAPABILITIES bits, but are not described in the README either.
+         */
+        case SVGA_CMD_SURFACE_FILL:
+        case SVGA_CMD_SURFACE_COPY:
+        case SVGA_CMD_FRONT_ROP_FILL:
+        case SVGA_CMD_FENCE:
+        case SVGA_CMD_INVALID_CMD:
+            break; /* Nop */
+
+        default:
+        badcmd:
+            while (args --)
+                vmsvga_fifo_read(s);
+            printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
+                            __FUNCTION__, cmd);
+            break;
+        }
+
+    s->syncing = 0;
+}
+
+static uint32_t vmsvga_index_read(void *opaque, uint32_t address)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    return s->index;
+}
+
+static void vmsvga_index_write(void *opaque, uint32_t address, uint32_t index)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    s->index = index;
+}
+
+static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
+{
+    uint32_t caps;
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    switch (s->index) {
+    case SVGA_REG_ID:
+        return s->svgaid;
+
+    case SVGA_REG_ENABLE:
+        return s->enable;
+
+    case SVGA_REG_WIDTH:
+        return s->width;
+
+    case SVGA_REG_HEIGHT:
+        return s->height;
+
+    case SVGA_REG_MAX_WIDTH:
+        return SVGA_MAX_WIDTH;
+
+    case SVGA_REG_MAX_HEIGHT:
+        return SVGA_MAX_HEIGHT;
+
+    case SVGA_REG_DEPTH:
+        return s->depth;
+
+    case SVGA_REG_BITS_PER_PIXEL:
+        return (s->depth + 7) & ~7;
+
+    case SVGA_REG_PSEUDOCOLOR:
+        return 0x0;
+
+    case SVGA_REG_RED_MASK:
+        return s->wred;
+    case SVGA_REG_GREEN_MASK:
+        return s->wgreen;
+    case SVGA_REG_BLUE_MASK:
+        return s->wblue;
+
+    case SVGA_REG_BYTES_PER_LINE:
+        return ((s->depth + 7) >> 3) * s->new_width;
+
+    case SVGA_REG_FB_START:
+        return SVGA_MEM_BASE;
+
+    case SVGA_REG_FB_OFFSET:
+        return 0x0;
+
+    case SVGA_REG_VRAM_SIZE:
+        return s->vram_size - SVGA_FIFO_SIZE;
+
+    case SVGA_REG_FB_SIZE:
+        return s->fb_size;
+
+    case SVGA_REG_CAPABILITIES:
+        caps = SVGA_CAP_NONE;
+#ifdef HW_RECT_ACCEL
+        caps |= SVGA_CAP_RECT_COPY;
+#endif
+#ifdef HW_FILL_ACCEL
+        caps |= SVGA_CAP_RECT_FILL;
+#endif
+#ifdef HW_MOUSE_ACCEL
+        if (s->ds->mouse_set)
+            caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 |
+                    SVGA_CAP_CURSOR_BYPASS;
+#endif
+        return caps;
+
+    case SVGA_REG_MEM_START:
+        return SVGA_MEM_BASE + s->vram_size - SVGA_FIFO_SIZE;
+
+    case SVGA_REG_MEM_SIZE:
+        return SVGA_FIFO_SIZE;
+
+    case SVGA_REG_CONFIG_DONE:
+        return s->config;
+
+    case SVGA_REG_SYNC:
+    case SVGA_REG_BUSY:
+        return s->syncing;
+
+    case SVGA_REG_GUEST_ID:
+        return s->guest;
+
+    case SVGA_REG_CURSOR_ID:
+        return s->cursor.id;
+
+    case SVGA_REG_CURSOR_X:
+        return s->cursor.x;
+
+    case SVGA_REG_CURSOR_Y:
+        return s->cursor.x;
+
+    case SVGA_REG_CURSOR_ON:
+        return s->cursor.on;
+
+    case SVGA_REG_HOST_BITS_PER_PIXEL:
+        return (s->depth + 7) & ~7;
+
+    case SVGA_REG_SCRATCH_SIZE:
+        return s->scratch_size;
+
+    case SVGA_REG_MEM_REGS:
+    case SVGA_REG_NUM_DISPLAYS:
+    case SVGA_REG_PITCHLOCK:
+    case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
+        return 0;
+
+    default:
+        if (s->index >= SVGA_SCRATCH_BASE &&
+                s->index < SVGA_SCRATCH_BASE + s->scratch_size)
+            return s->scratch[s->index - SVGA_SCRATCH_BASE];
+        printf("%s: Bad register %02x\n", __FUNCTION__, s->index);
+    }
+
+    return 0;
+}
+
+static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    switch (s->index) {
+    case SVGA_REG_ID:
+        if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0)
+            s->svgaid = value;
+        break;
+
+    case SVGA_REG_ENABLE:
+        s->enable = value;
+        s->config &= !!value;
+        s->width = -1;
+        s->height = -1;
+        s->invalidated = 1;
+#ifdef EMBED_STDVGA
+        s->invalidate(opaque);
+#endif
+        if (s->enable)
+            s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
+        break;
+
+    case SVGA_REG_WIDTH:
+        s->new_width = value;
+        s->invalidated = 1;
+        break;
+
+    case SVGA_REG_HEIGHT:
+        s->new_height = value;
+        s->invalidated = 1;
+        break;
+
+    case SVGA_REG_DEPTH:
+    case SVGA_REG_BITS_PER_PIXEL:
+        if (value != s->depth) {
+            printf("%s: Bad colour depth: %i bits\n", __FUNCTION__, value);
+            s->config = 0;
+        }
+        break;
+
+    case SVGA_REG_CONFIG_DONE:
+        if (value) {
+            s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE];
+            /* Check range and alignment.  */
+            if ((s->cmd->min | s->cmd->max |
+                        s->cmd->next_cmd | s->cmd->stop) & 3)
+                break;
+            if (s->cmd->min < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo)
+                break;
+            if (s->cmd->max > SVGA_FIFO_SIZE)
+                break;
+            if (s->cmd->max < s->cmd->min + 10 * 1024)
+                break;
+        }
+        s->config = !!value;
+        break;
+
+    case SVGA_REG_SYNC:
+        s->syncing = 1;
+        vmsvga_fifo_run(s); /* Or should we just wait for update_display? */
+        break;
+
+    case SVGA_REG_GUEST_ID:
+        s->guest = value;
+#ifdef VERBOSE
+        if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE +
+                sizeof(vmsvga_guest_id) / sizeof(*vmsvga_guest_id))
+            printf("%s: guest runs %s.\n", __FUNCTION__,
+                            vmsvga_guest_id[value - GUEST_OS_BASE]);
+#endif
+        break;
+
+    case SVGA_REG_CURSOR_ID:
+        s->cursor.id = value;
+        break;
+
+    case SVGA_REG_CURSOR_X:
+        s->cursor.x = value;
+        break;
+
+    case SVGA_REG_CURSOR_Y:
+        s->cursor.y = value;
+        break;
+
+    case SVGA_REG_CURSOR_ON:
+        s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW);
+        s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
+#ifdef HW_MOUSE_ACCEL
+        if (s->ds->mouse_set && value <= SVGA_CURSOR_ON_SHOW)
+            s->ds->mouse_set(s->cursor.x, s->cursor.y, s->cursor.on);
+#endif
+        break;
+
+    case SVGA_REG_MEM_REGS:
+    case SVGA_REG_NUM_DISPLAYS:
+    case SVGA_REG_PITCHLOCK:
+    case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
+        break;
+
+    default:
+        if (s->index >= SVGA_SCRATCH_BASE &&
+                s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
+            s->scratch[s->index - SVGA_SCRATCH_BASE] = value;
+            break;
+        }
+        printf("%s: Bad register %02x\n", __FUNCTION__, s->index);
+    }
+}
+
+static uint32_t vmsvga_bios_read(void *opaque, uint32_t address)
+{
+    printf("%s: what are we supposed to return?\n", __FUNCTION__);
+    return 0xcafe;
+}
+
+static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data)
+{
+    printf("%s: what are we supposed to do with (%08x)?\n",
+                    __FUNCTION__, data);
+}
+
+static inline void vmsvga_size(struct vmsvga_state_s *s)
+{
+    if (s->new_width != s->width || s->new_height != s->height) {
+        s->width = s->new_width;
+        s->height = s->new_height;
+        dpy_resize(s->ds, s->width, s->height);
+        s->invalidated = 1;
+    }
+}
+
+static void vmsvga_update_display(void *opaque)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    if (!s->enable) {
+#ifdef EMBED_STDVGA
+        s->update(opaque);
+#endif
+        return;
+    }
+
+    vmsvga_size(s);
+
+    vmsvga_fifo_run(s);
+    vmsvga_update_rect_flush(s);
+
+    /*
+     * Is it more efficient to look at vram VGA-dirty bits or wait
+     * for the driver to issue SVGA_CMD_UPDATE?
+     */
+    if (s->invalidated) {
+        s->invalidated = 0;
+        vmsvga_update_screen(s);
+    }
+}
+
+static void vmsvga_reset(struct vmsvga_state_s *s)
+{
+    s->index = 0;
+    s->enable = 0;
+    s->config = 0;
+    s->width = -1;
+    s->height = -1;
+    s->svgaid = SVGA_ID;
+    s->depth = s->ds->depth ? s->ds->depth : 24;
+    s->bypp = (s->depth + 7) >> 3;
+    s->cursor.on = 0;
+    s->redraw_fifo_first = 0;
+    s->redraw_fifo_last = 0;
+    switch (s->depth) {
+    case 8:
+        s->wred   = 0x00000007;
+        s->wgreen = 0x00000038;
+        s->wblue  = 0x000000c0;
+        break;
+    case 15:
+        s->wred   = 0x0000001f;
+        s->wgreen = 0x000003e0;
+        s->wblue  = 0x00007c00;
+        break;
+    case 16:
+        s->wred   = 0x0000001f;
+        s->wgreen = 0x000007e0;
+        s->wblue  = 0x0000f800;
+        break;
+    case 24:
+        s->wred   = 0x00ff0000;
+        s->wgreen = 0x0000ff00;
+        s->wblue  = 0x000000ff;
+        break;
+    case 32:
+        s->wred   = 0x00ff0000;
+        s->wgreen = 0x0000ff00;
+        s->wblue  = 0x000000ff;
+        break;
+    }
+    s->syncing = 0;
+}
+
+static void vmsvga_invalidate_display(void *opaque)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    if (!s->enable) {
+#ifdef EMBED_STDVGA
+        s->invalidate(opaque);
+#endif
+        return;
+    }
+
+    s->invalidated = 1;
+}
+
+/* save the vga display in a PPM image even if no display is
+   available */
+static void vmsvga_screen_dump(void *opaque, const char *filename)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    if (!s->enable) {
+#ifdef EMBED_STDVGA
+        s->screen_dump(opaque, filename);
+#endif
+        return;
+    }
+
+    if (s->depth == 32) {
+        ppm_save(filename, s->vram, s->width, s->height, s->ds->linesize);
+    }
+}
+
+#ifdef DIRECT_VRAM
+static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    addr -= SVGA_MEM_BASE;
+    if (addr < s->fb_size)
+        return *(uint8_t *) (s->ds->data + addr);
+    else
+        return *(uint8_t *) (s->vram + addr);
+}
+
+static uint32_t vmsvga_vram_readw(void *opaque, target_phys_addr_t addr)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    addr -= SVGA_MEM_BASE;
+    if (addr < s->fb_size)
+        return *(uint16_t *) (s->ds->data + addr);
+    else
+        return *(uint16_t *) (s->vram + addr);
+}
+
+static uint32_t vmsvga_vram_readl(void *opaque, target_phys_addr_t addr)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    addr -= SVGA_MEM_BASE;
+    if (addr < s->fb_size)
+        return *(uint32_t *) (s->ds->data + addr);
+    else
+        return *(uint32_t *) (s->vram + addr);
+}
+
+static void vmsvga_vram_writeb(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    addr -= SVGA_MEM_BASE;
+    if (addr < s->fb_size)
+        *(uint8_t *) (s->ds->data + addr) = value;
+    else
+        *(uint8_t *) (s->vram + addr) = value;
+}
+
+static void vmsvga_vram_writew(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    addr -= SVGA_MEM_BASE;
+    if (addr < s->fb_size)
+        *(uint16_t *) (s->ds->data + addr) = value;
+    else
+        *(uint16_t *) (s->vram + addr) = value;
+}
+
+static void vmsvga_vram_writel(void *opaque, target_phys_addr_t addr,
+                uint32_t value)
+{
+    struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+    addr -= SVGA_MEM_BASE;
+    if (addr < s->fb_size)
+        *(uint32_t *) (s->ds->data + addr) = value;
+    else
+        *(uint32_t *) (s->vram + addr) = value;
+}
+
+static CPUReadMemoryFunc *vmsvga_vram_read[] = {
+    vmsvga_vram_readb,
+    vmsvga_vram_readw,
+    vmsvga_vram_readl,
+};
+
+static CPUWriteMemoryFunc *vmsvga_vram_write[] = {
+    vmsvga_vram_writeb,
+    vmsvga_vram_writew,
+    vmsvga_vram_writel,
+};
+#endif
+
+static void vmsvga_save(struct vmsvga_state_s *s, QEMUFile *f)
+{
+    qemu_put_be32s(f, &s->depth);
+    qemu_put_be32s(f, &s->enable);
+    qemu_put_be32s(f, &s->config);
+    qemu_put_be32s(f, &s->cursor.id);
+    qemu_put_be32s(f, &s->cursor.x);
+    qemu_put_be32s(f, &s->cursor.y);
+    qemu_put_be32s(f, &s->cursor.on);
+    qemu_put_be32s(f, &s->index);
+    qemu_put_buffer(f, (uint8_t *) s->scratch, s->scratch_size * 4);
+    qemu_put_be32s(f, &s->new_width);
+    qemu_put_be32s(f, &s->new_height);
+    qemu_put_be32s(f, &s->guest);
+    qemu_put_be32s(f, &s->svgaid);
+    qemu_put_be32s(f, &s->syncing);
+    qemu_put_be32s(f, &s->fb_size);
+}
+
+static int vmsvga_load(struct vmsvga_state_s *s, QEMUFile *f)
+{
+    int depth;
+    qemu_get_be32s(f, &depth);
+    qemu_get_be32s(f, &s->enable);
+    qemu_get_be32s(f, &s->config);
+    qemu_get_be32s(f, &s->cursor.id);
+    qemu_get_be32s(f, &s->cursor.x);
+    qemu_get_be32s(f, &s->cursor.y);
+    qemu_get_be32s(f, &s->cursor.on);
+    qemu_get_be32s(f, &s->index);
+    qemu_get_buffer(f, (uint8_t *) s->scratch, s->scratch_size * 4);
+    qemu_get_be32s(f, &s->new_width);
+    qemu_get_be32s(f, &s->new_height);
+    qemu_get_be32s(f, &s->guest);
+    qemu_get_be32s(f, &s->svgaid);
+    qemu_get_be32s(f, &s->syncing);
+    qemu_get_be32s(f, &s->fb_size);
+
+    if (s->enable && depth != s->depth) {
+        printf("%s: need colour depth of %i bits to resume operation.\n",
+                        __FUNCTION__, depth);
+        return -EINVAL;
+    }
+
+    s->invalidated = 1;
+    if (s->config)
+        s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE];
+
+    return 0;
+}
+
+static void vmsvga_init(struct vmsvga_state_s *s, DisplayState *ds,
+                uint8_t *vga_ram_base, unsigned long vga_ram_offset,
+                int vga_ram_size)
+{
+    int iomemtype;
+    s->ds = ds;
+    s->vram = vga_ram_base;
+    s->vram_size = vga_ram_size;
+
+    s->scratch_size = SVGA_SCRATCH_SIZE;
+    s->scratch = (uint32_t *) qemu_malloc(s->scratch_size * 4);
+
+    vmsvga_reset(s);
+
+#ifdef DIRECT_VRAM
+    iomemtype = cpu_register_io_memory(0, vmsvga_vram_read,
+                    vmsvga_vram_write, s);
+#else
+    iomemtype = vga_ram_offset | IO_MEM_RAM;
+#endif
+    cpu_register_physical_memory(SVGA_MEM_BASE, vga_ram_size,
+                    iomemtype);
+
+    register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT,
+                    1, 4, vmsvga_index_read, s);
+    register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT,
+                    1, 4, vmsvga_index_write, s);
+    register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT,
+                    1, 4, vmsvga_value_read, s);
+    register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT,
+                    1, 4, vmsvga_value_write, s);
+    register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT,
+                    1, 4, vmsvga_bios_read, s);
+    register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT,
+                    1, 4, vmsvga_bios_write, s);
+
+    graphic_console_init(ds, vmsvga_update_display,
+                    vmsvga_invalidate_display, vmsvga_screen_dump, s);
+
+#ifdef EMBED_STDVGA
+    vga_common_init((VGAState *) s, ds,
+                    vga_ram_base, vga_ram_offset, vga_ram_size);
+    vga_init((VGAState *) s);
+#endif
+}
+
+static void pci_vmsvga_save(QEMUFile *f, void *opaque)
+{
+    struct pci_vmsvga_state_s *s = (struct pci_vmsvga_state_s *) opaque;
+    pci_device_save(&s->card, f);
+    vmsvga_save(&s->chip, f);
+}
+
+static int pci_vmsvga_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct pci_vmsvga_state_s *s = (struct pci_vmsvga_state_s *) opaque;
+    int ret;
+
+    ret = pci_device_load(&s->card, f);
+    if (ret < 0)
+        return ret;
+
+    ret = vmsvga_load(&s->chip, f);
+    if (ret < 0)
+        return ret;
+
+    return 0;
+}
+
+#define PCI_VENDOR_ID_VMWARE		0x15ad
+#define PCI_DEVICE_ID_VMWARE_SVGA2	0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA	0x0710
+#define PCI_DEVICE_ID_VMWARE_NET	0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI	0x0730
+#define PCI_DEVICE_ID_VMWARE_IDE	0x1729
+#define PCI_CLASS_BASE_DISPLAY		0x03
+#define PCI_CLASS_SUB_VGA		0x00
+#define PCI_CLASS_HEADERTYPE_00h	0x00
+
+void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
+                     unsigned long vga_ram_offset, int vga_ram_size)
+{
+    struct pci_vmsvga_state_s *s;
+
+    /* Setup PCI configuration */
+    s = (struct pci_vmsvga_state_s *)
+        pci_register_device(bus, "QEMUware SVGA",
+                sizeof(struct pci_vmsvga_state_s), -1, 0, 0);
+    s->card.config[PCI_VENDOR_ID]	= PCI_VENDOR_ID_VMWARE & 0xff;
+    s->card.config[PCI_VENDOR_ID + 1]	= PCI_VENDOR_ID_VMWARE >> 8;
+    s->card.config[PCI_DEVICE_ID]	= SVGA_PCI_DEVICE_ID & 0xff;
+    s->card.config[PCI_DEVICE_ID + 1]	= SVGA_PCI_DEVICE_ID >> 8;
+    s->card.config[PCI_COMMAND]		= 0x07;		/* I/O + Memory */
+    s->card.config[PCI_CLASS_DEVICE]	= PCI_CLASS_SUB_VGA;
+    s->card.config[0x0b]		= PCI_CLASS_BASE_DISPLAY;
+    s->card.config[0x0c]		= 0x08;		/* Cache line size */
+    s->card.config[0x0d]		= 0x40;		/* Latency timer */
+    s->card.config[0x0e]		= PCI_CLASS_HEADERTYPE_00h;
+    s->card.config[0x10]		= ((SVGA_IO_BASE >>  0) & 0xff) | 1;
+    s->card.config[0x11]		=  (SVGA_IO_BASE >>  8) & 0xff;
+    s->card.config[0x12]		=  (SVGA_IO_BASE >> 16) & 0xff;
+    s->card.config[0x13]		=  (SVGA_IO_BASE >> 24) & 0xff;
+    s->card.config[0x18]		= (SVGA_MEM_BASE >>  0) & 0xff;
+    s->card.config[0x19]		= (SVGA_MEM_BASE >>  8) & 0xff;
+    s->card.config[0x1a]		= (SVGA_MEM_BASE >> 16) & 0xff;
+    s->card.config[0x1b]		= (SVGA_MEM_BASE >> 24) & 0xff;
+    s->card.config[0x2c]		= PCI_VENDOR_ID_VMWARE & 0xff;
+    s->card.config[0x2d]		= PCI_VENDOR_ID_VMWARE >> 8;
+    s->card.config[0x2e]		= SVGA_PCI_DEVICE_ID & 0xff;
+    s->card.config[0x2f]		= SVGA_PCI_DEVICE_ID >> 8;
+    s->card.config[0x3c]		= 0xff;		/* End */
+
+    vmsvga_init(&s->chip, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
+
+    register_savevm("vmware_vga", 0, 0, pci_vmsvga_save, pci_vmsvga_load, s);
+}
diff --git a/hw/wm8750.c b/hw/wm8750.c
new file mode 100644
index 0000000..b999890
--- /dev/null
+++ b/hw/wm8750.c
@@ -0,0 +1,634 @@
+/*
+ * WM8750 audio CODEC.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog@zabor.org>
+ *
+ * This file is licensed under GNU GPL.
+ */
+
+#include "vl.h"
+
+#define IN_PORT_N	3
+#define OUT_PORT_N	3
+
+#define CODEC		"wm8750"
+
+struct wm_rate_s;
+struct wm8750_s {
+    i2c_slave i2c;
+    uint8_t i2c_data[2];
+    int i2c_len;
+    QEMUSoundCard card;
+    SWVoiceIn *adc_voice[IN_PORT_N];
+    SWVoiceOut *dac_voice[OUT_PORT_N];
+    int enable;
+    void (*data_req)(void *, int, int);
+    void *opaque;
+    uint8_t data_in[4096];
+    uint8_t data_out[4096];
+    int idx_in, req_in;
+    int idx_out, req_out;
+
+    SWVoiceOut **out[2];
+    uint8_t outvol[7], outmute[2];
+    SWVoiceIn **in[2];
+    uint8_t invol[4], inmute[2];
+
+    uint8_t diff[2], pol, ds, monomix[2], alc, mute;
+    uint8_t path[4], mpath[2], power, format;
+    uint32_t inmask, outmask;
+    const struct wm_rate_s *rate;
+};
+
+static inline void wm8750_in_load(struct wm8750_s *s)
+{
+    int acquired;
+    if (s->idx_in + s->req_in <= sizeof(s->data_in))
+        return;
+    s->idx_in = audio_MAX(0, (int) sizeof(s->data_in) - s->req_in);
+    acquired = AUD_read(*s->in[0], s->data_in + s->idx_in,
+                    sizeof(s->data_in) - s->idx_in);
+}
+
+static inline void wm8750_out_flush(struct wm8750_s *s)
+{
+    int sent;
+    if (!s->idx_out)
+        return;
+    sent = AUD_write(*s->out[0], s->data_out, s->idx_out);
+    s->idx_out = 0;
+}
+
+static void wm8750_audio_in_cb(void *opaque, int avail_b)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    s->req_in = avail_b;
+    s->data_req(s->opaque, s->req_out >> 2, avail_b >> 2);
+
+#if 0
+    wm8750_in_load(s);
+#endif
+}
+
+static void wm8750_audio_out_cb(void *opaque, int free_b)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    wm8750_out_flush(s);
+
+    s->req_out = free_b;
+    s->data_req(s->opaque, free_b >> 2, s->req_in >> 2);
+}
+
+struct wm_rate_s {
+    int adc;
+    int adc_hz;
+    int dac;
+    int dac_hz;
+};
+
+static const struct wm_rate_s wm_rate_table[] = {
+    {  256, 48000,  256, 48000 },	/* SR: 00000 */
+    {  384, 48000,  384, 48000 },	/* SR: 00001 */
+    {  256, 48000, 1536,  8000 },	/* SR: 00010 */
+    {  384, 48000, 2304,  8000 },	/* SR: 00011 */
+    { 1536,  8000,  256, 48000 },	/* SR: 00100 */
+    { 2304,  8000,  384, 48000 },	/* SR: 00101 */
+    { 1536,  8000, 1536,  8000 },	/* SR: 00110 */
+    { 2304,  8000, 2304,  8000 },	/* SR: 00111 */
+    { 1024, 12000, 1024, 12000 },	/* SR: 01000 */
+    { 1526, 12000, 1536, 12000 },	/* SR: 01001 */
+    {  768, 16000,  768, 16000 },	/* SR: 01010 */
+    { 1152, 16000, 1152, 16000 },	/* SR: 01011 */
+    {  384, 32000,  384, 32000 },	/* SR: 01100 */
+    {  576, 32000,  576, 32000 },	/* SR: 01101 */
+    {  128, 96000,  128, 96000 },	/* SR: 01110 */
+    {  192, 96000,  192, 96000 },	/* SR: 01111 */
+    {  256, 44100,  256, 44100 },	/* SR: 10000 */
+    {  384, 44100,  384, 44100 },	/* SR: 10001 */
+    {  256, 44100, 1408,  8018 },	/* SR: 10010 */
+    {  384, 44100, 2112,  8018 },	/* SR: 10011 */
+    { 1408,  8018,  256, 44100 },	/* SR: 10100 */
+    { 2112,  8018,  384, 44100 },	/* SR: 10101 */
+    { 1408,  8018, 1408,  8018 },	/* SR: 10110 */
+    { 2112,  8018, 2112,  8018 },	/* SR: 10111 */
+    { 1024, 11025, 1024, 11025 },	/* SR: 11000 */
+    { 1536, 11025, 1536, 11025 },	/* SR: 11001 */
+    {  512, 22050,  512, 22050 },	/* SR: 11010 */
+    {  768, 22050,  768, 22050 },	/* SR: 11011 */
+    {  512, 24000,  512, 24000 },	/* SR: 11100 */
+    {  768, 24000,  768, 24000 },	/* SR: 11101 */
+    {  128, 88200,  128, 88200 },	/* SR: 11110 */
+    {  192, 88200,  128, 88200 },	/* SR: 11111 */
+};
+
+void wm8750_set_format(struct wm8750_s *s)
+{
+    int i;
+    audsettings_t in_fmt;
+    audsettings_t out_fmt;
+    audsettings_t monoout_fmt;
+
+    wm8750_out_flush(s);
+
+    if (s->in[0] && *s->in[0])
+        AUD_set_active_in(*s->in[0], 0);
+    if (s->out[0] && *s->out[0])
+        AUD_set_active_out(*s->out[0], 0);
+
+    for (i = 0; i < IN_PORT_N; i ++)
+        if (s->adc_voice[i]) {
+            AUD_close_in(&s->card, s->adc_voice[i]);
+            s->adc_voice[i] = 0;
+        }
+    for (i = 0; i < OUT_PORT_N; i ++)
+        if (s->dac_voice[i]) {
+            AUD_close_out(&s->card, s->dac_voice[i]);
+            s->dac_voice[i] = 0;
+        }
+
+    if (!s->enable)
+        return;
+
+    /* Setup input */
+    in_fmt.endianness = 0;
+    in_fmt.nchannels = 2;
+    in_fmt.freq = s->rate->adc_hz;
+    in_fmt.fmt = AUD_FMT_S16;
+
+    s->adc_voice[0] = AUD_open_in(&s->card, s->adc_voice[0],
+                    CODEC ".input1", s, wm8750_audio_in_cb, &in_fmt);
+    s->adc_voice[1] = AUD_open_in(&s->card, s->adc_voice[1],
+                    CODEC ".input2", s, wm8750_audio_in_cb, &in_fmt);
+    s->adc_voice[2] = AUD_open_in(&s->card, s->adc_voice[2],
+                    CODEC ".input3", s, wm8750_audio_in_cb, &in_fmt);
+
+    /* Setup output */
+    out_fmt.endianness = 0;
+    out_fmt.nchannels = 2;
+    out_fmt.freq = s->rate->dac_hz;
+    out_fmt.fmt = AUD_FMT_S16;
+    monoout_fmt.endianness = 0;
+    monoout_fmt.nchannels = 1;
+    monoout_fmt.freq = s->rate->dac_hz;
+    monoout_fmt.fmt = AUD_FMT_S16;
+
+    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
+                    CODEC ".speaker", s, wm8750_audio_out_cb, &out_fmt);
+    s->dac_voice[1] = AUD_open_out(&s->card, s->dac_voice[1],
+                    CODEC ".headphone", s, wm8750_audio_out_cb, &out_fmt);
+    /* MONOMIX is also in stereo for simplicity */
+    s->dac_voice[2] = AUD_open_out(&s->card, s->dac_voice[2],
+                    CODEC ".monomix", s, wm8750_audio_out_cb, &out_fmt);
+    /* no sense emulating OUT3 which is a mix of other outputs */
+
+    /* We should connect the left and right channels to their
+     * respective inputs/outputs but we have completely no need
+     * for mixing or combining paths to different ports, so we
+     * connect both channels to where the left channel is routed.  */
+    if (s->in[0] && *s->in[0])
+        AUD_set_active_in(*s->in[0], 1);
+    if (s->out[0] && *s->out[0])
+        AUD_set_active_out(*s->out[0], 1);
+}
+
+void inline wm8750_mask_update(struct wm8750_s *s)
+{
+#define R_ONLY	0x0000ffff
+#define L_ONLY	0xffff0000
+#define BOTH	(R_ONLY | L_ONLY)
+#define NONE	(R_ONLY & L_ONLY)
+    s->inmask =
+            (s->inmute[0] ? R_ONLY : BOTH) &
+            (s->inmute[1] ? L_ONLY : BOTH) &
+            (s->mute ? NONE : BOTH);
+    s->outmask =
+            (s->outmute[0] ? R_ONLY : BOTH) &
+            (s->outmute[1] ? L_ONLY : BOTH) &
+            (s->mute ? NONE : BOTH);
+}
+
+void wm8750_reset(i2c_slave *i2c)
+{
+    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    s->enable = 0;
+    wm8750_set_format(s);
+    s->diff[0] = 0;
+    s->diff[1] = 0;
+    s->ds = 0;
+    s->alc = 0;
+    s->in[0] = &s->adc_voice[0];
+    s->invol[0] = 0x17;
+    s->invol[1] = 0x17;
+    s->invol[2] = 0xc3;
+    s->invol[3] = 0xc3;
+    s->out[0] = &s->dac_voice[0];
+    s->outvol[0] = 0xff;
+    s->outvol[1] = 0xff;
+    s->outvol[2] = 0x79;
+    s->outvol[3] = 0x79;
+    s->outvol[4] = 0x79;
+    s->outvol[5] = 0x79;
+    s->inmute[0] = 0;
+    s->inmute[1] = 0;
+    s->outmute[0] = 0;
+    s->outmute[1] = 0;
+    s->mute = 1;
+    s->path[0] = 0;
+    s->path[1] = 0;
+    s->path[2] = 0;
+    s->path[3] = 0;
+    s->mpath[0] = 0;
+    s->mpath[1] = 0;
+    s->format = 0x0a;
+    s->idx_in = sizeof(s->data_in);
+    s->req_in = 0;
+    s->idx_out = 0;
+    s->req_out = 0;
+    wm8750_mask_update(s);
+    s->i2c_len = 0;
+}
+
+static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
+{
+    struct wm8750_s *s = (struct wm8750_s *) i2c;
+
+    switch (event) {
+    case I2C_START_SEND:
+        s->i2c_len = 0;
+        break;
+    case I2C_FINISH:
+#ifdef VERBOSE
+        if (s->i2c_len < 2)
+            printf("%s: message too short (%i bytes)\n",
+                            __FUNCTION__, s->i2c_len);
+#endif
+        break;
+    default:
+        break;
+    }
+}
+
+#define WM8750_LINVOL	0x00
+#define WM8750_RINVOL	0x01
+#define WM8750_LOUT1V	0x02
+#define WM8750_ROUT1V	0x03
+#define WM8750_ADCDAC	0x05
+#define WM8750_IFACE	0x07
+#define WM8750_SRATE	0x08
+#define WM8750_LDAC	0x0a
+#define WM8750_RDAC	0x0b
+#define WM8750_BASS	0x0c
+#define WM8750_TREBLE	0x0d
+#define WM8750_RESET	0x0f
+#define WM8750_3D	0x10
+#define WM8750_ALC1	0x11
+#define WM8750_ALC2	0x12
+#define WM8750_ALC3	0x13
+#define WM8750_NGATE	0x14
+#define WM8750_LADC	0x15
+#define WM8750_RADC	0x16
+#define WM8750_ADCTL1	0x17
+#define WM8750_ADCTL2	0x18
+#define WM8750_PWR1	0x19
+#define WM8750_PWR2	0x1a
+#define WM8750_ADCTL3	0x1b
+#define WM8750_ADCIN	0x1f
+#define WM8750_LADCIN	0x20
+#define WM8750_RADCIN	0x21
+#define WM8750_LOUTM1	0x22
+#define WM8750_LOUTM2	0x23
+#define WM8750_ROUTM1	0x24
+#define WM8750_ROUTM2	0x25
+#define WM8750_MOUTM1	0x26
+#define WM8750_MOUTM2	0x27
+#define WM8750_LOUT2V	0x28
+#define WM8750_ROUT2V	0x29
+#define WM8750_MOUTV	0x2a
+
+static int wm8750_tx(i2c_slave *i2c, uint8_t data)
+{
+    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    uint8_t cmd;
+    uint16_t value;
+
+    if (s->i2c_len >= 2) {
+        printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
+#ifdef VERBOSE
+        return 1;
+#endif
+    }
+    s->i2c_data[s->i2c_len ++] = data;
+    if (s->i2c_len != 2)
+        return 0;
+
+    cmd = s->i2c_data[0] >> 1;
+    value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
+
+    switch (cmd) {
+    case WM8750_LADCIN:	/* ADC Signal Path Control (Left) */
+        s->diff[0] = (((value >> 6) & 3) == 3);	/* LINSEL */
+        if (s->diff[0])
+            s->in[0] = &s->adc_voice[0 + s->ds * 1];
+        else
+            s->in[0] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
+        break;
+
+    case WM8750_RADCIN:	/* ADC Signal Path Control (Right) */
+        s->diff[1] = (((value >> 6) & 3) == 3);	/* RINSEL */
+        if (s->diff[1])
+            s->in[1] = &s->adc_voice[0 + s->ds * 1];
+        else
+            s->in[1] = &s->adc_voice[((value >> 6) & 3) * 1 + 0];
+        break;
+
+    case WM8750_ADCIN:	/* ADC Input Mode */
+        s->ds = (value >> 8) & 1;	/* DS */
+        if (s->diff[0])
+            s->in[0] = &s->adc_voice[0 + s->ds * 1];
+        if (s->diff[1])
+            s->in[1] = &s->adc_voice[0 + s->ds * 1];
+        s->monomix[0] = (value >> 6) & 3;	/* MONOMIX */
+        break;
+
+    case WM8750_ADCTL1:	/* Additional Control (1) */
+        s->monomix[1] = (value >> 1) & 1;	/* DMONOMIX */
+        break;
+
+    case WM8750_PWR1:	/* Power Management (1) */
+        s->enable = ((value >> 6) & 7) == 3;	/* VMIDSEL, VREF */
+        wm8750_set_format(s);
+        break;
+
+    case WM8750_LINVOL:	/* Left Channel PGA */
+        s->invol[0] = value & 0x3f;		/* LINVOL */
+        s->inmute[0] = (value >> 7) & 1;	/* LINMUTE */
+        wm8750_mask_update(s);
+        break;
+
+    case WM8750_RINVOL:	/* Right Channel PGA */
+        s->invol[1] = value & 0x3f;		/* RINVOL */
+        s->inmute[1] = (value >> 7) & 1;	/* RINMUTE */
+        wm8750_mask_update(s);
+        break;
+
+    case WM8750_ADCDAC:	/* ADC and DAC Control */
+        s->pol = (value >> 5) & 3;		/* ADCPOL */
+        s->mute = (value >> 3) & 1;		/* DACMU */
+        wm8750_mask_update(s);
+        break;
+
+    case WM8750_ADCTL3:	/* Additional Control (3) */
+        break;
+
+    case WM8750_LADC:	/* Left ADC Digital Volume */
+        s->invol[2] = value & 0xff;		/* LADCVOL */
+        break;
+
+    case WM8750_RADC:	/* Right ADC Digital Volume */
+        s->invol[3] = value & 0xff;		/* RADCVOL */
+        break;
+
+    case WM8750_ALC1:	/* ALC Control (1) */
+        s->alc = (value >> 7) & 3;		/* ALCSEL */
+        break;
+
+    case WM8750_NGATE:	/* Noise Gate Control */
+    case WM8750_3D:	/* 3D enhance */
+        break;
+
+    case WM8750_LDAC:	/* Left Channel Digital Volume */
+        s->outvol[0] = value & 0xff;		/* LDACVOL */
+        break;
+
+    case WM8750_RDAC:	/* Right Channel Digital Volume */
+        s->outvol[1] = value & 0xff;		/* RDACVOL */
+        break;
+
+    case WM8750_BASS:	/* Bass Control */
+        break;
+
+    case WM8750_LOUTM1:	/* Left Mixer Control (1) */
+        s->path[0] = (value >> 8) & 1;		/* LD2LO */
+        break;
+
+    case WM8750_LOUTM2:	/* Left Mixer Control (2) */
+        s->path[1] = (value >> 8) & 1;		/* RD2LO */
+        break;
+
+    case WM8750_ROUTM1:	/* Right Mixer Control (1) */
+        s->path[2] = (value >> 8) & 1;		/* LD2RO */
+        break;
+
+    case WM8750_ROUTM2:	/* Right Mixer Control (2) */
+        s->path[3] = (value >> 8) & 1;		/* RD2RO */
+        break;
+
+    case WM8750_MOUTM1:	/* Mono Mixer Control (1) */
+        s->mpath[0] = (value >> 8) & 1;		/* LD2MO */
+        break;
+
+    case WM8750_MOUTM2:	/* Mono Mixer Control (2) */
+        s->mpath[1] = (value >> 8) & 1;		/* RD2MO */
+        break;
+
+    case WM8750_LOUT1V:	/* LOUT1 Volume */
+        s->outvol[2] = value & 0x7f;		/* LOUT2VOL */
+        break;
+
+    case WM8750_LOUT2V:	/* LOUT2 Volume */
+        s->outvol[4] = value & 0x7f;		/* LOUT2VOL */
+        break;
+
+    case WM8750_ROUT1V:	/* ROUT1 Volume */
+        s->outvol[3] = value & 0x7f;		/* ROUT2VOL */
+        break;
+
+    case WM8750_ROUT2V:	/* ROUT2 Volume */
+        s->outvol[5] = value & 0x7f;		/* ROUT2VOL */
+        break;
+
+    case WM8750_MOUTV:	/* MONOOUT Volume */
+        s->outvol[6] = value & 0x7f;		/* MONOOUTVOL */
+        break;
+
+    case WM8750_ADCTL2:	/* Additional Control (2) */
+        break;
+
+    case WM8750_PWR2:	/* Power Management (2) */
+        s->power = value & 0x7e;
+        break;
+
+    case WM8750_IFACE:	/* Digital Audio Interface Format */
+#ifdef VERBOSE
+        if (value & 0x40)			/* MS */
+            printf("%s: attempt to enable Master Mode\n", __FUNCTION__);
+#endif
+        s->format = value;
+        wm8750_set_format(s);
+        break;
+
+    case WM8750_SRATE:	/* Clocking and Sample Rate Control */
+        s->rate = &wm_rate_table[(value >> 1) & 0x1f];
+        wm8750_set_format(s);
+        break;
+
+    case WM8750_RESET:	/* Reset */
+        wm8750_reset(&s->i2c);
+        break;
+
+#ifdef VERBOSE
+    default:
+        printf("%s: unknown register %02x\n", __FUNCTION__, cmd);
+#endif
+    }
+
+    return 0;
+}
+
+static int wm8750_rx(i2c_slave *i2c)
+{
+    return 0x00;
+}
+
+static void wm8750_save(QEMUFile *f, void *opaque)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    int i;
+    qemu_put_8s(f, &s->i2c_data[0]);
+    qemu_put_8s(f, &s->i2c_data[1]);
+    qemu_put_be32(f, s->i2c_len);
+    qemu_put_be32(f, s->enable);
+    qemu_put_be32(f, s->idx_in);
+    qemu_put_be32(f, s->req_in);
+    qemu_put_be32(f, s->idx_out);
+    qemu_put_be32(f, s->req_out);
+
+    for (i = 0; i < 7; i ++)
+        qemu_put_8s(f, &s->outvol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->outmute[i]);
+    for (i = 0; i < 4; i ++)
+        qemu_put_8s(f, &s->invol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->inmute[i]);
+
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->diff[i]);
+    qemu_put_8s(f, &s->pol);
+    qemu_put_8s(f, &s->ds);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->monomix[i]);
+    qemu_put_8s(f, &s->alc);
+    qemu_put_8s(f, &s->mute);
+    for (i = 0; i < 4; i ++)
+        qemu_put_8s(f, &s->path[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_put_8s(f, &s->mpath[i]);
+    qemu_put_8s(f, &s->format);
+    qemu_put_8s(f, &s->power);
+    qemu_put_be32s(f, &s->inmask);
+    qemu_put_be32s(f, &s->outmask);
+    qemu_put_byte(f, (s->rate - wm_rate_table) / sizeof(*s->rate));
+    i2c_slave_save(f, &s->i2c);
+}
+
+static int wm8750_load(QEMUFile *f, void *opaque, int version_id)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    int i;
+    qemu_get_8s(f, &s->i2c_data[0]);
+    qemu_get_8s(f, &s->i2c_data[1]);
+    s->i2c_len = qemu_get_be32(f);
+    s->enable = qemu_get_be32(f);
+    s->idx_in = qemu_get_be32(f);
+    s->req_in = qemu_get_be32(f);
+    s->idx_out = qemu_get_be32(f);
+    s->req_out = qemu_get_be32(f);
+
+    for (i = 0; i < 7; i ++)
+        qemu_get_8s(f, &s->outvol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->outmute[i]);
+    for (i = 0; i < 4; i ++)
+        qemu_get_8s(f, &s->invol[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->inmute[i]);
+
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->diff[i]);
+    qemu_get_8s(f, &s->pol);
+    qemu_get_8s(f, &s->ds);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->monomix[i]);
+    qemu_get_8s(f, &s->alc);
+    qemu_get_8s(f, &s->mute);
+    for (i = 0; i < 4; i ++)
+        qemu_get_8s(f, &s->path[i]);
+    for (i = 0; i < 2; i ++)
+        qemu_get_8s(f, &s->mpath[i]);
+    qemu_get_8s(f, &s->format);
+    qemu_get_8s(f, &s->power);
+    qemu_get_be32s(f, &s->inmask);
+    qemu_get_be32s(f, &s->outmask);
+    s->rate = &wm_rate_table[(uint8_t) qemu_get_byte(f) & 0x1f];
+    i2c_slave_load(f, &s->i2c);
+    return 0;
+}
+
+static int wm8750_iid = 0;
+
+i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
+{
+    struct wm8750_s *s = (struct wm8750_s *)
+            i2c_slave_init(bus, 0, sizeof(struct wm8750_s));
+    s->i2c.event = wm8750_event;
+    s->i2c.recv = wm8750_rx;
+    s->i2c.send = wm8750_tx;
+
+    AUD_register_card(audio, CODEC, &s->card);
+    wm8750_reset(&s->i2c);
+
+    register_savevm(CODEC, wm8750_iid ++, 0, wm8750_save, wm8750_load, s);
+
+    return &s->i2c;
+}
+
+void wm8750_fini(i2c_slave *i2c)
+{
+    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    wm8750_reset(&s->i2c);
+    AUD_remove_card(&s->card);
+    qemu_free(s);
+}
+
+void wm8750_data_req_set(i2c_slave *i2c,
+                void (*data_req)(void *, int, int), void *opaque)
+{
+    struct wm8750_s *s = (struct wm8750_s *) i2c;
+    s->data_req = data_req;
+    s->opaque = opaque;
+}
+
+void wm8750_dac_dat(void *opaque, uint32_t sample)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    uint32_t *data = (uint32_t *) &s->data_out[s->idx_out];
+    *data = sample & s->outmask;
+    s->req_out -= 4;
+    s->idx_out += 4;
+    if (s->idx_out >= sizeof(s->data_out) || s->req_out <= 0)
+        wm8750_out_flush(s);
+}
+
+uint32_t wm8750_adc_dat(void *opaque)
+{
+    struct wm8750_s *s = (struct wm8750_s *) opaque;
+    uint32_t *data;
+    if (s->idx_in >= sizeof(s->data_in))
+        wm8750_in_load(s);
+    data = (uint32_t *) &s->data_in[s->idx_in];
+    s->req_in -= 4;
+    s->idx_in += 4;
+    return *data & s->inmask;
+}
diff --git a/keymaps.c b/keymaps.c
index bd89328..f0f8c10 100644
--- a/keymaps.c
+++ b/keymaps.c
@@ -1,8 +1,8 @@
 /*
  * QEMU keysym to keycode conversion using rdesktop keymaps
- * 
+ *
  * Copyright (c) 2004 Johannes Schindelin
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
diff --git a/keymaps/common b/keymaps/common
index 0b53f1c..adc56c7 100644
--- a/keymaps/common
+++ b/keymaps/common
@@ -82,7 +82,7 @@
 
 # Printscreen, Scrollock and Pause
 # Printscreen really requires four scancodes (0xe0, 0x2a, 0xe0, 0x37),
-# but (0xe0, 0x37) seems to work. 
+# but (0xe0, 0x37) seems to work.
 Print 0xb7 localstate
 Sys_Req 0xb7 localstate
 Execute 0xb7 localstate
diff --git a/keymaps/de-ch b/keymaps/de-ch
index f83837b..852f8b8 100644
--- a/keymaps/de-ch
+++ b/keymaps/de-ch
@@ -1,5 +1,5 @@
-# rdesktop Swiss-German (de-ch) keymap file 
-# 2003-06-03 by noldi@tristar.ch 
+# rdesktop Swiss-German (de-ch) keymap file
+# 2003-06-03 by noldi@tristar.ch
 #
 include common
 map 0x00000807
@@ -40,7 +40,7 @@
 # Scan Code 9
 parenleft 0x09 shift
 cent 0x09 altgr
-# 
+#
 # Scan Code 10
 parenright 0x0a shift
 #
@@ -49,7 +49,7 @@
 braceright 0x0b altgr inhibit
 #
 # Scan Code 12
-apostrophe 0x0c 
+apostrophe 0x0c
 question 0x0c shift
 dead_acute 0x0c altgr
 #
@@ -68,10 +68,10 @@
 udiaeresis 0x1a
 egrave 0x1a shift
 bracketleft 0x1a altgr
-# 
+#
 # Scan Code 28
 dead_diaeresis 0x1b
-exclam 0x1b shift 
+exclam 0x1b shift
 bracketright 0x1b altgr
 #
 # Scan Code 40
@@ -93,17 +93,17 @@
 #
 # Scan Code 46
 y 0x2c addupper
-# 
+#
 # Scan Code 53
 comma 0x33
 semicolon 0x33 shift
-# 
+#
 # Scan Code 54
 period 0x34
 colon 0x34 shift
 #
 # Scan Code 55
-minus 0x35 
+minus 0x35
 underscore 0x35 shift
 #
 # Suppress Windows unsupported AltGr keys
diff --git a/keymaps/et b/keymaps/et
index b5a73fe..3252e31 100644
--- a/keymaps/et
+++ b/keymaps/et
@@ -50,9 +50,9 @@
 # QWERTY first row
 #
 EuroSign 0x12 altgr
-udiaeresis 0x1a 
+udiaeresis 0x1a
 Udiaeresis 0x1a shift
-otilde 0x1b 
+otilde 0x1b
 Otilde 0x1b shift
 section 0x1b altgr
 
@@ -61,9 +61,9 @@
 #
 scaron 0x1f altgr
 Scaron 0x1f altgr shift
-odiaeresis 0x27 
+odiaeresis 0x27
 Odiaeresis 0x27 shift
-adiaeresis 0x28 
+adiaeresis 0x28
 Adiaeresis 0x28 shift
 asciicircum 0x28 altgr
 apostrophe 0x2b
@@ -72,7 +72,7 @@
 #
 # QWERTY third row
 #
-less 0x56 
+less 0x56
 greater 0x56 shift
 bar 0x56 altgr
 zcaron 0x2c altgr
diff --git a/keymaps/fr b/keymaps/fr
index cbb4591..ba5a176 100644
--- a/keymaps/fr
+++ b/keymaps/fr
@@ -97,7 +97,7 @@
 thorn 0x19 altgr
 THORN 0x19 shift altgr
 
-dead_circumflex 0x1a 
+dead_circumflex 0x1a
 dead_diaeresis 0x1a shift
 dead_abovering 0x1a shift altgr
 
diff --git a/keymaps/is b/keymaps/is
index 8fde40f..d512cf6 100644
--- a/keymaps/is
+++ b/keymaps/is
@@ -1,6 +1,6 @@
-# 2004-03-16 Halldór Guðmundsson and Morten Lange 
+# 2004-03-16 Halldór Guðmundsson and Morten Lange
 # Keyboard definition file for the Icelandic keyboard
-# to be used in rdesktop 1.3.x ( See rdesktop.org) 
+# to be used in rdesktop 1.3.x ( See rdesktop.org)
 # generated from XKB map de, and changed manually
 # Location for example /usr/local/share/rdesktop/keymaps/is
 include common
@@ -71,8 +71,8 @@
 #Udiaeresis 0x1a shift
 #dead_diaeresis 0x1a altgr
 #dead_abovering 0x1a shift altgr
-eth 0x1a 
-ETH 0x1a shift 
+eth 0x1a
+ETH 0x1a shift
 apostrophe 0x1b
 question 0x1b shift
 #plus 0x1b
@@ -84,9 +84,9 @@
 #ae 0x1e altgr
 #AE 0x1e shift altgr
 #eth 0x20 altgr
-#eth 0x20 
+#eth 0x20
 #ETH 0x20 shift altgr
-#ETH 0x20 shift 
+#ETH 0x20 shift
 dstroke 0x21 altgr
 ordfeminine 0x21 shift altgr
 eng 0x22 altgr
@@ -96,8 +96,8 @@
 kra 0x25 altgr
 #adiaeresis 0x27
 #Adiaeresis 0x27 shift
-ae 0x27 
-AE 0x27 shift 
+ae 0x27
+AE 0x27 shift
 dead_doubleacute 0x27 altgr
 #adiaeresis 0x28
 #Adiaeresis 0x28 shift
@@ -133,8 +133,8 @@
 division 0x34 shift altgr
 #minus 0x35
 #underscore 0x35 shift
-thorn 0x35 
-THORN 0x35 shift 
+thorn 0x35
+THORN 0x35 shift
 dead_belowdot 0x35 altgr
 dead_abovedot 0x35 shift altgr
 
diff --git a/keymaps/modifiers b/keymaps/modifiers
index d8b019f..84a04d6 100644
--- a/keymaps/modifiers
+++ b/keymaps/modifiers
@@ -8,10 +8,10 @@
 Control_R 0x9d
 Control_L 0x1d
 
-# Translate Super to Windows keys. 
-# This is hardcoded. See documentation for details. 
+# Translate Super to Windows keys.
+# This is hardcoded. See documentation for details.
 Super_R 0xdb
 Super_L 0xdc
 
-# Translate Menu to the Windows Application key. 
+# Translate Menu to the Windows Application key.
 Menu 0xdd
diff --git a/keymaps/nl b/keymaps/nl
index bc823bd..4f0fe3d 100644
--- a/keymaps/nl
+++ b/keymaps/nl
@@ -45,7 +45,7 @@
 greater 0x2b shift
 guillemotleft 0x2c altgr
 guillemotright 0x2d altgr
-copyright 0x2e altgr 
+copyright 0x2e altgr
 mu 0x32 altgr
 comma 0x33
 semicolon 0x33 shift
diff --git a/keymaps/sv b/keymaps/sv
index 736d637..9905a48 100644
--- a/keymaps/sv
+++ b/keymaps/sv
@@ -50,18 +50,18 @@
 # QWERTY first row
 #
 EuroSign 0x12 altgr
-aring 0x1a 
+aring 0x1a
 Aring 0x1a shift
-dead_diaeresis 0x1b 
+dead_diaeresis 0x1b
 dead_circumflex 0x1b shift
 dead_tilde 0x1b altgr
 
 #
 # QWERTY second row
 #
-odiaeresis 0x27 
+odiaeresis 0x27
 Odiaeresis 0x27 shift
-adiaeresis 0x28 
+adiaeresis 0x28
 Adiaeresis 0x28 shift
 apostrophe 0x2b
 asterisk 0x2b shift
diff --git a/kqemu.c b/kqemu.c
index 96ca582..9e2d1d6 100644
--- a/kqemu.c
+++ b/kqemu.c
@@ -1,6 +1,6 @@
 /*
  *  KQEMU support
- * 
+ *
  *  Copyright (c) 2005 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -27,7 +27,7 @@
 #include <sys/ioctl.h>
 #endif
 #ifdef HOST_SOLARIS
-#include <sys/modctl.h>
+#include <sys/ioccom.h>
 #endif
 #include <stdlib.h>
 #include <stdio.h>
@@ -129,9 +129,9 @@
        target cpus because they are important for user code. Strictly
        speaking, only SSE really matters because the OS must support
        it if the user code uses it. */
-    critical_features_mask = 
-        CPUID_CMOV | CPUID_CX8 | 
-        CPUID_FXSR | CPUID_MMX | CPUID_SSE | 
+    critical_features_mask =
+        CPUID_CMOV | CPUID_CX8 |
+        CPUID_FXSR | CPUID_MMX | CPUID_SSE |
         CPUID_SSE2 | CPUID_SEP;
     ext_features_mask = CPUID_EXT_SSE3 | CPUID_EXT_MONITOR;
     if (!is_cpuid_supported()) {
@@ -177,7 +177,8 @@
     kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
 #endif
     if (kqemu_fd == KQEMU_INVALID_FD) {
-        fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
+        fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated: %s\n",
+                KQEMU_DEVICE, strerror(errno));
         return -1;
     }
     version = 0;
@@ -193,17 +194,17 @@
         goto fail;
     }
 
-    pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH * 
+    pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH *
                                   sizeof(unsigned long));
     if (!pages_to_flush)
         goto fail;
 
-    ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE * 
+    ram_pages_to_update = qemu_vmalloc(KQEMU_MAX_RAM_PAGES_TO_UPDATE *
                                        sizeof(unsigned long));
     if (!ram_pages_to_update)
         goto fail;
 
-    modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES * 
+    modified_ram_pages = qemu_vmalloc(KQEMU_MAX_MODIFIED_RAM_PAGES *
                                       sizeof(unsigned long));
     if (!modified_ram_pages)
         goto fail;
@@ -285,7 +286,7 @@
 {
     int i;
     unsigned long page_index;
-    
+
     for(i = 0; i < nb_modified_ram_pages; i++) {
         page_index = modified_ram_pages[i] >> TARGET_PAGE_BITS;
         modified_ram_pages_table[page_index] = 0;
@@ -311,12 +312,12 @@
         if (nb_modified_ram_pages >= KQEMU_MAX_MODIFIED_RAM_PAGES) {
             /* flush */
 #ifdef _WIN32
-            ret = DeviceIoControl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, 
-                                  &nb_modified_ram_pages, 
+            ret = DeviceIoControl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES,
+                                  &nb_modified_ram_pages,
                                   sizeof(nb_modified_ram_pages),
                                   NULL, 0, &temp, NULL);
 #else
-            ret = ioctl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES, 
+            ret = ioctl(kqemu_fd, KQEMU_MODIFY_RAM_PAGES,
                         &nb_modified_ram_pages);
 #endif
             kqemu_reset_modified_ram_pages();
@@ -363,7 +364,7 @@
 {
     int fptag, i, j;
     struct fpstate fp1, *fp = &fp1;
-    
+
     fp->fpuc = env->fpuc;
     fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
     fptag = 0;
@@ -383,7 +384,7 @@
     }
     asm volatile ("frstor %0" : "=m" (*fp));
 }
- 
+
 static void save_native_fp_fsave(CPUState *env)
 {
     int fptag, i, j;
@@ -469,7 +470,7 @@
                       struct kqemu_cpu_state *kenv)
 {
     int selector;
-    
+
     selector = (env->star >> 32) & 0xffff;
 #ifdef __x86_64__
     if (env->hflags & HF_LMA_MASK) {
@@ -481,12 +482,12 @@
         code64 = env->hflags & HF_CS64_MASK;
 
         cpu_x86_set_cpl(env, 0);
-        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
-                               0, 0xffffffff, 
+        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+                               0, 0xffffffff,
                                DESC_G_MASK | DESC_P_MASK |
                                DESC_S_MASK |
                                DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
-        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK |
@@ -496,18 +497,18 @@
             env->eip = env->lstar;
         else
             env->eip = env->cstar;
-    } else 
+    } else
 #endif
     {
         env->regs[R_ECX] = (uint32_t)kenv->next_eip;
-        
+
         cpu_x86_set_cpl(env, 0);
-        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
-                           0, 0xffffffff, 
+        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+                           0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK |
                                DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
-        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK |
@@ -604,7 +605,7 @@
         }
     }
     qsort(pr, nb_pc_records, sizeof(PCRecord *), pc_rec_cmp);
-    
+
     f = fopen("/tmp/kqemu.stats", "w");
     if (!f) {
         perror("/tmp/kqemu.stats");
@@ -615,9 +616,9 @@
     for(i = 0; i < nb_pc_records; i++) {
         r = pr[i];
         sum += r->count;
-        fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n", 
-                r->pc, 
-                r->count, 
+        fprintf(f, "%08lx: %" PRId64 " %0.2f%% %0.2f%%\n",
+                r->pc,
+                r->count,
                 (double)r->count / (double)total * 100.0,
                 (double)sum / (double)total * 100.0);
     }
@@ -696,7 +697,7 @@
     kenv->nb_ram_pages_to_update = nb_ram_pages_to_update;
 #endif
     nb_ram_pages_to_update = 0;
-    
+
 #if KQEMU_VERSION >= 0x010300
     kenv->nb_modified_ram_pages = nb_modified_ram_pages;
 #endif
@@ -788,7 +789,7 @@
     {
         unsigned int new_hflags;
 #ifdef TARGET_X86_64
-        if ((env->hflags & HF_LMA_MASK) && 
+        if ((env->hflags & HF_LMA_MASK) &&
             (env->segs[R_CS].flags & DESC_L_MASK)) {
             /* long mode */
             new_hflags = HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
@@ -800,7 +801,7 @@
                 >> (DESC_B_SHIFT - HF_CS32_SHIFT);
             new_hflags |= (env->segs[R_SS].flags & DESC_B_MASK)
                 >> (DESC_B_SHIFT - HF_SS32_SHIFT);
-            if (!(env->cr[0] & CR0_PE_MASK) || 
+            if (!(env->cr[0] & CR0_PE_MASK) ||
                    (env->eflags & VM_MASK) ||
                    !(env->hflags & HF_CS32_MASK)) {
                 /* XXX: try to avoid this test. The problem comes from the
@@ -810,13 +811,13 @@
                    translate-i386.c. */
                 new_hflags |= HF_ADDSEG_MASK;
             } else {
-                new_hflags |= ((env->segs[R_DS].base | 
+                new_hflags |= ((env->segs[R_DS].base |
                                 env->segs[R_ES].base |
-                                env->segs[R_SS].base) != 0) << 
+                                env->segs[R_SS].base) != 0) <<
                     HF_ADDSEG_SHIFT;
             }
         }
-        env->hflags = (env->hflags & 
+        env->hflags = (env->hflags &
            ~(HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK)) |
             new_hflags;
     }
@@ -827,7 +828,7 @@
         env->hflags |= HF_OSFXSR_MASK;
     else
         env->hflags &= ~HF_OSFXSR_MASK;
-        
+
 #ifdef DEBUG
     if (loglevel & CPU_LOG_INT) {
         fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
@@ -836,7 +837,7 @@
     if (ret == KQEMU_RET_SYSCALL) {
         /* syscall instruction */
         return do_syscall(env, kenv);
-    } else 
+    } else
     if ((ret & 0xff00) == KQEMU_RET_INT) {
         env->exception_index = ret & 0xff;
         env->error_code = 0;
@@ -847,7 +848,7 @@
 #endif
 #ifdef DEBUG
         if (loglevel & CPU_LOG_INT) {
-            fprintf(logfile, "kqemu: interrupt v=%02x:\n", 
+            fprintf(logfile, "kqemu: interrupt v=%02x:\n",
                     env->exception_index);
             cpu_dump_state(env, logfile, fprintf, 0);
         }
@@ -879,7 +880,7 @@
         }
 #endif
         return 0;
-    } else if (ret == KQEMU_RET_SOFTMMU) { 
+    } else if (ret == KQEMU_RET_SOFTMMU) {
 #ifdef CONFIG_PROFILER
         {
             unsigned long pc = env->eip + env->segs[R_CS].base;
@@ -903,7 +904,7 @@
 void kqemu_cpu_interrupt(CPUState *env)
 {
 #if defined(_WIN32) && KQEMU_VERSION >= 0x010101
-    /* cancelling the I/O request causes KQEMU to finish executing the 
+    /* cancelling the I/O request causes KQEMU to finish executing the
        current block and successfully returning. */
     CancelIo(kqemu_fd);
 #endif
diff --git a/kqemu.h b/kqemu.h
index 892e335..7b43057 100644
--- a/kqemu.h
+++ b/kqemu.h
@@ -1,8 +1,8 @@
 /*
  * KQEMU header
- * 
+ *
  * Copyright (c) 2004-2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -91,7 +91,7 @@
     long retval;
 
     /* number of ram_dirty entries to update */
-    unsigned int nb_ram_pages_to_update; 
+    unsigned int nb_ram_pages_to_update;
 #define KQEMU_MAX_RAM_PAGES_TO_UPDATE 512
 #define KQEMU_RAM_PAGES_UPDATE_ALL (KQEMU_MAX_RAM_PAGES_TO_UPDATE + 1)
 
diff --git a/linux-user/alpha/syscall.h b/linux-user/alpha/syscall.h
new file mode 100644
index 0000000..6435817
--- /dev/null
+++ b/linux-user/alpha/syscall.h
@@ -0,0 +1,41 @@
+/* default linux values for the selectors */
+#define __USER_DS	(1)
+
+struct target_pt_regs {
+	target_ulong r0;
+	target_ulong r1;
+	target_ulong r2;
+	target_ulong r3;
+	target_ulong r4;
+	target_ulong r5;
+	target_ulong r6;
+	target_ulong r7;
+	target_ulong r8;
+	target_ulong r19;
+	target_ulong r20;
+	target_ulong r21;
+	target_ulong r22;
+	target_ulong r23;
+	target_ulong r24;
+	target_ulong r25;
+	target_ulong r26;
+	target_ulong r27;
+	target_ulong r28;
+	target_ulong hae;
+/* JRP - These are the values provided to a0-a2 by PALcode */
+	target_ulong trap_a0;
+	target_ulong trap_a1;
+	target_ulong trap_a2;
+/* These are saved by PAL-code: */
+	target_ulong ps;
+	target_ulong pc;
+	target_ulong gp;
+	target_ulong r16;
+	target_ulong r17;
+	target_ulong r18;
+/* Those is needed by qemu to temporary store the user stack pointer */
+        target_ulong usp;
+        target_ulong unique;
+};
+
+#define UNAME_MACHINE "alpha"
diff --git a/linux-user/alpha/syscall_nr.h b/linux-user/alpha/syscall_nr.h
new file mode 100644
index 0000000..d3c19cc
--- /dev/null
+++ b/linux-user/alpha/syscall_nr.h
@@ -0,0 +1,413 @@
+#define TARGET_NR_osf_syscall	  0	/* not implemented */
+#define TARGET_NR_exit		  1
+#define TARGET_NR_fork		  2
+#define TARGET_NR_read		  3
+#define TARGET_NR_write		  4
+#define TARGET_NR_osf_old_open	  5	/* not implemented */
+#define TARGET_NR_close		  6
+#define TARGET_NR_osf_wait4		  7
+#define TARGET_NR_osf_old_creat	  8	/* not implemented */
+#define TARGET_NR_link		  9
+#define TARGET_NR_unlink		 10
+#define TARGET_NR_osf_execve		 11	/* not implemented */
+#define TARGET_NR_chdir		 12
+#define TARGET_NR_fchdir		 13
+#define TARGET_NR_mknod		 14
+#define TARGET_NR_chmod		 15
+#define TARGET_NR_chown		 16
+#define TARGET_NR_brk		 17
+#define TARGET_NR_osf_getfsstat	 18	/* not implemented */
+#define TARGET_NR_lseek		 19
+#define TARGET_NR_getxpid		 20
+#define TARGET_NR_osf_mount		 21
+#define TARGET_NR_umount		 22
+#define TARGET_NR_setuid		 23
+#define TARGET_NR_getxuid		 24
+#define TARGET_NR_exec_with_loader	 25	/* not implemented */
+#define TARGET_NR_ptrace		 26
+#define TARGET_NR_osf_nrecvmsg	 27	/* not implemented */
+#define TARGET_NR_osf_nsendmsg	 28	/* not implemented */
+#define TARGET_NR_osf_nrecvfrom	 29	/* not implemented */
+#define TARGET_NR_osf_naccept	 30	/* not implemented */
+#define TARGET_NR_osf_ngetpeername	 31	/* not implemented */
+#define TARGET_NR_osf_ngetsockname	 32	/* not implemented */
+#define TARGET_NR_access		 33
+#define TARGET_NR_osf_chflags	 34	/* not implemented */
+#define TARGET_NR_osf_fchflags	 35	/* not implemented */
+#define TARGET_NR_sync		 36
+#define TARGET_NR_kill		 37
+#define TARGET_NR_osf_old_stat	 38	/* not implemented */
+#define TARGET_NR_setpgid		 39
+#define TARGET_NR_osf_old_lstat	 40	/* not implemented */
+#define TARGET_NR_dup		 41
+#define TARGET_NR_pipe		 42
+#define TARGET_NR_osf_set_program_attributes	43
+#define TARGET_NR_osf_profil		 44	/* not implemented */
+#define TARGET_NR_open		 45
+#define TARGET_NR_osf_old_sigaction	 46	/* not implemented */
+#define TARGET_NR_getxgid		 47
+#define TARGET_NR_osf_sigprocmask	 48
+#define TARGET_NR_osf_getlogin	 49	/* not implemented */
+#define TARGET_NR_osf_setlogin	 50	/* not implemented */
+#define TARGET_NR_acct		 51
+#define TARGET_NR_sigpending		 52
+
+#define TARGET_NR_ioctl		 54
+#define TARGET_NR_osf_reboot		 55	/* not implemented */
+#define TARGET_NR_osf_revoke		 56	/* not implemented */
+#define TARGET_NR_symlink		 57
+#define TARGET_NR_readlink		 58
+#define TARGET_NR_execve		 59
+#define TARGET_NR_umask		 60
+#define TARGET_NR_chroot		 61
+#define TARGET_NR_osf_old_fstat	 62	/* not implemented */
+#define TARGET_NR_getpgrp		 63
+#define TARGET_NR_getpagesize	 64
+#define TARGET_NR_osf_mremap		 65	/* not implemented */
+#define TARGET_NR_vfork		 66
+#define TARGET_NR_stat		 67
+#define TARGET_NR_lstat		 68
+#define TARGET_NR_osf_sbrk		 69	/* not implemented */
+#define TARGET_NR_osf_sstk		 70	/* not implemented */
+#define TARGET_NR_mmap		 71	/* OSF/1 mmap is superset of Linux */
+#define TARGET_NR_osf_old_vadvise	 72	/* not implemented */
+#define TARGET_NR_munmap		 73
+#define TARGET_NR_mprotect		 74
+#define TARGET_NR_madvise		 75
+#define TARGET_NR_vhangup		 76
+#define TARGET_NR_osf_kmodcall	 77	/* not implemented */
+#define TARGET_NR_osf_mincore	 78	/* not implemented */
+#define TARGET_NR_getgroups		 79
+#define TARGET_NR_setgroups		 80
+#define TARGET_NR_osf_old_getpgrp	 81	/* not implemented */
+#define TARGET_NR_setpgrp		 82	/* BSD alias for setpgid */
+#define TARGET_NR_osf_setitimer	 83
+#define TARGET_NR_osf_old_wait	 84	/* not implemented */
+#define TARGET_NR_osf_table		 85	/* not implemented */
+#define TARGET_NR_osf_getitimer	 86
+#define TARGET_NR_gethostname	 87
+#define TARGET_NR_sethostname	 88
+#define TARGET_NR_getdtablesize	 89
+#define TARGET_NR_dup2		 90
+#define TARGET_NR_fstat		 91
+#define TARGET_NR_fcntl		 92
+#define TARGET_NR_osf_select		 93
+#define TARGET_NR_poll		 94
+#define TARGET_NR_fsync		 95
+#define TARGET_NR_setpriority	 96
+#define TARGET_NR_socket		 97
+#define TARGET_NR_connect		 98
+#define TARGET_NR_accept		 99
+#define TARGET_NR_getpriority	100
+#define TARGET_NR_send		101
+#define TARGET_NR_recv		102
+#define TARGET_NR_sigreturn		103
+#define TARGET_NR_bind		104
+#define TARGET_NR_setsockopt		105
+#define TARGET_NR_listen		106
+#define TARGET_NR_osf_plock		107	/* not implemented */
+#define TARGET_NR_osf_old_sigvec	108	/* not implemented */
+#define TARGET_NR_osf_old_sigblock	109	/* not implemented */
+#define TARGET_NR_osf_old_sigsetmask	110	/* not implemented */
+#define TARGET_NR_sigsuspend		111
+#define TARGET_NR_osf_sigstack	112
+#define TARGET_NR_recvmsg		113
+#define TARGET_NR_sendmsg		114
+#define TARGET_NR_osf_old_vtrace	115	/* not implemented */
+#define TARGET_NR_osf_gettimeofday	116
+#define TARGET_NR_osf_getrusage	117
+#define TARGET_NR_getsockopt		118
+
+#define TARGET_NR_readv		120
+#define TARGET_NR_writev		121
+#define TARGET_NR_osf_settimeofday	122
+#define TARGET_NR_fchown		123
+#define TARGET_NR_fchmod		124
+#define TARGET_NR_recvfrom		125
+#define TARGET_NR_setreuid		126
+#define TARGET_NR_setregid		127
+#define TARGET_NR_rename		128
+#define TARGET_NR_truncate		129
+#define TARGET_NR_ftruncate		130
+#define TARGET_NR_flock		131
+#define TARGET_NR_setgid		132
+#define TARGET_NR_sendto		133
+#define TARGET_NR_shutdown		134
+#define TARGET_NR_socketpair		135
+#define TARGET_NR_mkdir		136
+#define TARGET_NR_rmdir		137
+#define TARGET_NR_osf_utimes		138
+#define TARGET_NR_osf_old_sigreturn	139	/* not implemented */
+#define TARGET_NR_osf_adjtime	140	/* not implemented */
+#define TARGET_NR_getpeername	141
+#define TARGET_NR_osf_gethostid	142	/* not implemented */
+#define TARGET_NR_osf_sethostid	143	/* not implemented */
+#define TARGET_NR_getrlimit		144
+#define TARGET_NR_setrlimit		145
+#define TARGET_NR_osf_old_killpg	146	/* not implemented */
+#define TARGET_NR_setsid		147
+#define TARGET_NR_quotactl		148
+#define TARGET_NR_osf_oldquota	149	/* not implemented */
+#define TARGET_NR_getsockname	150
+
+#define TARGET_NR_osf_pid_block	153	/* not implemented */
+#define TARGET_NR_osf_pid_unblock	154	/* not implemented */
+
+#define TARGET_NR_sigaction		156
+#define TARGET_NR_osf_sigwaitprim	157	/* not implemented */
+#define TARGET_NR_osf_nfssvc		158	/* not implemented */
+#define TARGET_NR_osf_getdirentries	159
+#define TARGET_NR_osf_statfs		160
+#define TARGET_NR_osf_fstatfs	161
+
+#define TARGET_NR_osf_asynch_daemon	163	/* not implemented */
+#define TARGET_NR_osf_getfh		164	/* not implemented */
+#define TARGET_NR_osf_getdomainname	165
+#define TARGET_NR_setdomainname	166
+
+#define TARGET_NR_osf_exportfs	169	/* not implemented */
+
+#define TARGET_NR_osf_alt_plock	181	/* not implemented */
+
+#define TARGET_NR_osf_getmnt		184	/* not implemented */
+
+#define TARGET_NR_osf_alt_sigpending	187	/* not implemented */
+#define TARGET_NR_osf_alt_setsid	188	/* not implemented */
+
+#define TARGET_NR_osf_swapon		199
+#define TARGET_NR_msgctl		200
+#define TARGET_NR_msgget		201
+#define TARGET_NR_msgrcv		202
+#define TARGET_NR_msgsnd		203
+#define TARGET_NR_semctl		204
+#define TARGET_NR_semget		205
+#define TARGET_NR_semop		206
+#define TARGET_NR_osf_utsname	207
+#define TARGET_NR_lchown		208
+#define TARGET_NR_osf_shmat		209
+#define TARGET_NR_shmctl		210
+#define TARGET_NR_shmdt		211
+#define TARGET_NR_shmget		212
+#define TARGET_NR_osf_mvalid		213	/* not implemented */
+#define TARGET_NR_osf_getaddressconf	214	/* not implemented */
+#define TARGET_NR_osf_msleep		215	/* not implemented */
+#define TARGET_NR_osf_mwakeup	216	/* not implemented */
+#define TARGET_NR_msync		217
+#define TARGET_NR_osf_signal		218	/* not implemented */
+#define TARGET_NR_osf_utc_gettime	219	/* not implemented */
+#define TARGET_NR_osf_utc_adjtime	220	/* not implemented */
+
+#define TARGET_NR_osf_security	222	/* not implemented */
+#define TARGET_NR_osf_kloadcall	223	/* not implemented */
+
+#define TARGET_NR_getpgid		233
+#define TARGET_NR_getsid		234
+#define TARGET_NR_sigaltstack	235
+#define TARGET_NR_osf_waitid		236	/* not implemented */
+#define TARGET_NR_osf_priocntlset	237	/* not implemented */
+#define TARGET_NR_osf_sigsendset	238	/* not implemented */
+#define TARGET_NR_osf_set_speculative	239	/* not implemented */
+#define TARGET_NR_osf_msfs_syscall	240	/* not implemented */
+#define TARGET_NR_osf_sysinfo	241
+#define TARGET_NR_osf_uadmin		242	/* not implemented */
+#define TARGET_NR_osf_fuser		243	/* not implemented */
+#define TARGET_NR_osf_proplist_syscall    244
+#define TARGET_NR_osf_ntp_adjtime	245	/* not implemented */
+#define TARGET_NR_osf_ntp_gettime	246	/* not implemented */
+#define TARGET_NR_osf_pathconf	247	/* not implemented */
+#define TARGET_NR_osf_fpathconf	248	/* not implemented */
+
+#define TARGET_NR_osf_uswitch	250	/* not implemented */
+#define TARGET_NR_osf_usleep_thread	251
+#define TARGET_NR_osf_audcntl	252	/* not implemented */
+#define TARGET_NR_osf_audgen		253	/* not implemented */
+#define TARGET_NR_sysfs		254
+#define TARGET_NR_osf_subsys_info	255	/* not implemented */
+#define TARGET_NR_osf_getsysinfo	256
+#define TARGET_NR_osf_setsysinfo	257
+#define TARGET_NR_osf_afs_syscall	258	/* not implemented */
+#define TARGET_NR_osf_swapctl	259	/* not implemented */
+#define TARGET_NR_osf_memcntl	260	/* not implemented */
+#define TARGET_NR_osf_fdatasync	261	/* not implemented */
+
+
+/*
+ * Linux-specific system calls begin at 300
+ */
+#define TARGET_NR_bdflush		300
+#define TARGET_NR_sethae		301
+#define TARGET_NR_mount		302
+#define TARGET_NR_old_adjtimex	303
+#define TARGET_NR_swapoff		304
+#define TARGET_NR_getdents		305
+#define TARGET_NR_create_module	306
+#define TARGET_NR_init_module	307
+#define TARGET_NR_delete_module	308
+#define TARGET_NR_get_kernel_syms	309
+#define TARGET_NR_syslog		310
+#define TARGET_NR_reboot		311
+#define TARGET_NR_clone		312
+#define TARGET_NR_uselib		313
+#define TARGET_NR_mlock		314
+#define TARGET_NR_munlock		315
+#define TARGET_NR_mlockall		316
+#define TARGET_NR_munlockall		317
+#define TARGET_NR_sysinfo		318
+#define TARGET_NR__sysctl		319
+/* 320 was sys_idle.  */
+#define TARGET_NR_oldumount		321
+#define TARGET_NR_swapon		322
+#define TARGET_NR_times		323
+#define TARGET_NR_personality	324
+#define TARGET_NR_setfsuid		325
+#define TARGET_NR_setfsgid		326
+#define TARGET_NR_ustat		327
+#define TARGET_NR_statfs		328
+#define TARGET_NR_fstatfs		329
+#define TARGET_NR_sched_setparam		330
+#define TARGET_NR_sched_getparam		331
+#define TARGET_NR_sched_setscheduler		332
+#define TARGET_NR_sched_getscheduler		333
+#define TARGET_NR_sched_yield		334
+#define TARGET_NR_sched_get_priority_max	335
+#define TARGET_NR_sched_get_priority_min	336
+#define TARGET_NR_sched_rr_get_interval	337
+#define TARGET_NR_afs_syscall		338
+#define TARGET_NR_uname			339
+#define TARGET_NR_nanosleep			340
+#define TARGET_NR_mremap			341
+#define TARGET_NR_nfsservctl			342
+#define TARGET_NR_setresuid			343
+#define TARGET_NR_getresuid			344
+#define TARGET_NR_pciconfig_read		345
+#define TARGET_NR_pciconfig_write		346
+#define TARGET_NR_query_module		347
+#define TARGET_NR_prctl			348
+#define TARGET_NR_pread64			349
+#define TARGET_NR_pwrite64			350
+#define TARGET_NR_rt_sigreturn		351
+#define TARGET_NR_rt_sigaction		352
+#define TARGET_NR_rt_sigprocmask		353
+#define TARGET_NR_rt_sigpending		354
+#define TARGET_NR_rt_sigtimedwait		355
+#define TARGET_NR_rt_sigqueueinfo		356
+#define TARGET_NR_rt_sigsuspend		357
+#define TARGET_NR_select			358
+#define TARGET_NR_gettimeofday		359
+#define TARGET_NR_settimeofday		360
+#define TARGET_NR_getitimer			361
+#define TARGET_NR_setitimer			362
+#define TARGET_NR_utimes			363
+#define TARGET_NR_getrusage			364
+#define TARGET_NR_wait4			365
+#define TARGET_NR_adjtimex			366
+#define TARGET_NR_getcwd			367
+#define TARGET_NR_capget			368
+#define TARGET_NR_capset			369
+#define TARGET_NR_sendfile			370
+#define TARGET_NR_setresgid			371
+#define TARGET_NR_getresgid			372
+#define TARGET_NR_dipc			373
+#define TARGET_NR_pivot_root			374
+#define TARGET_NR_mincore			375
+#define TARGET_NR_pciconfig_iobase		376
+#define TARGET_NR_getdents64			377
+#define TARGET_NR_gettid			378
+#define TARGET_NR_readahead			379
+/* 380 is unused */
+#define TARGET_NR_tkill			381
+#define TARGET_NR_setxattr			382
+#define TARGET_NR_lsetxattr			383
+#define TARGET_NR_fsetxattr			384
+#define TARGET_NR_getxattr			385
+#define TARGET_NR_lgetxattr			386
+#define TARGET_NR_fgetxattr			387
+#define TARGET_NR_listxattr			388
+#define TARGET_NR_llistxattr			389
+#define TARGET_NR_flistxattr			390
+#define TARGET_NR_removexattr		391
+#define TARGET_NR_lremovexattr		392
+#define TARGET_NR_fremovexattr		393
+#define TARGET_NR_futex			394
+#define TARGET_NR_sched_setaffinity		395
+#define TARGET_NR_sched_getaffinity		396
+#define TARGET_NR_tuxcall			397
+#define TARGET_NR_io_setup			398
+#define TARGET_NR_io_destroy			399
+#define TARGET_NR_io_getevents		400
+#define TARGET_NR_io_submit			401
+#define TARGET_NR_io_cancel			402
+#define TARGET_NR_exit_group			405
+#define TARGET_NR_lookup_dcookie		406
+#define TARGET_NR_sys_epoll_create		407
+#define TARGET_NR_sys_epoll_ctl		408
+#define TARGET_NR_sys_epoll_wait		409
+#define TARGET_NR_remap_file_pages		410
+#define TARGET_NR_set_tid_address		411
+#define TARGET_NR_restart_syscall		412
+#define TARGET_NR_fadvise64			413
+#define TARGET_NR_timer_create		414
+#define TARGET_NR_timer_settime		415
+#define TARGET_NR_timer_gettime		416
+#define TARGET_NR_timer_getoverrun		417
+#define TARGET_NR_timer_delete		418
+#define TARGET_NR_clock_settime		419
+#define TARGET_NR_clock_gettime		420
+#define TARGET_NR_clock_getres		421
+#define TARGET_NR_clock_nanosleep		422
+#define TARGET_NR_semtimedop			423
+#define TARGET_NR_tgkill			424
+#define TARGET_NR_stat64			425
+#define TARGET_NR_lstat64			426
+#define TARGET_NR_fstat64			427
+#define TARGET_NR_vserver			428
+#define TARGET_NR_mbind			429
+#define TARGET_NR_get_mempolicy		430
+#define TARGET_NR_set_mempolicy		431
+#define TARGET_NR_mq_open			432
+#define TARGET_NR_mq_unlink			433
+#define TARGET_NR_mq_timedsend		434
+#define TARGET_NR_mq_timedreceive		435
+#define TARGET_NR_mq_notify			436
+#define TARGET_NR_mq_getsetattr		437
+#define TARGET_NR_waitid			438
+#define TARGET_NR_add_key			439
+#define TARGET_NR_request_key		440
+#define TARGET_NR_keyctl			441
+#define TARGET_NR_ioprio_set			442
+#define TARGET_NR_ioprio_get			443
+#define TARGET_NR_inotify_init		444
+#define TARGET_NR_inotify_add_watch		445
+#define TARGET_NR_inotify_rm_watch		446
+#define TARGET_NR_fdatasync			447
+#define TARGET_NR_kexec_load			448
+#define TARGET_NR_migrate_pages		449
+#define TARGET_NR_openat			450
+#define TARGET_NR_mkdirat			451
+#define TARGET_NR_mknodat			452
+#define TARGET_NR_fchownat			453
+#define TARGET_NR_futimesat			454
+#define TARGET_NR_fstatat64			455
+#define TARGET_NR_unlinkat			456
+#define TARGET_NR_renameat			457
+#define TARGET_NR_linkat			458
+#define TARGET_NR_symlinkat			459
+#define TARGET_NR_readlinkat			460
+#define TARGET_NR_fchmodat			461
+#define TARGET_NR_faccessat			462
+#define TARGET_NR_pselect6			463
+#define TARGET_NR_ppoll			464
+#define TARGET_NR_unshare			465
+#define TARGET_NR_set_robust_list		466
+#define TARGET_NR_get_robust_list		467
+#define TARGET_NR_splice			468
+#define TARGET_NR_sync_file_range		469
+#define TARGET_NR_tee			470
+#define TARGET_NR_vmsplice			471
+#define TARGET_NR_move_pages			472
+#define TARGET_NR_getcpu			473
+#define TARGET_NR_epoll_pwait		474
+#define TARGET_NR_utimensat			475
+#define TARGET_NR_signalfd			476
+#define TARGET_NR_timerfd			477
+#define TARGET_NR_eventfd			478
diff --git a/linux-user/alpha/target_signal.h b/linux-user/alpha/target_signal.h
new file mode 100644
index 0000000..7618c3e
--- /dev/null
+++ b/linux-user/alpha/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	4096
+#define TARGET_SIGSTKSZ		16384
+
+static inline target_ulong get_sp_from_cpustate(CPUAlphaState *state)
+{
+    return state->ir[IR_SP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/alpha/termbits.h b/linux-user/alpha/termbits.h
new file mode 100644
index 0000000..86d0982
--- /dev/null
+++ b/linux-user/alpha/termbits.h
@@ -0,0 +1,265 @@
+typedef unsigned char	target_cc_t;
+typedef unsigned int	target_speed_t;
+typedef unsigned int	target_tcflag_t;
+
+#define TARGET_NCCS 19
+struct target_termios {
+	target_tcflag_t c_iflag;		/* input mode flags */
+	target_tcflag_t c_oflag;		/* output mode flags */
+	target_tcflag_t c_cflag;		/* control mode flags */
+	target_tcflag_t c_lflag;		/* local mode flags */
+	target_cc_t c_cc[TARGET_NCCS];		/* control characters */
+	target_cc_t c_line;			/* line discipline (== c_cc[19]) */
+	target_speed_t c_ispeed;		/* input speed */
+	target_speed_t c_ospeed;		/* output speed */
+};
+
+/* c_cc characters */
+#define TARGET_VEOF 0
+#define TARGET_VEOL 1
+#define TARGET_VEOL2 2
+#define TARGET_VERASE 3
+#define TARGET_VWERASE 4
+#define TARGET_VKILL 5
+#define TARGET_VREPRINT 6
+#define TARGET_VSWTC 7
+#define TARGET_VINTR 8
+#define TARGET_VQUIT 9
+#define TARGET_VSUSP 10
+#define TARGET_VSTART 12
+#define TARGET_VSTOP 13
+#define TARGET_VLNEXT 14
+#define TARGET_VDISCARD 15
+#define TARGET_VMIN 16
+#define TARGET_VTIME 17
+
+/* c_iflag bits */
+#define TARGET_IGNBRK	0000001
+#define TARGET_BRKINT	0000002
+#define TARGET_IGNPAR	0000004
+#define TARGET_PARMRK	0000010
+#define TARGET_INPCK	0000020
+#define TARGET_ISTRIP	0000040
+#define TARGET_INLCR	0000100
+#define TARGET_IGNCR	0000200
+#define TARGET_ICRNL	0000400
+#define TARGET_IXON	0001000
+#define TARGET_IXOFF	0002000
+#define TARGET_IXANY	0004000
+#define TARGET_IUCLC	0010000
+#define TARGET_IMAXBEL	0020000
+#define TARGET_IUTF8	0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0000001
+#define TARGET_ONLCR	0000002
+#define TARGET_OLCUC	0000004
+
+#define TARGET_OCRNL	0000010
+#define TARGET_ONOCR	0000020
+#define TARGET_ONLRET	0000040
+
+#define TARGET_OFILL	00000100
+#define TARGET_OFDEL	00000200
+#define TARGET_NLDLY	00001400
+#define   TARGET_NL0	00000000
+#define   TARGET_NL1	00000400
+#define   TARGET_NL2	00001000
+#define   TARGET_NL3	00001400
+#define TARGET_TABDLY	00006000
+#define   TARGET_TAB0	00000000
+#define   TARGET_TAB1	00002000
+#define   TARGET_TAB2	00004000
+#define   TARGET_TAB3	00006000
+#define TARGET_CRDLY	00030000
+#define   TARGET_CR0	00000000
+#define   TARGET_CR1	00010000
+#define   TARGET_CR2	00020000
+#define   TARGET_CR3	00030000
+#define TARGET_FFDLY	00040000
+#define   TARGET_FF0	00000000
+#define   TARGET_FF1	00040000
+#define TARGET_BSDLY	00100000
+#define   TARGET_BS0	00000000
+#define   TARGET_BS1	00100000
+#define TARGET_VTDLY	00200000
+#define   TARGET_VT0	00000000
+#define   TARGET_VT1	00200000
+#define TARGET_XTABS	01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	0000037
+#define  TARGET_B0	0000000		/* hang up */
+#define  TARGET_B50	0000001
+#define  TARGET_B75	0000002
+#define  TARGET_B110	0000003
+#define  TARGET_B134	0000004
+#define  TARGET_B150	0000005
+#define  TARGET_B200	0000006
+#define  TARGET_B300	0000007
+#define  TARGET_B600	0000010
+#define  TARGET_B1200	0000011
+#define  TARGET_B1800	0000012
+#define  TARGET_B2400	0000013
+#define  TARGET_B4800	0000014
+#define  TARGET_B9600	0000015
+#define  TARGET_B19200	0000016
+#define  TARGET_B38400	0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CBAUDEX 0000000
+#define  TARGET_B57600   00020
+#define  TARGET_B115200  00021
+#define  TARGET_B230400  00022
+#define  TARGET_B460800  00023
+#define  TARGET_B500000  00024
+#define  TARGET_B576000  00025
+#define  TARGET_B921600  00026
+#define TARGET_B1000000  00027
+#define TARGET_B1152000  00030
+#define TARGET_B1500000  00031
+#define TARGET_B2000000  00032
+#define TARGET_B2500000  00033
+#define TARGET_B3000000  00034
+#define TARGET_B3500000  00035
+#define TARGET_B4000000  00036
+
+#define TARGET_CSIZE	00001400
+#define   TARGET_CS5	00000000
+#define   TARGET_CS6	00000400
+#define   TARGET_CS7	00001000
+#define   TARGET_CS8	00001400
+
+#define TARGET_CSTOPB	00002000
+#define TARGET_CREAD	00004000
+#define TARGET_PARENB	00010000
+#define TARGET_PARODD	00020000
+#define TARGET_HUPCL	00040000
+
+#define TARGET_CLOCAL	00100000
+#define TARGET_CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	  020000000000		/* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0x00000080
+#define TARGET_ICANON	0x00000100
+#define TARGET_XCASE	0x00004000
+#define TARGET_ECHO	0x00000008
+#define TARGET_ECHOE	0x00000002
+#define TARGET_ECHOK	0x00000004
+#define TARGET_ECHONL	0x00000010
+#define TARGET_NOFLSH	0x80000000
+#define TARGET_TOSTOP	0x00400000
+#define TARGET_ECHOCTL	0x00000040
+#define TARGET_ECHOPRT	0x00000020
+#define TARGET_ECHOKE	0x00000001
+#define TARGET_FLUSHO	0x00800000
+#define TARGET_PENDIN	0x20000000
+#define TARGET_IEXTEN	0x00000400
+
+#define TARGET_FIOCLEX		_IO('f', 1)
+#define TARGET_FIONCLEX	_IO('f', 2)
+#define TARGET_FIOASYNC	_IOW('f', 125, int)
+#define TARGET_FIONBIO		_IOW('f', 126, int)
+#define TARGET_FIONREAD	_IOR('f', 127, int)
+#define TARGET_TIOCINQ		FIONREAD
+#define TARGET_FIOQSIZE	_IOR('f', 128, loff_t)
+
+#define TARGET_TIOCGETP	_IOR('t', 8, struct sgttyb)
+#define TARGET_TIOCSETP	_IOW('t', 9, struct sgttyb)
+#define TARGET_TIOCSETN	_IOW('t', 10, struct sgttyb)	/* TIOCSETP wo flush */
+
+#define TARGET_TIOCSETC	_IOW('t', 17, struct tchars)
+#define TARGET_TIOCGETC	_IOR('t', 18, struct tchars)
+#define TARGET_TCGETS		_IOR('t', 19, struct termios)
+#define TARGET_TCSETS		_IOW('t', 20, struct termios)
+#define TARGET_TCSETSW		_IOW('t', 21, struct termios)
+#define TARGET_TCSETSF		_IOW('t', 22, struct termios)
+
+#define TARGET_TCGETA		_IOR('t', 23, struct termio)
+#define TARGET_TCSETA		_IOW('t', 24, struct termio)
+#define TARGET_TCSETAW		_IOW('t', 25, struct termio)
+#define TARGET_TCSETAF		_IOW('t', 28, struct termio)
+
+#define TARGET_TCSBRK		_IO('t', 29)
+#define TARGET_TCXONC		_IO('t', 30)
+#define TARGET_TCFLSH		_IO('t', 31)
+
+#define TARGET_TIOCSWINSZ	_IOW('t', 103, struct winsize)
+#define TARGET_TIOCGWINSZ	_IOR('t', 104, struct winsize)
+#define	TARGET_TIOCSTART	_IO('t', 110)		/* start output, like ^Q */
+#define	TARGET_TIOCSTOP	_IO('t', 111)		/* stop output, like ^S */
+#define TARGET_TIOCOUTQ        _IOR('t', 115, int)     /* output queue size */
+
+#define TARGET_TIOCGLTC	_IOR('t', 116, struct ltchars)
+#define TARGET_TIOCSLTC	_IOW('t', 117, struct ltchars)
+#define TARGET_TIOCSPGRP	_IOW('t', 118, int)
+#define TARGET_TIOCGPGRP	_IOR('t', 119, int)
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+# define TARGET_TIOCM_LE	0x001
+# define TARGET_TIOCM_DTR	0x002
+# define TARGET_TIOCM_RTS	0x004
+# define TARGET_TIOCM_ST	0x008
+# define TARGET_TIOCM_SR	0x010
+# define TARGET_TIOCM_CTS	0x020
+# define TARGET_TIOCM_CAR	0x040
+# define TARGET_TIOCM_RNG	0x080
+# define TARGET_TIOCM_DSR	0x100
+# define TARGET_TIOCM_CD	TIOCM_CAR
+# define TARGET_TIOCM_RI	TIOCM_RNG
+# define TARGET_TIOCM_OUT1	0x2000
+# define TARGET_TIOCM_OUT2	0x4000
+# define TARGET_TIOCM_LOOP	0x8000
+
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+# define TARGET_TIOCPKT_DATA		 0
+# define TARGET_TIOCPKT_FLUSHREAD	 1
+# define TARGET_TIOCPKT_FLUSHWRITE	 2
+# define TARGET_TIOCPKT_STOP		 4
+# define TARGET_TIOCPKT_START		 8
+# define TARGET_TIOCPKT_NOSTOP		16
+# define TARGET_TIOCPKT_DOSTOP		32
+
+
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP	0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP	0x545F  /* Set Hayes ESP configuration */
+
diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h
index c48be98..9ca3a5d 100644
--- a/linux-user/arm/syscall_nr.h
+++ b/linux-user/arm/syscall_nr.h
@@ -325,3 +325,34 @@
 #define TARGET_NR_mbind			319
 #define TARGET_NR_get_mempolicy		320
 #define TARGET_NR_set_mempolicy		321
+#define TARGET_NR_openat			(322)
+#define TARGET_NR_mkdirat			(323)
+#define TARGET_NR_mknodat			(324)
+#define TARGET_NR_fchownat			(325)
+#define TARGET_NR_futimesat			(326)
+#define TARGET_NR_fstatat64			(327)
+#define TARGET_NR_unlinkat			(328)
+#define TARGET_NR_renameat			(329)
+#define TARGET_NR_linkat			(330)
+#define TARGET_NR_symlinkat			(331)
+#define TARGET_NR_readlinkat			(332)
+#define TARGET_NR_fchmodat			(333)
+#define TARGET_NR_faccessat			(334)
+					/* 335 for pselect6 */
+					/* 336 for ppoll */
+#define TARGET_NR_unshare			(337)
+#define TARGET_NR_set_robust_list		(338)
+#define TARGET_NR_get_robust_list		(339)
+#define TARGET_NR_splice			(340)
+#define TARGET_NR_arm_sync_file_range	(341)
+#define TARGET_NR_sync_file_range2		TARGET_NR_arm_sync_file_range
+#define TARGET_NR_tee			(342)
+#define TARGET_NR_vmsplice			(343)
+#define TARGET_NR_move_pages			(344)
+#define TARGET_NR_getcpu			(345)
+					/* 346 for epoll_pwait */
+#define TARGET_NR_kexec_load			(347)
+#define TARGET_NR_utimensat			(348)
+#define TARGET_NR_signalfd			(349)
+#define TARGET_NR_timerfd			(350)
+#define TARGET_NR_eventfd			(351)
diff --git a/linux-user/arm/target_signal.h b/linux-user/arm/target_signal.h
new file mode 100644
index 0000000..d518165
--- /dev/null
+++ b/linux-user/arm/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ		8192
+
+static inline target_ulong get_sp_from_cpustate(CPUARMState *state)
+{
+   return state->regs[13];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/arm/termbits.h b/linux-user/arm/termbits.h
index 36ead08..f018c07 100644
--- a/linux-user/arm/termbits.h
+++ b/linux-user/arm/termbits.h
@@ -27,6 +27,7 @@
 #define TARGET_IXANY   0004000
 #define TARGET_IXOFF   0010000
 #define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
 
 /* c_oflag bits */
 #define TARGET_OPOST   0000001
@@ -98,7 +99,8 @@
 #define  TARGET_B230400 0010003
 #define  TARGET_B460800 0010004
 #define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
-#define TARGET_CRTSCTS   020000000000          /* flow control */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
 
 /* c_lflag bits */
 #define TARGET_ISIG    0000001
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index c0ea5a0..22e3283 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -44,6 +44,23 @@
   return global_env->cpuid_features;
 }
 
+#ifdef TARGET_X86_64
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2LSB
+#define ELF_ARCH       EM_X86_64
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->rax = 0;
+    regs->rsp = infop->start_stack;
+    regs->rip = infop->entry;
+}
+
+#else
+
 #define ELF_START_MMAP 0x80000000
 
 /*
@@ -72,6 +89,7 @@
        A value of 0 tells we have no such handler.  */
     regs->edx = 0;
 }
+#endif
 
 #define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE	4096
@@ -177,9 +195,20 @@
 
 #define ELF_START_MMAP 0x80000000
 
+#ifdef TARGET_PPC64
+
+#define elf_check_arch(x) ( (x) == EM_PPC64 )
+
+#define ELF_CLASS	ELFCLASS64
+
+#else
+
 #define elf_check_arch(x) ( (x) == EM_PPC )
 
 #define ELF_CLASS	ELFCLASS32
+
+#endif
+
 #ifdef TARGET_WORDS_BIGENDIAN
 #define ELF_DATA	ELFDATA2MSB
 #else
@@ -222,9 +251,18 @@
 {
     target_ulong pos = infop->start_stack;
     target_ulong tmp;
+#ifdef TARGET_PPC64
+    target_ulong entry, toc;
+#endif
 
     _regs->msr = 1 << MSR_PR; /* Set user mode */
     _regs->gpr[1] = infop->start_stack;
+#ifdef TARGET_PPC64
+    entry = ldq_raw(infop->entry) + infop->load_addr;
+    toc = ldq_raw(infop->entry + 8) + infop->load_addr;
+    _regs->gpr[2] = toc;
+    infop->entry = entry;
+#endif
     _regs->nip = infop->entry;
     /* Note that isn't exactly what regular kernel does
      * but this is what the ABI wants and is needed to allow
@@ -249,7 +287,11 @@
 
 #define elf_check_arch(x) ( (x) == EM_MIPS )
 
+#ifdef TARGET_MIPS64
+#define ELF_CLASS   ELFCLASS64
+#else
 #define ELF_CLASS   ELFCLASS32
+#endif
 #ifdef TARGET_WORDS_BIGENDIAN
 #define ELF_DATA	ELFDATA2MSB
 #else
@@ -264,6 +306,9 @@
     regs->regs[29] = infop->start_stack;
 }
 
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        4096
+
 #endif /* TARGET_MIPS */
 
 #ifdef TARGET_SH4
@@ -280,7 +325,7 @@
 {
   /* Check other registers XXXXX */
   regs->pc = infop->entry;
-  regs->regs[15] = infop->start_stack - 16 * 4;
+  regs->regs[15] = infop->start_stack;
 }
 
 #define USE_ELF_CORE_DUMP
@@ -313,6 +358,31 @@
 
 #endif
 
+#ifdef TARGET_ALPHA
+
+#define ELF_START_MMAP (0x30000000000ULL)
+
+#define elf_check_arch(x) ( (x) == ELF_ARCH )
+
+#define ELF_CLASS      ELFCLASS64
+#define ELF_DATA       ELFDATA2MSB
+#define ELF_ARCH       EM_ALPHA
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+    regs->pc = infop->entry;
+    regs->ps = 8;
+    regs->usp = infop->start_stack;
+    regs->unique = infop->start_data; /* ? */
+    printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
+           regs->unique, infop->start_data);
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE        8192
+
+#endif /* TARGET_ALPHA */
+
 #ifndef ELF_PLATFORM
 #define ELF_PLATFORM (NULL)
 #endif
@@ -431,11 +501,11 @@
     bswaptls(&shdr->sh_entsize);
 }
 
-static void bswap_sym(Elf32_Sym *sym)
+static void bswap_sym(struct elf_sym *sym)
 {
     bswap32s(&sym->st_name);
-    bswap32s(&sym->st_value);
-    bswap32s(&sym->st_size);
+    bswaptls(&sym->st_value);
+    bswaptls(&sym->st_size);
     bswap16s(&sym->st_shndx);
 }
 #endif
@@ -447,7 +517,7 @@
  *
  */
 static unsigned long copy_elf_strings(int argc,char ** argv, void **page,
-                                      unsigned long p)
+                                      target_ulong p)
 {
     char *tmp, *tmp1, *pag = NULL;
     int len, offset = 0;
@@ -474,6 +544,7 @@
                 pag = (char *)page[p/TARGET_PAGE_SIZE];
                 if (!pag) {
                     pag = (char *)malloc(TARGET_PAGE_SIZE);
+                    memset(pag, 0, TARGET_PAGE_SIZE);
                     page[p/TARGET_PAGE_SIZE] = pag;
                     if (!pag)
                         return 0;
@@ -507,7 +578,7 @@
     size = x86_stack_size;
     if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
         size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
-    error = target_mmap(0, 
+    error = target_mmap(0,
                         size + qemu_host_page_size,
                         PROT_READ | PROT_WRITE,
                         MAP_PRIVATE | MAP_ANONYMOUS,
@@ -567,7 +638,7 @@
            size must be known */
         if (qemu_real_host_page_size < qemu_host_page_size) {
             unsigned long end_addr, end_addr1;
-            end_addr1 = (elf_bss + qemu_real_host_page_size - 1) & 
+            end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
                 ~(qemu_real_host_page_size - 1);
             end_addr = HOST_PAGE_ALIGN(elf_bss);
             if (end_addr1 < end_addr) {
@@ -625,7 +696,7 @@
         size *= n;
         if (size & 15)
             sp -= 16 - (size & 15);
-        
+
 #define NEW_AUX_ENT(id, val) do { \
             sp -= n; tputl(sp, val); \
             sp -= n; tputl(sp, id); \
@@ -648,7 +719,7 @@
         if (k_platform)
             NEW_AUX_ENT(AT_PLATFORM, u_platform);
 #ifdef ARCH_DLINFO
-	/* 
+	/*
 	 * ARCH_DLINFO must come last so platform specific code can enforce
 	 * special alignment requirements on the AUXV if necessary (eg. PPC).
 	 */
@@ -673,7 +744,7 @@
 	unsigned long last_bss, elf_bss;
 	unsigned long error;
 	int i;
-	
+
 	elf_bss = 0;
 	last_bss = 0;
 	error = 0;
@@ -682,24 +753,24 @@
         bswap_ehdr(interp_elf_ex);
 #endif
 	/* First of all, some simple consistency checks */
-	if ((interp_elf_ex->e_type != ET_EXEC && 
-             interp_elf_ex->e_type != ET_DYN) || 
+	if ((interp_elf_ex->e_type != ET_EXEC &&
+             interp_elf_ex->e_type != ET_DYN) ||
 	   !elf_check_arch(interp_elf_ex->e_machine)) {
 		return ~0UL;
 	}
-	
+
 
 	/* Now read in all of the header information */
-	
+
 	if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
 	    return ~0UL;
-	
-	elf_phdata =  (struct elf_phdr *) 
+
+	elf_phdata =  (struct elf_phdr *)
 		malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
 
 	if (!elf_phdata)
 	  return ~0UL;
-	
+
 	/*
 	 * If the size of this structure has changed, then punt, since
 	 * we will be doing the wrong thing.
@@ -729,10 +800,10 @@
 #endif
 
         if (interp_elf_ex->e_type == ET_DYN) {
-            /* in order to avoid harcoding the interpreter load
+            /* in order to avoid hardcoding the interpreter load
                address in qemu, we allocate a big enough memory zone */
             error = target_mmap(0, INTERP_MAP_SIZE,
-                                PROT_NONE, MAP_PRIVATE | MAP_ANON, 
+                                PROT_NONE, MAP_PRIVATE | MAP_ANON,
                                 -1, 0);
             if (error == -1) {
                 perror("mmap");
@@ -763,7 +834,7 @@
 		 elf_type,
 		 interpreter_fd,
 		 eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
-	    
+
 	    if (error == -1) {
 	      /* Real error */
 	      close(interpreter_fd);
@@ -790,7 +861,7 @@
 	    k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
 	    if (k > last_bss) last_bss = k;
 	  }
-	
+
 	/* Now use mmap to map the library into memory. */
 
 	close(interpreter_fd);
@@ -823,6 +894,11 @@
     struct elf_shdr sechdr, symtab, strtab;
     char *strings;
     struct syminfo *s;
+#if (ELF_CLASS == ELFCLASS64)
+    // Disas uses 32 bit symbols
+    struct elf32_sym *syms32 = NULL;
+    struct elf_sym *sym;
+#endif
 
     lseek(fd, hdr->e_shoff, SEEK_SET);
     for (i = 0; i < hdr->e_shnum; i++) {
@@ -850,19 +926,37 @@
     /* Now know where the strtab and symtab are.  Snarf them. */
     s = malloc(sizeof(*s));
     s->disas_symtab = malloc(symtab.sh_size);
+#if (ELF_CLASS == ELFCLASS64)
+    syms32 = malloc(symtab.sh_size / sizeof(struct elf_sym)
+                    * sizeof(struct elf32_sym));
+#endif
     s->disas_strtab = strings = malloc(strtab.sh_size);
     if (!s->disas_symtab || !s->disas_strtab)
 	return;
-	
+
     lseek(fd, symtab.sh_offset, SEEK_SET);
     if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
 	return;
 
+    for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++) {
 #ifdef BSWAP_NEEDED
-    for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
 	bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
 #endif
+#if (ELF_CLASS == ELFCLASS64)
+        sym = s->disas_symtab + sizeof(struct elf_sym)*i;
+        syms32[i].st_name = sym->st_name;
+        syms32[i].st_info = sym->st_info;
+        syms32[i].st_other = sym->st_other;
+        syms32[i].st_shndx = sym->st_shndx;
+        syms32[i].st_value = sym->st_value & 0xffffffff;
+        syms32[i].st_size = sym->st_size & 0xffffffff;
+#endif
+    }
 
+#if (ELF_CLASS == ELFCLASS64)
+    free(s->disas_symtab);
+    s->disas_symtab = syms32;
+#endif
     lseek(fd, strtab.sh_offset, SEEK_SET);
     if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
 	return;
@@ -892,6 +986,7 @@
     unsigned long elf_entry, interp_load_addr = 0;
     int status;
     unsigned long start_code, end_code, end_data;
+    unsigned long reloc_func_desc = 0;
     unsigned long elf_stack;
     char passed_fileno[6];
 
@@ -925,7 +1020,7 @@
 
     retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
     if(retval > 0) {
-	retval = read(bprm->fd, (char *) elf_phdata, 
+	retval = read(bprm->fd, (char *) elf_phdata,
 				elf_ex.e_phentsize * elf_ex.e_phnum);
     }
 
@@ -984,7 +1079,7 @@
 	    if(retval < 0) {
 	 	perror("load_elf_binary2");
 		exit(-1);
-	    }	
+	    }
 
 	    /* If the program interpreter is one of these two,
 	       then assume an iBCS2 image. Otherwise assume
@@ -1105,10 +1200,10 @@
         int elf_prot = 0;
         int elf_flags = 0;
         unsigned long error;
-        
+
 	if (elf_ppnt->p_type != PT_LOAD)
             continue;
-        
+
         if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
         if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
         if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
@@ -1120,9 +1215,9 @@
                base, as well as whatever program they might try to exec.  This
                is because the brk will follow the loader, and is not movable.  */
             /* NOTE: for qemu, we do a big mmap to get enough space
-               without harcoding any address */
+               without hardcoding any address */
             error = target_mmap(0, ET_DYN_MAP_SIZE,
-                                PROT_NONE, MAP_PRIVATE | MAP_ANON, 
+                                PROT_NONE, MAP_PRIVATE | MAP_ANON,
                                 -1, 0);
             if (error == -1) {
                 perror("mmap");
@@ -1130,14 +1225,14 @@
             }
             load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
         }
-        
+
         error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
                             (elf_ppnt->p_filesz +
                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
                             elf_prot,
                             (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
                             bprm->fd,
-                            (elf_ppnt->p_offset - 
+                            (elf_ppnt->p_offset -
                              TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
         if (error == -1) {
             perror("mmap");
@@ -1148,7 +1243,7 @@
         if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
             elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
 #endif
-        
+
         if (!load_addr_set) {
             load_addr_set = 1;
             load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
@@ -1156,17 +1251,18 @@
                 load_bias += error -
                     TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
                 load_addr += load_bias;
+                reloc_func_desc = load_bias;
             }
         }
         k = elf_ppnt->p_vaddr;
-        if (k < start_code) 
+        if (k < start_code)
             start_code = k;
         k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
-        if (k > elf_bss) 
+        if (k > elf_bss)
             elf_bss = k;
         if ((elf_ppnt->p_flags & PF_X) && end_code <  k)
             end_code = k;
-        if (end_data < k) 
+        if (end_data < k)
             end_data = k;
         k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
         if (k > elf_brk) elf_brk = k;
@@ -1188,6 +1284,7 @@
 	    elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
 					    &interp_load_addr);
 	}
+        reloc_func_desc = interp_load_addr;
 
 	close(interpreter_fd);
 	free(elf_interpreter);
@@ -1219,6 +1316,7 @@
 		    interp_load_addr,
 		    (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
 		    info);
+    info->load_addr = reloc_func_desc;
     info->start_brk = info->brk = elf_brk;
     info->end_code = end_code;
     info->start_code = start_code;
diff --git a/linux-user/errno_defs.h b/linux-user/errno_defs.h
new file mode 100644
index 0000000..209c187
--- /dev/null
+++ b/linux-user/errno_defs.h
@@ -0,0 +1,142 @@
+/*
+ * Target definitions of errnos. These may be overridden by an
+ * architecture specific header if needed.
+ *
+ * Taken from asm-generic/errno-base.h and asm-generic/errno.h
+ */
+#define TARGET_EPERM            1      /* Operation not permitted */
+#define TARGET_ENOENT           2      /* No such file or directory */
+#define TARGET_ESRCH            3      /* No such process */
+#define TARGET_EINTR            4      /* Interrupted system call */
+#define TARGET_EIO              5      /* I/O error */
+#define TARGET_ENXIO            6      /* No such device or address */
+#define TARGET_E2BIG            7      /* Argument list too long */
+#define TARGET_ENOEXEC          8      /* TARGET_Exec format error */
+#define TARGET_EBADF            9      /* Bad file number */
+#define TARGET_ECHILD          10      /* No child processes */
+#define TARGET_EAGAIN          11      /* Try again */
+#define TARGET_ENOMEM          12      /* Out of memory */
+#define TARGET_EACCES          13      /* Permission denied */
+#define TARGET_EFAULT          14      /* Bad address */
+#define TARGET_ENOTBLK         15      /* Block device required */
+#define TARGET_EBUSY           16      /* Device or resource busy */
+#define TARGET_EEXIST          17      /* File exists */
+#define TARGET_EXDEV           18      /* Cross-device link */
+#define TARGET_ENODEV          19      /* No such device */
+#define TARGET_ENOTDIR         20      /* Not a directory */
+#define TARGET_EISDIR          21      /* Is a directory */
+#define TARGET_EINVAL          22      /* Invalid argument */
+#define TARGET_ENFILE          23      /* File table overflow */
+#define TARGET_EMFILE          24      /* Too many open files */
+#define TARGET_ENOTTY          25      /* Not a typewriter */
+#define TARGET_ETXTBSY         26      /* Text file busy */
+#define TARGET_EFBIG           27      /* File too large */
+#define TARGET_ENOSPC          28      /* No space left on device */
+#define TARGET_ESPIPE          29      /* Illegal seek */
+#define TARGET_EROFS           30      /* Read-only file system */
+#define TARGET_EMLINK          31      /* Too many links */
+#define TARGET_EPIPE           32      /* Broken pipe */
+#define TARGET_EDOM            33      /* Math argument out of domain of func */
+#define TARGET_ERANGE          34      /* Math result not representable */
+
+#define TARGET_EDEADLK         35      /* Resource deadlock would occur */
+#define TARGET_ENAMETOOLONG    36      /* File name too long */
+#define TARGET_ENOLCK          37      /* No record locks available */
+#define TARGET_ENOSYS          38      /* Function not implemented */
+#define TARGET_ENOTEMPTY       39      /* Directory not empty */
+#define TARGET_ELOOP           40      /* Too many symbolic links encountered */
+
+#define TARGET_ENOMSG          42      /* No message of desired type */
+#define TARGET_EIDRM           43      /* Identifier removed */
+#define TARGET_ECHRNG          44      /* Channel number out of range */
+#define TARGET_EL2NSYNC        45      /* Level 2 not synchronized */
+#define TARGET_EL3HLT          46      /* Level 3 halted */
+#define TARGET_EL3RST          47      /* Level 3 reset */
+#define TARGET_ELNRNG          48      /* Link number out of range */
+#define TARGET_EUNATCH         49      /* Protocol driver not attached */
+#define TARGET_ENOCSI          50      /* No CSI structure available */
+#define TARGET_EL2HLT          51      /* Level 2 halted */
+#define TARGET_EBADE           52      /* Invalid exchange */
+#define TARGET_EBADR           53      /* Invalid request descriptor */
+#define TARGET_EXFULL          54      /* TARGET_Exchange full */
+#define TARGET_ENOANO          55      /* No anode */
+#define TARGET_EBADRQC         56      /* Invalid request code */
+#define TARGET_EBADSLT         57      /* Invalid slot */
+
+#define TARGET_EBFONT          59      /* Bad font file format */
+#define TARGET_ENOSTR          60      /* Device not a stream */
+#define TARGET_ENODATA         61      /* No data available */
+#define TARGET_ETIME           62      /* Timer expired */
+#define TARGET_ENOSR           63      /* Out of streams resources */
+#define TARGET_ENONET          64      /* Machine is not on the network */
+#define TARGET_ENOPKG          65      /* Package not installed */
+#define TARGET_EREMOTE         66      /* Object is remote */
+#define TARGET_ENOLINK         67      /* Link has been severed */
+#define TARGET_EADV            68      /* Advertise error */
+#define TARGET_ESRMNT          69      /* Srmount error */
+#define TARGET_ECOMM           70      /* Communication error on send */
+#define TARGET_EPROTO          71      /* Protocol error */
+#define TARGET_EMULTIHOP       72      /* Multihop attempted */
+#define TARGET_EDOTDOT         73      /* RFS specific error */
+#define TARGET_EBADMSG         74      /* Not a data message */
+#define TARGET_EOVERFLOW       75      /* Value too large for defined data type */
+#define TARGET_ENOTUNIQ        76      /* Name not unique on network */
+#define TARGET_EBADFD          77      /* File descriptor in bad state */
+#define TARGET_EREMCHG         78      /* Remote address changed */
+#define TARGET_ELIBACC         79      /* Can not access a needed shared library */
+#define TARGET_ELIBBAD         80      /* Accessing a corrupted shared library */
+#define TARGET_ELIBSCN         81      /* .lib section in a.out corrupted */
+#define TARGET_ELIBMAX         82      /* Attempting to link in too many shared libraries */
+#define TARGET_ELIBEXEC        83      /* Cannot exec a shared library directly */
+#define TARGET_EILSEQ          84      /* Illegal byte sequence */
+#define TARGET_ERESTART        85      /* Interrupted system call should be restarted */
+#define TARGET_ESTRPIPE        86      /* Streams pipe error */
+#define TARGET_EUSERS          87      /* Too many users */
+#define TARGET_ENOTSOCK        88      /* Socket operation on non-socket */
+#define TARGET_EDESTADDRREQ    89      /* Destination address required */
+#define TARGET_EMSGSIZE        90      /* Message too long */
+#define TARGET_EPROTOTYPE      91      /* Protocol wrong type for socket */
+#define TARGET_ENOPROTOOPT     92      /* Protocol not available */
+#define TARGET_EPROTONOSUPPORT 93      /* Protocol not supported */
+#define TARGET_ESOCKTNOSUPPORT 94      /* Socket type not supported */
+#define TARGET_EOPNOTSUPP      95      /* Operation not supported on transport endpoint */
+#define TARGET_EPFNOSUPPORT    96      /* Protocol family not supported */
+#define TARGET_EAFNOSUPPORT    97      /* Address family not supported by protocol */
+#define TARGET_EADDRINUSE      98      /* Address already in use */
+#define TARGET_EADDRNOTAVAIL   99      /* Cannot assign requested address */
+#define TARGET_ENETDOWN        100     /* Network is down */
+#define TARGET_ENETUNREACH     101     /* Network is unreachable */
+#define TARGET_ENETRESET       102     /* Network dropped connection because of reset */
+#define TARGET_ECONNABORTED    103     /* Software caused connection abort */
+#define TARGET_ECONNRESET      104     /* Connection reset by peer */
+#define TARGET_ENOBUFS         105     /* No buffer space available */
+#define TARGET_EISCONN         106     /* Transport endpoint is already connected */
+#define TARGET_ENOTCONN        107     /* Transport endpoint is not connected */
+#define TARGET_ESHUTDOWN       108     /* Cannot send after transport endpoint shutdown */
+#define TARGET_ETOOMANYREFS    109     /* Too many references: cannot splice */
+#define TARGET_ETIMEDOUT       110     /* Connection timed out */
+#define TARGET_ECONNREFUSED    111     /* Connection refused */
+#define TARGET_EHOSTDOWN       112     /* Host is down */
+#define TARGET_EHOSTUNREACH    113     /* No route to host */
+#define TARGET_EALREADY        114     /* Operation already in progress */
+#define TARGET_EINPROGRESS     115     /* Operation now in progress */
+#define TARGET_ESTALE          116     /* Stale NFS file handle */
+#define TARGET_EUCLEAN         117     /* Structure needs cleaning */
+#define TARGET_ENOTNAM         118     /* Not a XENIX named type file */
+#define TARGET_ENAVAIL         119     /* No XENIX semaphores available */
+#define TARGET_EISNAM          120     /* Is a named type file */
+#define TARGET_EREMOTEIO       121     /* Remote I/O error */
+#define TARGET_EDQUOT          122     /* Quota exceeded */
+
+#define TARGET_ENOMEDIUM       123     /* No medium found */
+#define TARGET_EMEDIUMTYPE     124     /* Wrong medium type */
+#define TARGET_ECANCELED       125     /* Operation Canceled */
+#define TARGET_ENOKEY          126     /* Required key not available */
+#define TARGET_EKEYEXPIRED     127     /* Key has expired */
+#define TARGET_EKEYREVOKED     128     /* Key has been revoked */
+#define TARGET_EKEYREJECTED    129     /* Key was rejected by service */
+
+/* for robust mutexes */
+#define TARGET_EOWNERDEAD      130     /* Owner died */
+#define TARGET_ENOTRECOVERABLE 131     /* State not recoverable */
+
diff --git a/linux-user/flat.h b/linux-user/flat.h
index 6d52b1f..9b84c72 100644
--- a/linux-user/flat.h
+++ b/linux-user/flat.h
@@ -38,7 +38,7 @@
 	target_ulong reloc_start;  /* Offset of relocation records from
 	                               beginning of file */
 	target_ulong reloc_count;  /* Number of relocation records */
-	target_ulong flags;       
+	target_ulong flags;
 	target_ulong build_date;   /* When the program/library was built */
 	target_ulong filler[5];    /* Reservered, set to zero */
 };
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
index 7e3296e..db88e4b 100644
--- a/linux-user/flatload.c
+++ b/linux-user/flatload.c
@@ -359,7 +359,7 @@
 		"(address %p, currently %x) into segment %s\n",
 		offset, ptr, (int)*ptr, segment[reloc_type]);
 #endif
-	
+
 	switch (reloc_type) {
 	case OLD_FLAT_RELOC_TYPE_TEXT:
 		*ptr += libinfo->start_code;
@@ -376,7 +376,7 @@
 		break;
 	}
 	DBG_FLT("Relocation became %x\n", (int)*ptr);
-}		
+}
 
 /****************************************************************************/
 
@@ -393,6 +393,7 @@
     int i, rev, relocs = 0;
     target_ulong fpos;
     target_ulong start_code, end_code;
+    target_ulong indx_len;
 
     hdr = ((struct flat_hdr *) bprm->buf);		/* exec-header */
 
@@ -415,7 +416,7 @@
                 rev, (int) FLAT_VERSION);
         return -ENOEXEC;
     }
-    
+
     /* Don't allow old format executables to use shared libraries */
     if (rev == OLD_FLAT_VERSION && id != 0) {
         fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
@@ -443,6 +444,11 @@
     if (extra < bss_len + stack_len)
         extra = bss_len + stack_len;
 
+    /* Add space for library base pointers.  Make sure this does not
+       misalign the  doesn't misalign the data segment.  */
+    indx_len = MAX_SHARED_LIBS * sizeof(target_ulong);
+    indx_len = (indx_len + 15) & ~(target_ulong)15;
+
     /*
      * there are a couple of cases here,  the separate code/data
      * case,  and then the fully copied to RAM case which lumps
@@ -457,13 +463,12 @@
 
         textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
                               MAP_PRIVATE, bprm->fd, 0);
-        if (textpos == -1) { 
+        if (textpos == -1) {
             fprintf(stderr, "Unable to mmap process text\n");
             return -1;
         }
 
-        realdatastart = target_mmap(0, data_len + extra +
-                                    MAX_SHARED_LIBS * sizeof(target_ulong),
+        realdatastart = target_mmap(0, data_len + extra + indx_len,
                                     PROT_READ|PROT_WRITE|PROT_EXEC,
                                     MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 
@@ -471,7 +476,7 @@
             fprintf(stderr, "Unable to allocate RAM for process data\n");
             return realdatastart;
         }
-        datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
+        datapos = realdatastart + indx_len;
 
         DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
                         (int)(data_len + bss_len + stack_len), (int)datapos);
@@ -479,7 +484,7 @@
         fpos = ntohl(hdr->data_start);
 #ifdef CONFIG_BINFMT_ZFLAT
         if (flags & FLAT_FLAG_GZDATA) {
-            result = decompress_exec(bprm, fpos, (char *) datapos, 
+            result = decompress_exec(bprm, fpos, (char *) datapos,
                                      data_len + (relocs * sizeof(target_ulong)))
         } else
 #endif
@@ -498,8 +503,7 @@
 
     } else {
 
-        textpos = target_mmap(0, text_len + data_len + extra +
-                              MAX_SHARED_LIBS * sizeof(target_ulong),
+        textpos = target_mmap(0, text_len + data_len + extra + indx_len,
                               PROT_READ | PROT_EXEC | PROT_WRITE,
                               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
         if (textpos == -1 ) {
@@ -508,9 +512,8 @@
         }
 
         realdatastart = textpos + ntohl(hdr->data_start);
-        datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
-        reloc = (textpos + ntohl(hdr->reloc_start) +
-                 MAX_SHARED_LIBS * sizeof(target_ulong));
+        datapos = realdatastart + indx_len;
+        reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
         memp = textpos;
 
 #ifdef CONFIG_BINFMT_ZFLAT
@@ -578,7 +581,7 @@
     libinfo[id].loaded = 1;
     libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
     libinfo[id].build_date = ntohl(hdr->build_date);
-    
+
     /*
      * We just load the allocations into some temporary memory to
      * help simplify all this mumbo jumbo
@@ -659,7 +662,7 @@
             old_reloc(&libinfo[0], relval);
         }
     }
-    
+
     /* zero the BSS.  */
     memset((void*)(datapos + data_len), 0, bss_len);
 
@@ -729,11 +732,11 @@
     stack_len += (bprm->argc + 1) * 4; /* the argv array */
     stack_len += (bprm->envc + 1) * 4; /* the envp array */
 
-    
+
     res = load_flat_file(bprm, libinfo, 0, &stack_len);
     if (res > (unsigned long)-4096)
             return res;
-    
+
     /* Update data segment pointers for all libraries */
     for (i=0; i<MAX_SHARED_LIBS; i++) {
         if (libinfo[i].loaded) {
@@ -756,8 +759,15 @@
     p = copy_strings(p, bprm->argc, bprm->argv);
     /* Align stack.  */
     sp = p & ~(target_ulong)(sizeof(target_ulong) - 1);
+    /* Enforce final stack alignment of 16 bytes.  This is sufficient
+       for all current targets, and excess alignment is harmless.  */
+    stack_len = bprm->envc + bprm->argc + 2;
+    stack_len += 3;	/* argc, arvg, argp */
+    stack_len *= sizeof(target_ulong);
+    if ((sp + stack_len) & 15)
+        sp -= 16 - ((sp + stack_len) & 15);
     sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
-    
+
     /* Fake some return addresses to ensure the call chain will
      * initialise library in order for us.  We are required to call
      * lib 1 first, then 2, ... and finally the main program (id 0).
@@ -774,7 +784,7 @@
             }
     }
 #endif
-    
+
     /* Stash our initial stack pointer into the mm structure */
     info->start_code = libinfo[0].start_code;
     info->end_code = libinfo[0].start_code = libinfo[0].text_len;
@@ -788,6 +798,6 @@
 
     DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n",
             (int)info->entry, (int)info->start_stack);
-    
+
     return 0;
 }
diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h
index cc0942b..6e288b8 100644
--- a/linux-user/i386/syscall.h
+++ b/linux-user/i386/syscall.h
@@ -142,80 +142,4 @@
 	struct target_vm86plus_info_struct vm86plus;
 };
 
-/* ipcs */
-
-#define TARGET_SEMOP           1
-#define TARGET_SEMGET          2
-#define TARGET_SEMCTL          3 
-#define TARGET_MSGSND          11 
-#define TARGET_MSGRCV          12
-#define TARGET_MSGGET          13
-#define TARGET_MSGCTL          14
-#define TARGET_SHMAT           21
-#define TARGET_SHMDT           22
-#define TARGET_SHMGET          23
-#define TARGET_SHMCTL          24
-
-struct target_msgbuf {
-	int mtype;
-	char mtext[1];
-};
-
-struct target_ipc_kludge {
-	unsigned int	msgp;	/* Really (struct msgbuf *) */
-	int msgtyp;
-};	
-
-struct target_ipc_perm {
-	int	key;
-	unsigned short	uid;
-	unsigned short	gid;
-	unsigned short	cuid;
-	unsigned short	cgid;
-	unsigned short	mode;
-	unsigned short	seq;
-};
-
-struct target_msqid_ds {
-	struct target_ipc_perm	msg_perm;
-	unsigned int		msg_first;	/* really struct target_msg* */
-	unsigned int		msg_last;	/* really struct target_msg* */
-	unsigned int		msg_stime;	/* really target_time_t */
-	unsigned int		msg_rtime;	/* really target_time_t */
-	unsigned int		msg_ctime;	/* really target_time_t */
-	unsigned int		wwait;		/* really struct wait_queue* */
-	unsigned int		rwait;		/* really struct wait_queue* */
-	unsigned short		msg_cbytes;
-	unsigned short		msg_qnum;
-	unsigned short		msg_qbytes;
-	unsigned short		msg_lspid;
-	unsigned short		msg_lrpid;
-};
-
-struct target_shmid_ds {
-	struct target_ipc_perm	shm_perm;
-	int			shm_segsz;
-	unsigned int		shm_atime;	/* really target_time_t */
-	unsigned int		shm_dtime;	/* really target_time_t */
-	unsigned int		shm_ctime;	/* really target_time_t */
-	unsigned short		shm_cpid;
-	unsigned short		shm_lpid;
-	short			shm_nattch;
-	unsigned short		shm_npages;
-	unsigned long		*shm_pages;
-	void 			*attaches;	/* really struct shm_desc * */
-};
-
-#define TARGET_IPC_RMID	0
-#define TARGET_IPC_SET	1
-#define TARGET_IPC_STAT	2
-
-union target_semun {
-    int val;
-    unsigned int buf;	/* really struct semid_ds * */
-    unsigned int array; /* really unsigned short * */
-    unsigned int __buf;	/* really struct seminfo * */
-    unsigned int __pad;	/* really void* */
-};
-
 #define UNAME_MACHINE "i686"
diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h
index 9fa6be9..62662cc 100644
--- a/linux-user/i386/syscall_nr.h
+++ b/linux-user/i386/syscall_nr.h
@@ -253,7 +253,7 @@
 #define TARGET_NR_io_submit		248
 #define TARGET_NR_io_cancel		249
 #define TARGET_NR_fadvise64		250
-
+/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */
 #define TARGET_NR_exit_group		252
 #define TARGET_NR_lookup_dcookie	253
 #define TARGET_NR_epoll_create	254
@@ -270,5 +270,60 @@
 #define TARGET_NR_clock_gettime	(TARGET_NR_timer_create+6)
 #define TARGET_NR_clock_getres	(TARGET_NR_timer_create+7)
 #define TARGET_NR_clock_nanosleep	(TARGET_NR_timer_create+8)
-
+#define TARGET_NR_statfs64		268
+#define TARGET_NR_fstatfs64		269
+#define TARGET_NR_tgkill		270
 #define TARGET_NR_utimes		271
+#define TARGET_NR_fadvise64_64	272
+#define TARGET_NR_vserver		273
+#define TARGET_NR_mbind		274
+#define TARGET_NR_get_mempolicy	275
+#define TARGET_NR_set_mempolicy	276
+#define TARGET_NR_mq_open 		277
+#define TARGET_NR_mq_unlink		(TARGET_NR_mq_open+1)
+#define TARGET_NR_mq_timedsend	(TARGET_NR_mq_open+2)
+#define TARGET_NR_mq_timedreceive	(TARGET_NR_mq_open+3)
+#define TARGET_NR_mq_notify		(TARGET_NR_mq_open+4)
+#define TARGET_NR_mq_getsetattr	(TARGET_NR_mq_open+5)
+#define TARGET_NR_kexec_load		283
+#define TARGET_NR_waitid		284
+/* #define TARGET_NR_sys_setaltroot	285 */
+#define TARGET_NR_add_key		286
+#define TARGET_NR_request_key	287
+#define TARGET_NR_keyctl		288
+#define TARGET_NR_ioprio_set		289
+#define TARGET_NR_ioprio_get		290
+#define TARGET_NR_inotify_init	291
+#define TARGET_NR_inotify_add_watch	292
+#define TARGET_NR_inotify_rm_watch	293
+#define TARGET_NR_migrate_pages	294
+#define TARGET_NR_openat		295
+#define TARGET_NR_mkdirat		296
+#define TARGET_NR_mknodat		297
+#define TARGET_NR_fchownat		298
+#define TARGET_NR_futimesat		299
+#define TARGET_NR_fstatat64		300
+#define TARGET_NR_unlinkat		301
+#define TARGET_NR_renameat		302
+#define TARGET_NR_linkat		303
+#define TARGET_NR_symlinkat		304
+#define TARGET_NR_readlinkat		305
+#define TARGET_NR_fchmodat		306
+#define TARGET_NR_faccessat		307
+#define TARGET_NR_pselect6		308
+#define TARGET_NR_ppoll		309
+#define TARGET_NR_unshare		310
+#define TARGET_NR_set_robust_list	311
+#define TARGET_NR_get_robust_list	312
+#define TARGET_NR_splice		313
+#define TARGET_NR_sync_file_range	314
+#define TARGET_NR_tee		315
+#define TARGET_NR_vmsplice		316
+#define TARGET_NR_move_pages		317
+#define TARGET_NR_getcpu		318
+#define TARGET_NR_epoll_pwait	319
+#define TARGET_NR_utimensat		320
+#define TARGET_NR_signalfd		321
+#define TARGET_NR_timerfd		322
+#define TARGET_NR_eventfd		323
+#define TARGET_NR_fallocate		324
diff --git a/linux-user/i386/target_signal.h b/linux-user/i386/target_signal.h
new file mode 100644
index 0000000..f93a8d6
--- /dev/null
+++ b/linux-user/i386/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ		8192
+
+static inline target_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/i386/termbits.h b/linux-user/i386/termbits.h
index adff802..4acd2bd 100644
--- a/linux-user/i386/termbits.h
+++ b/linux-user/i386/termbits.h
@@ -26,6 +26,7 @@
 #define TARGET_IXANY   0004000
 #define TARGET_IXOFF   0010000
 #define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
 
 /* c_oflag bits */
 #define TARGET_OPOST   0000001
@@ -96,8 +97,20 @@
 #define  TARGET_B115200 0010002
 #define  TARGET_B230400 0010003
 #define  TARGET_B460800 0010004
+#define  TARGET_B500000 0010005
+#define  TARGET_B576000 0010006
+#define  TARGET_B921600 0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
 #define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
-#define TARGET_CRTSCTS   020000000000          /* flow control */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
 
 /* c_lflag bits */
 #define TARGET_ISIG    0000001
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 2d20c00..0efbb76 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -1,4 +1,4 @@
-/* Code for loading Linux executables.  Mostly linux kenrel code.  */
+/* Code for loading Linux executables.  Mostly linux kernel code.  */
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -140,7 +140,7 @@
     return sp;
 }
 
-int loader_exec(const char * filename, char ** argv, char ** envp, 
+int loader_exec(const char * filename, char ** argv, char ** envp,
              struct target_pt_regs * regs, struct image_info *infop)
 {
     struct linux_binprm bprm;
@@ -182,7 +182,7 @@
             return -1;
         }
     }
-    
+
     if(retval>=0) {
         /* success.  Initialize important registers */
         do_init_thread(regs, infop);
diff --git a/linux-user/m68k-semi.c b/linux-user/m68k-semi.c
deleted file mode 100644
index 7f6ddda..0000000
--- a/linux-user/m68k-semi.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- *  m68k/ColdFire Semihosting ssycall interface
- * 
- *  Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include "qemu.h"
-
-#define HOSTED_EXIT  0
-#define HOSTED_PUTCHAR 1 /* Obsolete */
-#define HOSTED_OPEN 2
-#define HOSTED_CLOSE 3
-#define HOSTED_READ 4
-#define HOSTED_WRITE 5
-#define HOSTED_LSEEK 6
-#define HOSTED_RENAME 7
-#define HOSTED_UNLINK 8
-#define HOSTED_STAT 9
-#define HOSTED_FSTAT 10
-#define HOSTED_GETTIMEOFDAY 11
-#define HOSTED_ISATTY 12
-#define HOSTED_SYSTEM 13
-
-typedef uint32_t gdb_mode_t;
-typedef uint32_t gdb_time_t;
-
-struct m68k_gdb_stat {
-  uint32_t    gdb_st_dev;     /* device */
-  uint32_t    gdb_st_ino;     /* inode */
-  gdb_mode_t  gdb_st_mode;    /* protection */
-  uint32_t    gdb_st_nlink;   /* number of hard links */
-  uint32_t    gdb_st_uid;     /* user ID of owner */
-  uint32_t    gdb_st_gid;     /* group ID of owner */
-  uint32_t    gdb_st_rdev;    /* device type (if inode device) */
-  uint64_t    gdb_st_size;    /* total size, in bytes */
-  uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
-  uint64_t    gdb_st_blocks;  /* number of blocks allocated */
-  gdb_time_t  gdb_st_atime;   /* time of last access */
-  gdb_time_t  gdb_st_mtime;   /* time of last modification */
-  gdb_time_t  gdb_st_ctime;   /* time of last change */
-};
-
-struct gdb_timeval {
-  gdb_time_t tv_sec;  /* second */
-  uint64_t tv_usec;   /* microsecond */
-};
-
-#define GDB_O_RDONLY   0x0
-#define GDB_O_WRONLY   0x1
-#define GDB_O_RDWR     0x2
-#define GDB_O_APPEND   0x8
-#define GDB_O_CREAT  0x200
-#define GDB_O_TRUNC  0x400
-#define GDB_O_EXCL   0x800
-
-static int translate_openflags(int flags)
-{
-    int hf;
-
-    if (flags & GDB_O_WRONLY)
-        hf = O_WRONLY;
-    else if (flags & GDB_O_RDWR)
-        hf = O_RDWR;
-    else
-        hf = O_RDONLY;
-
-    if (flags & GDB_O_APPEND) hf |= O_APPEND;
-    if (flags & GDB_O_CREAT) hf |= O_CREAT;
-    if (flags & GDB_O_TRUNC) hf |= O_TRUNC;
-    if (flags & GDB_O_EXCL) hf |= O_EXCL;
-
-    return hf;
-}
-
-static void translate_stat(struct m68k_gdb_stat *p, struct stat *s)
-{
-    p->gdb_st_dev = tswap16(s->st_dev);
-    p->gdb_st_ino = tswap16(s->st_ino);
-    p->gdb_st_mode = tswap32(s->st_mode);
-    p->gdb_st_nlink = tswap16(s->st_nlink);
-    p->gdb_st_uid = tswap16(s->st_uid);
-    p->gdb_st_gid = tswap16(s->st_gid);
-    p->gdb_st_rdev = tswap16(s->st_rdev);
-    p->gdb_st_size = tswap32(s->st_size);
-    p->gdb_st_atime = tswap32(s->st_atime);
-    p->gdb_st_mtime = tswap32(s->st_mtime);
-    p->gdb_st_ctime = tswap32(s->st_ctime);
-    p->gdb_st_blksize = tswap32(s->st_blksize);
-    p->gdb_st_blocks = tswap32(s->st_blocks);
-}
-
-static inline uint32_t check_err(CPUM68KState *env, uint32_t code)
-{
-  if (code == (uint32_t)-1) {
-      env->sr |= CCF_C;
-  } else {
-      env->sr &= ~CCF_C;
-      env->dregs[0] = code;
-  }
-  return code;
-}
-
-#define ARG(x) tswap32(args[x])
-void do_m68k_semihosting(CPUM68KState *env, int nr)
-{
-    uint32_t *args;
-
-    args = (uint32_t *)env->dregs[1];
-    switch (nr) {
-    case HOSTED_EXIT:
-        exit(env->dregs[0]);
-    case HOSTED_OPEN:
-        /* Assume name is NULL terminated.  */
-        check_err(env, open((char *)ARG(0), translate_openflags(ARG(2)),
-                            ARG(3)));
-        break;
-    case HOSTED_CLOSE:
-        {
-            /* Ignore attempts to close stdin/out/err.  */
-            int fd = ARG(0);
-            if (fd > 2)
-              check_err(env, close(fd));
-            else
-              check_err(env, 0);
-            break;
-        }
-    case HOSTED_READ:
-        check_err(env, read(ARG(0), (void *)ARG(1), ARG(2)));
-        break;
-    case HOSTED_WRITE:
-        check_err(env, write(ARG(0), (void *)ARG(1), ARG(2)));
-        break;
-    case HOSTED_LSEEK:
-        {
-            uint64_t off;
-            off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32);
-            check_err(env, lseek(ARG(0), off, ARG(3)));
-        }
-        break;
-    case HOSTED_RENAME:
-        /* Assume names are NULL terminated.  */
-        check_err(env, rename((char *)ARG(0), (char *)ARG(2)));
-        break;
-    case HOSTED_UNLINK:
-        /* Assume name is NULL terminated.  */
-        check_err(env, unlink((char *)ARG(0)));
-        break;
-    case HOSTED_STAT:
-        /* Assume name is NULL terminated.  */
-        {
-            struct stat s;
-            int rc;
-            rc = check_err(env, stat((char *)ARG(0), &s));
-            if (rc == 0) {
-                translate_stat((struct m68k_gdb_stat *)ARG(2), &s);
-            }
-        }
-        break;
-    case HOSTED_FSTAT:
-        {
-            struct stat s;
-            int rc;
-            rc = check_err(env, fstat(ARG(0), &s));
-            if (rc == 0) {
-                translate_stat((struct m68k_gdb_stat *)ARG(1), &s);
-            }
-        }
-        break;
-    case HOSTED_GETTIMEOFDAY:
-        {
-            struct timeval tv;
-            struct gdb_timeval *p;
-            int rc;
-            rc = check_err(env, gettimeofday(&tv, NULL));
-            if (rc != 0) {
-                p = (struct gdb_timeval *)ARG(0);
-                p->tv_sec = tswap32(tv.tv_sec);
-                p->tv_usec = tswap64(tv.tv_usec);
-            }
-        }
-        break;
-    case HOSTED_ISATTY:
-        check_err(env, isatty(ARG(0)));
-        break;
-    case HOSTED_SYSTEM:
-        /* Assume name is NULL terminated.  */
-        check_err(env, system((char *)ARG(0)));
-        break;
-    default:
-        cpu_abort(env, "Unsupported semihosting syscall %d\n", nr);
-    }
-}
diff --git a/linux-user/m68k-sim.c b/linux-user/m68k-sim.c
index 667808e..aab82dd 100644
--- a/linux-user/m68k-sim.c
+++ b/linux-user/m68k-sim.c
@@ -1,6 +1,6 @@
 /*
  *  m68k simulator syscall interface
- * 
+ *
  *  Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
  *
  *  This program is free software; you can redistribute it and/or modify
diff --git a/linux-user/m68k/syscall_nr.h b/linux-user/m68k/syscall_nr.h
index a39535f..0a802f4 100644
--- a/linux-user/m68k/syscall_nr.h
+++ b/linux-user/m68k/syscall_nr.h
@@ -281,3 +281,42 @@
 #define TARGET_NR_add_key            279
 #define TARGET_NR_request_key        280
 #define TARGET_NR_keyctl             281
+#define TARGET_NR_ioprio_set		282
+#define TARGET_NR_ioprio_get		283
+#define TARGET_NR_inotify_init	284
+#define TARGET_NR_inotify_add_watch	285
+#define TARGET_NR_inotify_rm_watch	286
+#define TARGET_NR_migrate_pages	287
+#define TARGET_NR_openat		288
+#define TARGET_NR_mkdirat		289
+#define TARGET_NR_mknodat		290
+#define TARGET_NR_fchownat		291
+#define TARGET_NR_futimesat		292
+#define TARGET_NR_fstatat64		293
+#define TARGET_NR_unlinkat		294
+#define TARGET_NR_renameat		295
+#define TARGET_NR_linkat		296
+#define TARGET_NR_symlinkat		297
+#define TARGET_NR_readlinkat		298
+#define TARGET_NR_fchmodat		299
+#define TARGET_NR_faccessat		300
+#define TARGET_NR_pselect6		301
+#define TARGET_NR_ppoll		302
+#define TARGET_NR_unshare		303
+#define TARGET_NR_set_robust_list	304
+#define TARGET_NR_get_robust_list	305
+#define TARGET_NR_splice		306
+#define TARGET_NR_sync_file_range	307
+#define TARGET_NR_tee		308
+#define TARGET_NR_vmsplice		309
+#define TARGET_NR_move_pages		310
+#define TARGET_NR_sched_setaffinity	311
+#define TARGET_NR_sched_getaffinity	312
+#define TARGET_NR_kexec_load		313
+#define TARGET_NR_getcpu		314
+#define TARGET_NR_epoll_pwait	315
+#define TARGET_NR_utimensat		316
+#define TARGET_NR_signalfd		317
+#define TARGET_NR_timerfd		318
+#define TARGET_NR_eventfd		319
+#define TARGET_NR_fallocate		320
diff --git a/linux-user/m68k/target_signal.h b/linux-user/m68k/target_signal.h
new file mode 100644
index 0000000..b481195
--- /dev/null
+++ b/linux-user/m68k/target_signal.h
@@ -0,0 +1,24 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ	8192
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/m68k/termbits.h b/linux-user/m68k/termbits.h
index 36ead08..1bce39d 100644
--- a/linux-user/m68k/termbits.h
+++ b/linux-user/m68k/termbits.h
@@ -27,6 +27,7 @@
 #define TARGET_IXANY   0004000
 #define TARGET_IXOFF   0010000
 #define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
 
 /* c_oflag bits */
 #define TARGET_OPOST   0000001
@@ -97,8 +98,20 @@
 #define  TARGET_B115200 0010002
 #define  TARGET_B230400 0010003
 #define  TARGET_B460800 0010004
+#define  TARGET_B500000 0010005
+#define  TARGET_B576000 0010006
+#define  TARGET_B921600 0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
 #define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
-#define TARGET_CRTSCTS   020000000000          /* flow control */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
 
 /* c_lflag bits */
 #define TARGET_ISIG    0000001
diff --git a/linux-user/main.c b/linux-user/main.c
index 7199372..af99d04 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -1,6 +1,6 @@
 /*
  *  qemu user main
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -131,7 +131,7 @@
     return cpu_get_real_ticks();
 }
 
-static void write_dt(void *ptr, unsigned long addr, unsigned long limit, 
+static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
                      int flags)
 {
     unsigned int e1, e2;
@@ -144,7 +144,7 @@
     p[1] = tswapl(e2);
 }
 
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
                      unsigned long addr, unsigned int sel)
 {
     unsigned int e1, e2;
@@ -176,8 +176,8 @@
         switch(trapnr) {
         case 0x80:
             /* linux syscall */
-            env->regs[R_EAX] = do_syscall(env, 
-                                          env->regs[R_EAX], 
+            env->regs[R_EAX] = do_syscall(env,
+                                          env->regs[R_EAX],
                                           env->regs[R_EBX],
                                           env->regs[R_ECX],
                                           env->regs[R_EDX],
@@ -194,9 +194,12 @@
             queue_signal(info.si_signo, &info);
             break;
         case EXCP0D_GPF:
+#ifndef TARGET_X86_64
             if (env->eflags & VM_MASK) {
                 handle_vm86_fault(env);
-            } else {
+            } else
+#endif
+            {
                 info.si_signo = SIGSEGV;
                 info.si_errno = 0;
                 info.si_code = TARGET_SI_KERNEL;
@@ -215,9 +218,12 @@
             queue_signal(info.si_signo, &info);
             break;
         case EXCP00_DIVZ:
+#ifndef TARGET_X86_64
             if (env->eflags & VM_MASK) {
                 handle_vm86_trap(env, trapnr);
-            } else {
+            } else
+#endif
+            {
                 /* division by zero */
                 info.si_signo = SIGFPE;
                 info.si_errno = 0;
@@ -228,9 +234,12 @@
             break;
         case EXCP01_SSTP:
         case EXCP03_INT3:
+#ifndef TARGET_X86_64
             if (env->eflags & VM_MASK) {
                 handle_vm86_trap(env, trapnr);
-            } else {
+            } else
+#endif
+            {
                 info.si_signo = SIGTRAP;
                 info.si_errno = 0;
                 if (trapnr == EXCP01_SSTP) {
@@ -245,9 +254,12 @@
             break;
         case EXCP04_INTO:
         case EXCP05_BOUND:
+#ifndef TARGET_X86_64
             if (env->eflags & VM_MASK) {
                 handle_vm86_trap(env, trapnr);
-            } else {
+            } else
+#endif
+            {
                 info.si_signo = SIGSEGV;
                 info.si_errno = 0;
                 info.si_code = TARGET_SI_KERNEL;
@@ -281,7 +293,7 @@
             break;
         default:
             pc = env->segs[R_CS].base + env->eip;
-            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n", 
+            fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
                     (long)pc, trapnr);
             abort();
         }
@@ -319,7 +331,7 @@
     unsigned int n, insn;
     target_siginfo_t info;
     uint32_t addr;
-    
+
     for(;;) {
         trapnr = cpu_arm_exec(env);
         switch(trapnr) {
@@ -331,7 +343,7 @@
                 /* we handle the FPU emulation here, as Linux */
                 /* we get the opcode */
                 opcode = tget32(env->regs[15]);
-                
+
                 if (EmulateAll(opcode, &ts->fpa, env) == 0) {
                     info.si_signo = SIGILL;
                     info.si_errno = 0;
@@ -383,8 +395,8 @@
                         n -= ARM_SYSCALL_BASE;
                         env->eabi = 0;
                     }
-                    env->regs[0] = do_syscall(env, 
-                                              n, 
+                    env->regs[0] = do_syscall(env,
+                                              n,
                                               env->regs[0],
                                               env->regs[1],
                                               env->regs[2],
@@ -431,7 +443,7 @@
             break;
         default:
         error:
-            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
                     trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
             abort();
@@ -463,10 +475,10 @@
 {
     unsigned int i;
     target_ulong sp_ptr;
-    
+
     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
 #if defined(DEBUG_WIN)
-    printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", 
+    printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
            (int)sp_ptr, cwp1);
 #endif
     for(i = 0; i < 16; i++) {
@@ -494,15 +506,15 @@
 {
     unsigned int new_wim, i, cwp1;
     target_ulong sp_ptr;
-    
+
     new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
         ((1LL << NWINDOWS) - 1);
-    
+
     /* restore the invalid window */
     cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
     sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
 #if defined(DEBUG_WIN)
-    printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", 
+    printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
            (int)sp_ptr, cwp1);
 #endif
     for(i = 0; i < 16; i++) {
@@ -543,20 +555,20 @@
 {
     int trapnr, ret;
     target_siginfo_t info;
-    
+
     while (1) {
         trapnr = cpu_sparc_exec (env);
-        
+
         switch (trapnr) {
 #ifndef TARGET_SPARC64
-        case 0x88: 
+        case 0x88:
         case 0x90:
 #else
         case 0x16d:
 #endif
             ret = do_syscall (env, env->gregs[1],
-                              env->regwptr[0], env->regwptr[1], 
-                              env->regwptr[2], env->regwptr[3], 
+                              env->regwptr[0], env->regwptr[1],
+                              env->regwptr[2], env->regwptr[3],
                               env->regwptr[4], env->regwptr[5]);
             if ((unsigned int)ret >= (unsigned int)(-515)) {
 #ifdef TARGET_SPARC64
@@ -608,7 +620,20 @@
         case TT_FILL: /* window underflow */
             restore_window(env);
             break;
-	    // XXX
+        case TT_TFAULT:
+        case TT_DFAULT:
+            {
+                info.si_signo = SIGSEGV;
+                info.si_errno = 0;
+                /* XXX: check env->error_code */
+                info.si_code = TARGET_SEGV_MAPERR;
+                if (trapnr == TT_DFAULT)
+                    info._sifields._sigfault._addr = env->dmmuregs[4];
+                else
+                    info._sifields._sigfault._addr = env->tpc[env->tl];
+                queue_signal(info.si_signo, &info);
+            }
+            break;
 #endif
         case EXCP_INTERRUPT:
             /* just indicate that signals should be handled asap */
@@ -639,68 +664,448 @@
 #endif
 
 #ifdef TARGET_PPC
-
 static inline uint64_t cpu_ppc_get_tb (CPUState *env)
 {
     /* TO FIX */
     return 0;
 }
-  
+
 uint32_t cpu_ppc_load_tbl (CPUState *env)
 {
     return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
 }
-  
+
 uint32_t cpu_ppc_load_tbu (CPUState *env)
 {
     return cpu_ppc_get_tb(env) >> 32;
 }
-  
-static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
+
+uint32_t cpu_ppc_load_atbl (CPUState *env)
 {
-    /* TO FIX */
+    return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
 }
 
-void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+uint32_t cpu_ppc_load_atbu (CPUState *env)
 {
-    cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
+    return cpu_ppc_get_tb(env) >> 32;
 }
- 
-void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
 {
-    cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
+    return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
 }
-  
-uint32_t cpu_ppc_load_decr (CPUState *env)
+
+/* XXX: to be fixed */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
 {
-    /* TO FIX */
     return -1;
 }
- 
-void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
 {
-    /* TO FIX */
+    return -1;
 }
- 
+
+#define EXCP_DUMP(env, fmt, args...)                                         \
+do {                                                                          \
+    fprintf(stderr, fmt , ##args);                                            \
+    cpu_dump_state(env, stderr, fprintf, 0);                                  \
+    if (loglevel != 0) {                                                      \
+        fprintf(logfile, fmt , ##args);                                       \
+        cpu_dump_state(env, logfile, fprintf, 0);                             \
+    }                                                                         \
+} while (0)
+
 void cpu_loop(CPUPPCState *env)
 {
     target_siginfo_t info;
     int trapnr;
     uint32_t ret;
-    
+
     for(;;) {
         trapnr = cpu_ppc_exec(env);
-        if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
-            trapnr != EXCP_TRACE) {
-            if (loglevel > 0) {
-                cpu_dump_state(env, logfile, fprintf, 0);
-            }
-        }
         switch(trapnr) {
-        case EXCP_NONE:
+        case POWERPC_EXCP_NONE:
+            /* Just go on */
             break;
-        case EXCP_SYSCALL_USER:
-            /* system call */
+        case POWERPC_EXCP_CRITICAL: /* Critical input                        */
+            cpu_abort(env, "Critical interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_MCHECK:   /* Machine check exception               */
+            cpu_abort(env, "Machine check exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DSI:      /* Data storage exception                */
+            EXCP_DUMP(env, "Invalid data memory access: 0x" ADDRX "\n",
+                      env->spr[SPR_DAR]);
+            /* XXX: check this. Seems bugged */
+            switch (env->error_code & 0xFF000000) {
+            case 0x40000000:
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                break;
+            case 0x04000000:
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                info.si_code = TARGET_ILL_ILLADR;
+                break;
+            case 0x08000000:
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_ACCERR;
+                break;
+            default:
+                /* Let's send a regular segfault... */
+                EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
+                          env->error_code);
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                break;
+            }
+            info._sifields._sigfault._addr = env->nip;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_ISI:      /* Instruction storage exception         */
+            EXCP_DUMP(env, "Invalid instruction fetch: 0x\n" ADDRX "\n",
+                      env->spr[SPR_DAR]);
+            /* XXX: check this */
+            switch (env->error_code & 0xFF000000) {
+            case 0x40000000:
+                info.si_signo = TARGET_SIGSEGV;
+            info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                break;
+            case 0x10000000:
+            case 0x08000000:
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_ACCERR;
+                break;
+            default:
+                /* Let's send a regular segfault... */
+                EXCP_DUMP(env, "Invalid segfault errno (%02x)\n",
+                          env->error_code);
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_MAPERR;
+                break;
+            }
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_EXTERNAL: /* External input                        */
+            cpu_abort(env, "External interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ALIGN:    /* Alignment exception                   */
+            EXCP_DUMP(env, "Unaligned memory access\n");
+            /* XXX: check this */
+            info.si_signo = TARGET_SIGBUS;
+            info.si_errno = 0;
+            info.si_code = TARGET_BUS_ADRALN;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_PROGRAM:  /* Program exception                     */
+            /* XXX: check this */
+            switch (env->error_code & ~0xF) {
+            case POWERPC_EXCP_FP:
+                EXCP_DUMP(env, "Floating point program exception\n");
+                /* Set FX */
+                env->fpscr[7] |= 0x8;
+                /* Finally, update FEX */
+                if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
+                    ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
+                    env->fpscr[7] |= 0x4;
+                info.si_signo = TARGET_SIGFPE;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_FP_OX:
+                    info.si_code = TARGET_FPE_FLTOVF;
+                    break;
+                case POWERPC_EXCP_FP_UX:
+                    info.si_code = TARGET_FPE_FLTUND;
+                    break;
+                case POWERPC_EXCP_FP_ZX:
+                case POWERPC_EXCP_FP_VXZDZ:
+                    info.si_code = TARGET_FPE_FLTDIV;
+                    break;
+                case POWERPC_EXCP_FP_XX:
+                    info.si_code = TARGET_FPE_FLTRES;
+                    break;
+                case POWERPC_EXCP_FP_VXSOFT:
+                    info.si_code = TARGET_FPE_FLTINV;
+                    break;
+                case POWERPC_EXCP_FP_VXNAN:
+                case POWERPC_EXCP_FP_VXISI:
+                case POWERPC_EXCP_FP_VXIDI:
+                case POWERPC_EXCP_FP_VXIMZ:
+                case POWERPC_EXCP_FP_VXVC:
+                case POWERPC_EXCP_FP_VXSQRT:
+                case POWERPC_EXCP_FP_VXCVI:
+                    info.si_code = TARGET_FPE_FLTSUB;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown floating point exception (%02x)\n",
+                              env->error_code);
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_INVAL:
+                EXCP_DUMP(env, "Invalid instruction\n");
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_INVAL_INVAL:
+                    info.si_code = TARGET_ILL_ILLOPC;
+                    break;
+                case POWERPC_EXCP_INVAL_LSWX:
+                    info.si_code = TARGET_ILL_ILLOPN;
+                    break;
+                case POWERPC_EXCP_INVAL_SPR:
+                    info.si_code = TARGET_ILL_PRVREG;
+                    break;
+                case POWERPC_EXCP_INVAL_FP:
+                    info.si_code = TARGET_ILL_COPROC;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown invalid operation (%02x)\n",
+                              env->error_code & 0xF);
+                    info.si_code = TARGET_ILL_ILLADR;
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_PRIV:
+                EXCP_DUMP(env, "Privilege violation\n");
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                switch (env->error_code & 0xF) {
+                case POWERPC_EXCP_PRIV_OPC:
+                    info.si_code = TARGET_ILL_PRVOPC;
+                    break;
+                case POWERPC_EXCP_PRIV_REG:
+                    info.si_code = TARGET_ILL_PRVREG;
+                    break;
+                default:
+                    EXCP_DUMP(env, "Unknown privilege violation (%02x)\n",
+                              env->error_code & 0xF);
+                    info.si_code = TARGET_ILL_PRVOPC;
+                    break;
+                }
+                break;
+            case POWERPC_EXCP_TRAP:
+                cpu_abort(env, "Tried to call a TRAP\n");
+                break;
+            default:
+                /* Should not happen ! */
+                cpu_abort(env, "Unknown program exception (%02x)\n",
+                          env->error_code);
+                break;
+            }
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_FPU:      /* Floating-point unavailable exception  */
+            EXCP_DUMP(env, "No floating point allowed\n");
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_COPROC;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_SYSCALL:  /* System call exception                 */
+            cpu_abort(env, "Syscall exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_APU:      /* Auxiliary processor unavailable       */
+            EXCP_DUMP(env, "No APU instruction allowed\n");
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_COPROC;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_DECR:     /* Decrementer exception                 */
+            cpu_abort(env, "Decrementer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_FIT:      /* Fixed-interval timer interrupt        */
+            cpu_abort(env, "Fix interval timer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_WDT:      /* Watchdog timer interrupt              */
+            cpu_abort(env, "Watchdog timer interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DTLB:     /* Data TLB error                        */
+            cpu_abort(env, "Data TLB exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ITLB:     /* Instruction TLB error                 */
+            cpu_abort(env, "Instruction TLB exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_DEBUG:    /* Debug interrupt                       */
+            /* XXX: check this */
+            {
+                int sig;
+
+                sig = gdb_handlesig(env, TARGET_SIGTRAP);
+                if (sig) {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(info.si_signo, &info);
+                  }
+            }
+            break;
+#if defined(TARGET_PPCEMB)
+        case POWERPC_EXCP_SPEU:     /* SPE/embedded floating-point unavail.  */
+            EXCP_DUMP(env, "No SPE/floating-point instruction allowed\n");
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_COPROC;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_EFPDI:    /* Embedded floating-point data IRQ      */
+            cpu_abort(env, "Embedded floating-point data IRQ not handled\n");
+            break;
+        case POWERPC_EXCP_EFPRI:    /* Embedded floating-point round IRQ     */
+            cpu_abort(env, "Embedded floating-point round IRQ not handled\n");
+            break;
+        case POWERPC_EXCP_EPERFM:   /* Embedded performance monitor IRQ      */
+            cpu_abort(env, "Performance monitor exception not handled\n");
+            break;
+        case POWERPC_EXCP_DOORI:    /* Embedded doorbell interrupt           */
+            cpu_abort(env, "Doorbell interrupt while in user mode. "
+                       "Aborting\n");
+            break;
+        case POWERPC_EXCP_DOORCI:   /* Embedded doorbell critical interrupt  */
+            cpu_abort(env, "Doorbell critical interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_RESET:    /* System reset exception                */
+            cpu_abort(env, "Reset interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+#endif /* defined(TARGET_PPCEMB) */
+#if defined(TARGET_PPC64) /* PowerPC 64 */
+        case POWERPC_EXCP_DSEG:     /* Data segment exception                */
+            cpu_abort(env, "Data segment exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_ISEG:     /* Instruction segment exception         */
+            cpu_abort(env, "Instruction segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+#endif /* defined(TARGET_PPC64) */
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+        case POWERPC_EXCP_HDECR:    /* Hypervisor decrementer exception      */
+            cpu_abort(env, "Hypervisor decrementer interrupt "
+                      "while in user mode. Aborting\n");
+            break;
+#endif /* defined(TARGET_PPC64H) */
+        case POWERPC_EXCP_TRACE:    /* Trace exception                       */
+            /* Nothing to do:
+             * we use this exception to emulate step-by-step execution mode.
+             */
+            break;
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+        case POWERPC_EXCP_HDSI:     /* Hypervisor data storage exception     */
+            cpu_abort(env, "Hypervisor data storage exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HISI:     /* Hypervisor instruction storage excp   */
+            cpu_abort(env, "Hypervisor instruction storage exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HDSEG:    /* Hypervisor data segment exception     */
+            cpu_abort(env, "Hypervisor data segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_HISEG:    /* Hypervisor instruction segment excp   */
+            cpu_abort(env, "Hypervisor instruction segment exception "
+                      "while in user mode. Aborting\n");
+            break;
+#endif /* defined(TARGET_PPC64H) */
+        case POWERPC_EXCP_VPU:      /* Vector unavailable exception          */
+            EXCP_DUMP(env, "No Altivec instructions allowed\n");
+            info.si_signo = TARGET_SIGILL;
+            info.si_errno = 0;
+            info.si_code = TARGET_ILL_COPROC;
+            info._sifields._sigfault._addr = env->nip - 4;
+            queue_signal(info.si_signo, &info);
+            break;
+        case POWERPC_EXCP_PIT:      /* Programmable interval timer IRQ       */
+            cpu_abort(env, "Programable interval timer interrupt "
+                      "while in user mode. Aborting\n");
+            break;
+        case POWERPC_EXCP_IO:       /* IO error exception                    */
+            cpu_abort(env, "IO error exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_RUNM:     /* Run mode exception                    */
+            cpu_abort(env, "Run mode exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_EMUL:     /* Emulation trap exception              */
+            cpu_abort(env, "Emulation trap exception not handled\n");
+            break;
+        case POWERPC_EXCP_IFTLB:    /* Instruction fetch TLB error           */
+            cpu_abort(env, "Instruction fetch TLB exception "
+                      "while in user-mode. Aborting");
+            break;
+        case POWERPC_EXCP_DLTLB:    /* Data load TLB miss                    */
+            cpu_abort(env, "Data load TLB exception while in user-mode. "
+                      "Aborting");
+            break;
+        case POWERPC_EXCP_DSTLB:    /* Data store TLB miss                   */
+            cpu_abort(env, "Data store TLB exception while in user-mode. "
+                      "Aborting");
+            break;
+        case POWERPC_EXCP_FPA:      /* Floating-point assist exception       */
+            cpu_abort(env, "Floating-point assist exception not handled\n");
+            break;
+        case POWERPC_EXCP_IABR:     /* Instruction address breakpoint        */
+            cpu_abort(env, "Instruction address breakpoint exception "
+                      "not handled\n");
+            break;
+        case POWERPC_EXCP_SMI:      /* System management interrupt           */
+            cpu_abort(env, "System management interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_THERM:    /* Thermal interrupt                     */
+            cpu_abort(env, "Thermal interrupt interrupt while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_PERFM:   /* Embedded performance monitor IRQ      */
+            cpu_abort(env, "Performance monitor exception not handled\n");
+            break;
+        case POWERPC_EXCP_VPUA:     /* Vector assist exception               */
+            cpu_abort(env, "Vector assist exception not handled\n");
+            break;
+        case POWERPC_EXCP_SOFTP:    /* Soft patch exception                  */
+            cpu_abort(env, "Soft patch exception not handled\n");
+            break;
+        case POWERPC_EXCP_MAINT:    /* Maintenance exception                 */
+            cpu_abort(env, "Maintenance exception while in user mode. "
+                      "Aborting\n");
+            break;
+        case POWERPC_EXCP_STOP:     /* stop translation                      */
+            /* We did invalidate the instruction cache. Go on */
+            break;
+        case POWERPC_EXCP_BRANCH:   /* branch instruction:                   */
+            /* We just stopped because of a branch. Go on */
+            break;
+        case POWERPC_EXCP_SYSCALL_USER:
+            /* system call in user-mode emulation */
             /* WARNING:
              * PPC ABI uses overflow flag in cr0 to signal an error
              * in syscalls.
@@ -722,287 +1127,12 @@
             printf("syscall returned 0x%08x (%d)\n", ret, ret);
 #endif
             break;
-        case EXCP_RESET:
-            /* Should not happen ! */
-            fprintf(stderr, "RESET asked... Stop emulation\n");
-            if (loglevel)
-                fprintf(logfile, "RESET asked... Stop emulation\n");
-            abort();
-        case EXCP_MACHINE_CHECK:
-            fprintf(stderr, "Machine check exeption...  Stop emulation\n");
-            if (loglevel)
-                fprintf(logfile, "RESET asked... Stop emulation\n");
-            info.si_signo = TARGET_SIGBUS;
-            info.si_errno = 0;
-            info.si_code = TARGET_BUS_OBJERR;
-            info._sifields._sigfault._addr = env->nip - 4;
-            queue_signal(info.si_signo, &info);
-        case EXCP_DSI:
-            fprintf(stderr, "Invalid data memory access: 0x%08x\n",
-                    env->spr[SPR_DAR]);
-            if (loglevel) {
-                fprintf(logfile, "Invalid data memory access: 0x%08x\n",
-                        env->spr[SPR_DAR]);
-            }
-            switch (env->error_code & 0xFF000000) {
-            case 0x40000000:
-                info.si_signo = TARGET_SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SEGV_MAPERR;
-                break;
-            case 0x04000000:
-                info.si_signo = TARGET_SIGILL;
-                info.si_errno = 0;
-                info.si_code = TARGET_ILL_ILLADR;
-                break;
-            case 0x08000000:
-                info.si_signo = TARGET_SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SEGV_ACCERR;
-                break;
-            default:
-                /* Let's send a regular segfault... */
-                fprintf(stderr, "Invalid segfault errno (%02x)\n",
-                        env->error_code);
-                if (loglevel) {
-                    fprintf(logfile, "Invalid segfault errno (%02x)\n",
-                            env->error_code);
-                }
-                info.si_signo = TARGET_SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SEGV_MAPERR;
-                break;
-            }
-            info._sifields._sigfault._addr = env->nip;
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_ISI:
-            fprintf(stderr, "Invalid instruction fetch\n");
-            if (loglevel)
-                fprintf(logfile, "Invalid instruction fetch\n");
-            switch (env->error_code & 0xFF000000) {
-            case 0x40000000:
-                info.si_signo = TARGET_SIGSEGV;
-            info.si_errno = 0;
-                info.si_code = TARGET_SEGV_MAPERR;
-                break;
-            case 0x10000000:
-            case 0x08000000:
-                info.si_signo = TARGET_SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SEGV_ACCERR;
-                break;
-            default:
-                /* Let's send a regular segfault... */
-                fprintf(stderr, "Invalid segfault errno (%02x)\n",
-                        env->error_code);
-                if (loglevel) {
-                    fprintf(logfile, "Invalid segfault errno (%02x)\n",
-                            env->error_code);
-                }
-                info.si_signo = TARGET_SIGSEGV;
-                info.si_errno = 0;
-                info.si_code = TARGET_SEGV_MAPERR;
-                break;
-            }
-            info._sifields._sigfault._addr = env->nip - 4;
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_EXTERNAL:
-            /* Should not happen ! */
-            fprintf(stderr, "External interruption... Stop emulation\n");
-            if (loglevel)
-                fprintf(logfile, "External interruption... Stop emulation\n");
-            abort();
-        case EXCP_ALIGN:
-            fprintf(stderr, "Invalid unaligned memory access\n");
-            if (loglevel)
-                fprintf(logfile, "Invalid unaligned memory access\n");
-            info.si_signo = TARGET_SIGBUS;
-            info.si_errno = 0;
-            info.si_code = TARGET_BUS_ADRALN;
-            info._sifields._sigfault._addr = env->nip - 4;
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_PROGRAM:
-            switch (env->error_code & ~0xF) {
-            case EXCP_FP:
-            fprintf(stderr, "Program exception\n");
-                if (loglevel)
-                    fprintf(logfile, "Program exception\n");
-                /* Set FX */
-                env->fpscr[7] |= 0x8;
-                /* Finally, update FEX */
-                if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
-                    ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
-                    env->fpscr[7] |= 0x4;
-                info.si_signo = TARGET_SIGFPE;
-                info.si_errno = 0;
-                switch (env->error_code & 0xF) {
-                case EXCP_FP_OX:
-                    info.si_code = TARGET_FPE_FLTOVF;
-                    break;
-                case EXCP_FP_UX:
-                    info.si_code = TARGET_FPE_FLTUND;
-                    break;
-                case EXCP_FP_ZX:
-                case EXCP_FP_VXZDZ:
-                    info.si_code = TARGET_FPE_FLTDIV;
-                    break;
-                case EXCP_FP_XX:
-                    info.si_code = TARGET_FPE_FLTRES;
-                    break;
-                case EXCP_FP_VXSOFT:
-                    info.si_code = TARGET_FPE_FLTINV;
-                    break;
-                case EXCP_FP_VXNAN:
-                case EXCP_FP_VXISI:
-                case EXCP_FP_VXIDI:
-                case EXCP_FP_VXIMZ:
-                case EXCP_FP_VXVC:
-                case EXCP_FP_VXSQRT:
-                case EXCP_FP_VXCVI:
-                    info.si_code = TARGET_FPE_FLTSUB;
-                    break;
-                default:
-                    fprintf(stderr, "Unknown floating point exception "
-                            "(%02x)\n", env->error_code);
-                    if (loglevel) {
-                        fprintf(logfile, "Unknown floating point exception "
-                                "(%02x)\n", env->error_code & 0xF);
-                    }
-                }
-            break;
-        case EXCP_INVAL:
-                fprintf(stderr, "Invalid instruction\n");
-                if (loglevel)
-                    fprintf(logfile, "Invalid instruction\n");
-                info.si_signo = TARGET_SIGILL;
-                info.si_errno = 0;
-                switch (env->error_code & 0xF) {
-                case EXCP_INVAL_INVAL:
-                    info.si_code = TARGET_ILL_ILLOPC;
-                    break;
-                case EXCP_INVAL_LSWX:
-            info.si_code = TARGET_ILL_ILLOPN;
-                    break;
-                case EXCP_INVAL_SPR:
-                    info.si_code = TARGET_ILL_PRVREG;
-                    break;
-                case EXCP_INVAL_FP:
-                    info.si_code = TARGET_ILL_COPROC;
-                    break;
-                default:
-                    fprintf(stderr, "Unknown invalid operation (%02x)\n",
-                            env->error_code & 0xF);
-                    if (loglevel) {
-                        fprintf(logfile, "Unknown invalid operation (%02x)\n",
-                                env->error_code & 0xF);
-                    }
-                    info.si_code = TARGET_ILL_ILLADR;
-                    break;
-                }
-                break;
-            case EXCP_PRIV:
-                fprintf(stderr, "Privilege violation\n");
-                if (loglevel)
-                    fprintf(logfile, "Privilege violation\n");
-                info.si_signo = TARGET_SIGILL;
-                info.si_errno = 0;
-                switch (env->error_code & 0xF) {
-                case EXCP_PRIV_OPC:
-                    info.si_code = TARGET_ILL_PRVOPC;
-                    break;
-                case EXCP_PRIV_REG:
-                    info.si_code = TARGET_ILL_PRVREG;
-                break;
-                default:
-                    fprintf(stderr, "Unknown privilege violation (%02x)\n",
-                            env->error_code & 0xF);
-                    info.si_code = TARGET_ILL_PRVOPC;
-                    break;
-                }
-                break;
-            case EXCP_TRAP:
-                fprintf(stderr, "Tried to call a TRAP\n");
-                if (loglevel)
-                    fprintf(logfile, "Tried to call a TRAP\n");
-                abort();
-            default:
-                /* Should not happen ! */
-                fprintf(stderr, "Unknown program exception (%02x)\n",
-                        env->error_code);
-                if (loglevel) {
-                    fprintf(logfile, "Unknwon program exception (%02x)\n",
-                            env->error_code);
-                }
-                abort();
-            }
-            info._sifields._sigfault._addr = env->nip - 4;
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_NO_FP:
-            fprintf(stderr, "No floating point allowed\n");
-            if (loglevel)
-                fprintf(logfile, "No floating point allowed\n");
-            info.si_signo = TARGET_SIGILL;
-            info.si_errno = 0;
-            info.si_code = TARGET_ILL_COPROC;
-            info._sifields._sigfault._addr = env->nip - 4;
-            queue_signal(info.si_signo, &info);
-            break;
-        case EXCP_DECR:
-            /* Should not happen ! */
-            fprintf(stderr, "Decrementer exception\n");
-            if (loglevel)
-                fprintf(logfile, "Decrementer exception\n");
-            abort();
-        case EXCP_TRACE:
-            /* Do nothing: we use this to trace execution */
-            break;
-        case EXCP_FP_ASSIST:
-            /* Should not happen ! */
-            fprintf(stderr, "Floating point assist exception\n");
-            if (loglevel)
-                fprintf(logfile, "Floating point assist exception\n");
-            abort();
-        case EXCP_MTMSR:
-            /* We reloaded the msr, just go on */
-            if (msr_pr == 0) {
-                fprintf(stderr, "Tried to go into supervisor mode !\n");
-                if (loglevel)
-                    fprintf(logfile, "Tried to go into supervisor mode !\n");
-                abort();
-        }
-            break;
-        case EXCP_BRANCH:
-            /* We stopped because of a jump... */
-            break;
         case EXCP_INTERRUPT:
-            /* Don't know why this should ever happen... */
-            break;
-        case EXCP_DEBUG:
-            {
-                int sig;
-
-                sig = gdb_handlesig (env, TARGET_SIGTRAP);
-                if (sig)
-                  {
-                    info.si_signo = sig;
-                    info.si_errno = 0;
-                    info.si_code = TARGET_TRAP_BRKPT;
-                    queue_signal(info.si_signo, &info);
-                  }
-            }
+            /* just indicate that signals should be handled asap */
             break;
         default:
-            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 
-                    trapnr);
-            if (loglevel) {
-                fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
-                        "0x%02x - aborting\n", trapnr, env->error_code);
-            }
-            abort();
+            cpu_abort(env, "Unknown exception 0x%d. Aborting\n", trapnr);
+            break;
         }
         process_pending_signals(env);
     }
@@ -1295,8 +1425,41 @@
 	MIPS_SYS(sys_waitid	, 4)
 	MIPS_SYS(sys_ni_syscall	, 0)	/* available, was setaltroot */
 	MIPS_SYS(sys_add_key	, 5)
-	MIPS_SYS(sys_request_key	, 4)
+	MIPS_SYS(sys_request_key, 4)
 	MIPS_SYS(sys_keyctl	, 5)
+	MIPS_SYS(sys_set_thread_area, 1)
+	MIPS_SYS(sys_inotify_init, 0)
+	MIPS_SYS(sys_inotify_add_watch, 3) /* 4285 */
+	MIPS_SYS(sys_inotify_rm_watch, 2)
+	MIPS_SYS(sys_migrate_pages, 4)
+	MIPS_SYS(sys_openat, 4)
+	MIPS_SYS(sys_mkdirat, 3)
+	MIPS_SYS(sys_mknodat, 4)	/* 4290 */
+	MIPS_SYS(sys_fchownat, 5)
+	MIPS_SYS(sys_futimesat, 3)
+	MIPS_SYS(sys_fstatat64, 4)
+	MIPS_SYS(sys_unlinkat, 3)
+	MIPS_SYS(sys_renameat, 4)	/* 4295 */
+	MIPS_SYS(sys_linkat, 5)
+	MIPS_SYS(sys_symlinkat, 3)
+	MIPS_SYS(sys_readlinkat, 4)
+	MIPS_SYS(sys_fchmodat, 3)
+	MIPS_SYS(sys_faccessat, 3)	/* 4300 */
+	MIPS_SYS(sys_pselect6, 6)
+	MIPS_SYS(sys_ppoll, 5)
+	MIPS_SYS(sys_unshare, 1)
+	MIPS_SYS(sys_splice, 4)
+	MIPS_SYS(sys_sync_file_range, 7) /* 4305 */
+	MIPS_SYS(sys_tee, 4)
+	MIPS_SYS(sys_vmsplice, 4)
+	MIPS_SYS(sys_move_pages, 6)
+	MIPS_SYS(sys_set_robust_list, 2)
+	MIPS_SYS(sys_get_robust_list, 3) /* 4310 */
+	MIPS_SYS(sys_kexec_load, 4)
+	MIPS_SYS(sys_getcpu, 3)
+	MIPS_SYS(sys_epoll_pwait, 6)
+	MIPS_SYS(sys_ioprio_set, 3)
+	MIPS_SYS(sys_ioprio_get, 2)
 };
 
 #undef MIPS_SYS
@@ -1304,53 +1467,47 @@
 void cpu_loop(CPUMIPSState *env)
 {
     target_siginfo_t info;
-    int trapnr, ret, nb_args;
+    int trapnr, ret;
     unsigned int syscall_num;
-    target_ulong arg5, arg6, sp_reg;
 
     for(;;) {
         trapnr = cpu_mips_exec(env);
         switch(trapnr) {
         case EXCP_SYSCALL:
-            {
-                syscall_num = env->gpr[2] - 4000;
-                env->PC += 4;
-                if (syscall_num >= sizeof(mips_syscall_args)) {
-                    ret = -ENOSYS;
-                } else {
-                    nb_args = mips_syscall_args[syscall_num];
-                    if (nb_args >= 5) {
-                        sp_reg = env->gpr[29];
-                        /* these arguments are taken from the stack */
-                        arg5 = tgetl(sp_reg + 16);
-                        if (nb_args >= 6) {
-                            arg6 = tgetl(sp_reg + 20);
-                        } else {
-                            arg6 = 0;
-                        }
-                    } else {
-                        arg5 = 0;
-                        arg6 = 0;
-                    }
-                    ret = do_syscall(env, 
-                                     env->gpr[2], 
-                                     env->gpr[4],
-                                     env->gpr[5],
-                                     env->gpr[6],
-                                     env->gpr[7],
-                                     arg5, 
-                                     arg6);
+            syscall_num = env->gpr[2][env->current_tc] - 4000;
+            env->PC[env->current_tc] += 4;
+            if (syscall_num >= sizeof(mips_syscall_args)) {
+                ret = -ENOSYS;
+            } else {
+                int nb_args;
+                target_ulong sp_reg;
+                target_ulong arg5 = 0, arg6 = 0, arg7 = 0, arg8 = 0;
+
+                nb_args = mips_syscall_args[syscall_num];
+                sp_reg = env->gpr[29][env->current_tc];
+                switch (nb_args) {
+                /* these arguments are taken from the stack */
+                case 8: arg8 = tgetl(sp_reg + 28);
+                case 7: arg7 = tgetl(sp_reg + 24);
+                case 6: arg6 = tgetl(sp_reg + 20);
+                case 5: arg5 = tgetl(sp_reg + 16);
+                default:
+                    break;
                 }
-                if ((unsigned int)ret >= (unsigned int)(-1133)) {
-                    env->gpr[7] = 1; /* error flag */
-                    ret = -ret;
-                    env->gpr[0] = ret;
-                    env->gpr[2] = ret;
-                } else {
-                    env->gpr[7] = 0; /* error flag */
-                    env->gpr[2] = ret;
-                }
+                ret = do_syscall(env, env->gpr[2][env->current_tc],
+                                 env->gpr[4][env->current_tc],
+                                 env->gpr[5][env->current_tc],
+                                 env->gpr[6][env->current_tc],
+                                 env->gpr[7][env->current_tc],
+                                 arg5, arg6/*, arg7, arg8*/);
             }
+            if ((unsigned int)ret >= (unsigned int)(-1133)) {
+                env->gpr[7][env->current_tc] = 1; /* error flag */
+                ret = -ret;
+            } else {
+                env->gpr[7][env->current_tc] = 0; /* error flag */
+            }
+            env->gpr[2][env->current_tc] = ret;
             break;
         case EXCP_TLBL:
         case EXCP_TLBS:
@@ -1380,7 +1537,7 @@
             break;
         default:
             //        error:
-            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
                     trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
             abort();
@@ -1395,19 +1552,19 @@
 {
     int trapnr, ret;
     target_siginfo_t info;
-    
+
     while (1) {
         trapnr = cpu_sh4_exec (env);
-        
+
         switch (trapnr) {
         case 0x160:
-            ret = do_syscall(env, 
-                             env->gregs[3], 
-                             env->gregs[4], 
-                             env->gregs[5], 
-                             env->gregs[6], 
-                             env->gregs[7], 
-                             env->gregs[0], 
+            ret = do_syscall(env,
+                             env->gregs[3],
+                             env->gregs[4],
+                             env->gregs[5],
+                             env->gregs[6],
+                             env->gregs[7],
+                             env->gregs[0],
                              0);
             env->gregs[0] = ret;
             env->pc += 2;
@@ -1444,7 +1601,7 @@
     unsigned int n;
     target_siginfo_t info;
     TaskState *ts = env->opaque;
-    
+
     for(;;) {
         trapnr = cpu_m68k_exec(env);
         switch(trapnr) {
@@ -1460,9 +1617,9 @@
                 }
             }
             break;
-        case EXCP_HALTED:
+        case EXCP_HALT_INSN:
             /* Semihosing syscall.  */
-            env->pc += 2;
+            env->pc += 4;
             do_m68k_semihosting(env, env->dregs[0]);
             break;
         case EXCP_LINEA:
@@ -1480,8 +1637,8 @@
                 ts->sim_syscalls = 0;
                 n = env->dregs[0];
                 env->pc += 2;
-                env->dregs[0] = do_syscall(env, 
-                                          n, 
+                env->dregs[0] = do_syscall(env,
+                                          n,
                                           env->dregs[1],
                                           env->dregs[2],
                                           env->dregs[3],
@@ -1518,7 +1675,7 @@
             }
             break;
         default:
-            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", 
+            fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
                     trapnr);
             cpu_dump_state(env, stderr, fprintf, 0);
             abort();
@@ -1528,16 +1685,108 @@
 }
 #endif /* TARGET_M68K */
 
+#ifdef TARGET_ALPHA
+void cpu_loop (CPUState *env)
+{
+    int trapnr;
+    target_siginfo_t info;
+
+    while (1) {
+        trapnr = cpu_alpha_exec (env);
+
+        switch (trapnr) {
+        case EXCP_RESET:
+            fprintf(stderr, "Reset requested. Exit\n");
+            exit(1);
+            break;
+        case EXCP_MCHK:
+            fprintf(stderr, "Machine check exception. Exit\n");
+            exit(1);
+            break;
+        case EXCP_ARITH:
+            fprintf(stderr, "Arithmetic trap.\n");
+            exit(1);
+            break;
+        case EXCP_HW_INTERRUPT:
+            fprintf(stderr, "External interrupt. Exit\n");
+            exit(1);
+            break;
+        case EXCP_DFAULT:
+            fprintf(stderr, "MMU data fault\n");
+            exit(1);
+            break;
+        case EXCP_DTB_MISS_PAL:
+            fprintf(stderr, "MMU data TLB miss in PALcode\n");
+            exit(1);
+            break;
+        case EXCP_ITB_MISS:
+            fprintf(stderr, "MMU instruction TLB miss\n");
+            exit(1);
+            break;
+        case EXCP_ITB_ACV:
+            fprintf(stderr, "MMU instruction access violation\n");
+            exit(1);
+            break;
+        case EXCP_DTB_MISS_NATIVE:
+            fprintf(stderr, "MMU data TLB miss\n");
+            exit(1);
+            break;
+        case EXCP_UNALIGN:
+            fprintf(stderr, "Unaligned access\n");
+            exit(1);
+            break;
+        case EXCP_OPCDEC:
+            fprintf(stderr, "Invalid instruction\n");
+            exit(1);
+            break;
+        case EXCP_FEN:
+            fprintf(stderr, "Floating-point not allowed\n");
+            exit(1);
+            break;
+        case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
+            fprintf(stderr, "Call to PALcode\n");
+            call_pal(env, (trapnr >> 6) | 0x80);
+            break;
+        case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1):
+            fprintf(stderr, "Privileged call to PALcode\n");
+            exit(1);
+            break;
+        case EXCP_DEBUG:
+            {
+                int sig;
+
+                sig = gdb_handlesig (env, TARGET_SIGTRAP);
+                if (sig)
+                  {
+                    info.si_signo = sig;
+                    info.si_errno = 0;
+                    info.si_code = TARGET_TRAP_BRKPT;
+                    queue_signal(info.si_signo, &info);
+                  }
+            }
+            break;
+        default:
+            printf ("Unhandled trap: 0x%x\n", trapnr);
+            cpu_dump_state(env, stderr, fprintf, 0);
+            exit (1);
+        }
+        process_pending_signals (env);
+    }
+}
+#endif /* TARGET_ALPHA */
+
 void usage(void)
 {
     printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
-           "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n"
+           "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] [-cpu model] program [arguments...]\n"
            "Linux CPU emulator (compiled for %s emulation)\n"
            "\n"
-           "-h           print this help\n"
-           "-g port      wait gdb connection to port\n"
-           "-L path      set the elf interpreter prefix (default=%s)\n"
-           "-s size      set the stack size in bytes (default=%ld)\n"
+           "-h                print this help\n"
+           "-g port           wait gdb connection to port\n"
+           "-L path           set the elf interpreter prefix (default=%s)\n"
+           "-s size           set the stack size in bytes (default=%ld)\n"
+           "-cpu model        select CPU (-cpu ? for list)\n"
+           "-drop-ld-preload  drop LD_PRELOAD for target process\n"
            "\n"
            "debug options:\n"
 #ifdef USE_CODE_COPY
@@ -1546,7 +1795,7 @@
            "-d options   activate log (logfile=%s)\n"
            "-p pagesize  set the host page size to 'pagesize'\n",
            TARGET_ARCH,
-           interp_prefix, 
+           interp_prefix,
            x86_stack_size,
            DEBUG_LOGFILE);
     _exit(1);
@@ -1561,6 +1810,7 @@
 int main(int argc, char **argv)
 {
     const char *filename;
+    const char *cpu_model;
     struct target_pt_regs regs1, *regs = &regs1;
     struct image_info info1, *info = &info1;
     TaskState ts1, *ts = &ts1;
@@ -1568,13 +1818,16 @@
     int optind;
     const char *r;
     int gdbstub_port = 0;
-    
+    int drop_ld_preload = 0, environ_count = 0;
+    char **target_environ, **wrk, **dst;
+
     if (argc <= 1)
         usage();
 
     /* init debug */
     cpu_set_log_filename(DEBUG_LOGFILE);
 
+    cpu_model = NULL;
     optind = 1;
     for(;;) {
         if (optind >= argc)
@@ -1592,7 +1845,7 @@
 
 	    if (optind >= argc)
 		break;
-            
+
 	    r = argv[optind++];
             mask = cpu_str_to_log_mask(r);
             if (!mask) {
@@ -1625,11 +1878,27 @@
             gdbstub_port = atoi(argv[optind++]);
 	} else if (!strcmp(r, "r")) {
 	    qemu_uname_release = argv[optind++];
-        } else 
+        } else if (!strcmp(r, "cpu")) {
+            cpu_model = argv[optind++];
+            if (strcmp(cpu_model, "?") == 0) {
+#if defined(TARGET_PPC)
+                ppc_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_ARM)
+                arm_cpu_list();
+#elif defined(TARGET_MIPS)
+                mips_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_SPARC)
+                sparc_cpu_list(stdout, &fprintf);
+#endif
+                _exit(1);
+            }
+        } else if (!strcmp(r, "drop-ld-preload")) {
+            drop_ld_preload = 1;
+        } else
 #ifdef USE_CODE_COPY
         if (!strcmp(r, "no-code-copy")) {
             code_copy_enabled = 0;
-        } else 
+        } else
 #endif
         {
             usage();
@@ -1652,15 +1921,35 @@
        qemu_host_page_size */
     env = cpu_init();
     global_env = env;
-    
-    if (loader_exec(filename, argv+optind, environ, regs, info) != 0) {
-	printf("Error loading %s\n", filename);
-	_exit(1);
+
+    wrk = environ;
+    while (*(wrk++))
+        environ_count++;
+
+    target_environ = malloc((environ_count + 1) * sizeof(char *));
+    if (!target_environ)
+        abort();
+    for (wrk = environ, dst = target_environ; *wrk; wrk++) {
+        if (drop_ld_preload && !strncmp(*wrk, "LD_PRELOAD=", 11))
+            continue;
+        *(dst++) = strdup(*wrk);
     }
-    
+    *dst = NULL; /* NULL terminate target_environ */
+
+    if (loader_exec(filename, argv+optind, target_environ, regs, info) != 0) {
+        printf("Error loading %s\n", filename);
+        _exit(1);
+    }
+
+    for (wrk = target_environ; *wrk; wrk++) {
+        free(*wrk);
+    }
+
+    free(target_environ);
+
     if (loglevel) {
         page_dump(logfile);
-    
+
         fprintf(logfile, "start_brk   0x%08lx\n" , info->start_brk);
         fprintf(logfile, "end_code    0x%08lx\n" , info->end_code);
         fprintf(logfile, "start_code  0x%08lx\n" , info->start_code);
@@ -1681,7 +1970,7 @@
     ts->used = 1;
     ts->info = info;
     env->user_mode_only = 1;
-    
+
 #if defined(TARGET_I386)
     cpu_x86_set_cpl(env, 3);
 
@@ -1694,8 +1983,19 @@
 
     /* flags setup : we activate the IRQs by default as in user mode */
     env->eflags |= IF_MASK;
-    
+
     /* linux register setup */
+#if defined(TARGET_X86_64)
+    env->regs[R_EAX] = regs->rax;
+    env->regs[R_EBX] = regs->rbx;
+    env->regs[R_ECX] = regs->rcx;
+    env->regs[R_EDX] = regs->rdx;
+    env->regs[R_ESI] = regs->rsi;
+    env->regs[R_EDI] = regs->rdi;
+    env->regs[R_EBP] = regs->rbp;
+    env->regs[R_ESP] = regs->rsp;
+    env->eip = regs->rip;
+#else
     env->regs[R_EAX] = regs->eax;
     env->regs[R_EBX] = regs->ebx;
     env->regs[R_ECX] = regs->ecx;
@@ -1705,6 +2005,7 @@
     env->regs[R_EBP] = regs->ebp;
     env->regs[R_ESP] = regs->esp;
     env->eip = regs->eip;
+#endif
 
     /* linux interrupt setup */
     env->idt.base = h2g(idt_table);
@@ -1735,10 +2036,10 @@
     env->gdt.base = h2g(gdt_table);
     env->gdt.limit = sizeof(gdt_table) - 1;
     write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
-             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 
+             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
              (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
     write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
-             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK | 
+             DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
              (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
     cpu_x86_load_seg(env, R_CS, __USER_CS);
     cpu_x86_load_seg(env, R_DS, __USER_DS);
@@ -1747,22 +2048,36 @@
     cpu_x86_load_seg(env, R_FS, __USER_DS);
     cpu_x86_load_seg(env, R_GS, __USER_DS);
 
+    /* This hack makes Wine work... */
+    env->segs[R_FS].selector = 0;
 #elif defined(TARGET_ARM)
     {
         int i;
-        cpu_arm_set_model(env, ARM_CPUID_ARM1026);
+        if (cpu_model == NULL)
+            cpu_model = "arm926";
+        cpu_arm_set_model(env, cpu_model);
         cpsr_write(env, regs->uregs[16], 0xffffffff);
         for(i = 0; i < 16; i++) {
             env->regs[i] = regs->uregs[i];
         }
-        ts->stack_base = info->start_stack;
-        ts->heap_base = info->brk;
-        /* This will be filled in on the first SYS_HEAPINFO call.  */
-        ts->heap_limit = 0;
     }
 #elif defined(TARGET_SPARC)
     {
         int i;
+        const sparc_def_t *def;
+#ifdef TARGET_SPARC64
+        if (cpu_model == NULL)
+            cpu_model = "TI UltraSparc II";
+#else
+        if (cpu_model == NULL)
+            cpu_model = "Fujitsu MB86904";
+#endif
+        sparc_find_by_name(cpu_model, &def);
+        if (def == NULL) {
+            fprintf(stderr, "Unable to find Sparc CPU definition\n");
+            exit(1);
+        }
+        cpu_sparc_register(env, def);
 	env->pc = regs->pc;
 	env->npc = regs->npc;
         env->y = regs->y;
@@ -1777,15 +2092,9 @@
         int i;
 
         /* Choose and initialise CPU */
-        /* XXX: CPU model (or PVR) should be provided on command line */
-        //        ppc_find_by_name("750gx", &def);
-        //        ppc_find_by_name("750fx", &def);
-        //        ppc_find_by_name("750p", &def);
-        ppc_find_by_name("750", &def);
-        //        ppc_find_by_name("G3", &def);
-        //        ppc_find_by_name("604r", &def);
-        //        ppc_find_by_name("604e", &def);
-        //        ppc_find_by_name("604", &def);
+        if (cpu_model == NULL)
+            cpu_model = "750";
+        ppc_find_by_name(cpu_model, &def);
         if (def == NULL) {
             cpu_abort(env,
                       "Unable to find PowerPC CPU definition\n");
@@ -1796,6 +2105,9 @@
             if (i != 12 && i != 6 && i != 13)
                 env->msr[i] = (regs->msr >> i) & 1;
         }
+#if defined(TARGET_PPC64)
+        msr_sf = 1;
+#endif
         env->nip = regs->nip;
         for(i = 0; i < 32; i++) {
             env->gpr[i] = regs->gpr[i];
@@ -1803,13 +2115,12 @@
     }
 #elif defined(TARGET_M68K)
     {
-        m68k_def_t *def;
-        def = m68k_find_by_name("cfv4e");
-        if (def == NULL) {
+        if (cpu_model == NULL)
+            cpu_model = "any";
+        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;
@@ -1832,15 +2143,25 @@
     }
 #elif defined(TARGET_MIPS)
     {
+        mips_def_t *def;
         int i;
 
-        for(i = 0; i < 32; i++) {
-            env->gpr[i] = regs->regs[i];
-        }
-        env->PC = regs->cp0_epc;
-#ifdef MIPS_USES_FPU
-        env->CP0_Status |= (1 << CP0St_CU1);
+        /* Choose and initialise CPU */
+        if (cpu_model == NULL)
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+            cpu_model = "20Kc";
+#else
+            cpu_model = "24Kf";
 #endif
+        mips_find_by_name(cpu_model, &def);
+        if (def == NULL)
+            cpu_abort(env, "Unable to find MIPS CPU definition\n");
+        cpu_mips_register(env, def);
+
+        for(i = 0; i < 32; i++) {
+            env->gpr[i][env->current_tc] = regs->regs[i];
+        }
+        env->PC[env->current_tc] = regs->cp0_epc;
     }
 #elif defined(TARGET_SH4)
     {
@@ -1851,10 +2172,29 @@
         }
         env->pc = regs->pc;
     }
+#elif defined(TARGET_ALPHA)
+    {
+        int i;
+
+        for(i = 0; i < 28; i++) {
+            env->ir[i] = ((target_ulong *)regs)[i];
+        }
+        env->ipr[IPR_USP] = regs->usp;
+        env->ir[30] = regs->usp;
+        env->pc = regs->pc;
+        env->unique = regs->unique;
+    }
 #else
 #error unsupported target CPU
 #endif
 
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
+    ts->stack_base = info->start_stack;
+    ts->heap_base = info->brk;
+    /* This will be filled in on the first SYS_HEAPINFO call.  */
+    ts->heap_limit = 0;
+#endif
+
     if (gdbstub_port) {
         gdbserver_start (gdbstub_port);
         gdb_handlesig(env, 0);
diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h
index 4b3c7d6..a789348 100644
--- a/linux-user/mips/syscall.h
+++ b/linux-user/mips/syscall.h
@@ -3,10 +3,8 @@
    stack during a system call. */
 
 struct target_pt_regs {
-#if 1
 	/* Pad bytes for argument save space on the stack. */
 	target_ulong pad0[6];
-#endif
 
 	/* Saved main processor registers. */
 	target_ulong regs[32];
@@ -20,4 +18,207 @@
 	target_ulong cp0_epc;
 };
 
+/* Target errno definitions taken from asm-mips/errno.h */
+#undef TARGET_ENOMSG
+#define TARGET_ENOMSG          35      /* Identifier removed */
+#undef TARGET_EIDRM
+#define TARGET_EIDRM           36      /* Identifier removed */
+#undef TARGET_ECHRNG
+#define TARGET_ECHRNG          37      /* Channel number out of range */
+#undef TARGET_EL2NSYNC
+#define TARGET_EL2NSYNC        38      /* Level 2 not synchronized */
+#undef TARGET_EL3HLT
+#define TARGET_EL3HLT          39      /* Level 3 halted */
+#undef TARGET_EL3RST
+#define TARGET_EL3RST          40      /* Level 3 reset */
+#undef TARGET_ELNRNG
+#define TARGET_ELNRNG          41      /* Link number out of range */
+#undef TARGET_EUNATCH
+#define TARGET_EUNATCH         42      /* Protocol driver not attached */
+#undef TARGET_ENOCSI
+#define TARGET_ENOCSI          43      /* No CSI structure available */
+#undef TARGET_EL2HLT
+#define TARGET_EL2HLT          44      /* Level 2 halted */
+#undef TARGET_EDEADLK
+#define TARGET_EDEADLK         45      /* Resource deadlock would occur */
+#undef TARGET_ENOLCK
+#define TARGET_ENOLCK          46      /* No record locks available */
+#undef TARGET_EBADE
+#define TARGET_EBADE           50      /* Invalid exchange */
+#undef TARGET_EBADR
+#define TARGET_EBADR           51      /* Invalid request descriptor */
+#undef TARGET_EXFULL
+#define TARGET_EXFULL          52      /* TARGET_Exchange full */
+#undef TARGET_ENOANO
+#define TARGET_ENOANO          53      /* No anode */
+#undef TARGET_EBADRQC
+#define TARGET_EBADRQC         54      /* Invalid request code */
+#undef TARGET_EBADSLT
+#define TARGET_EBADSLT         55      /* Invalid slot */
+#undef TARGET_EDEADLOCK
+#define TARGET_EDEADLOCK       56      /* File locking deadlock error */
+#undef TARGET_EBFONT
+#define TARGET_EBFONT          59      /* Bad font file format */
+#undef TARGET_ENOSTR
+#define TARGET_ENOSTR          60      /* Device not a stream */
+#undef TARGET_ENODATA
+#define TARGET_ENODATA         61      /* No data available */
+#undef TARGET_ETIME
+#define TARGET_ETIME           62      /* Timer expired */
+#undef TARGET_ENOSR
+#define TARGET_ENOSR           63      /* Out of streams resources */
+#undef TARGET_ENONET
+#define TARGET_ENONET          64      /* Machine is not on the network */
+#undef TARGET_ENOPKG
+#define TARGET_ENOPKG          65      /* Package not installed */
+#undef TARGET_EREMOTE
+#define TARGET_EREMOTE         66      /* Object is remote */
+#undef TARGET_ENOLINK
+#define TARGET_ENOLINK         67      /* Link has been severed */
+#undef TARGET_EADV
+#define TARGET_EADV            68      /* Advertise error */
+#undef TARGET_ESRMNT
+#define TARGET_ESRMNT          69      /* Srmount error */
+#undef TARGET_ECOMM
+#define TARGET_ECOMM           70      /* Communication error on send */
+#undef TARGET_EPROTO
+#define TARGET_EPROTO          71      /* Protocol error */
+#undef TARGET_EDOTDOT
+#define TARGET_EDOTDOT         73      /* RFS specific error */
+#undef TARGET_EMULTIHOP
+#define TARGET_EMULTIHOP       74      /* Multihop attempted */
+#undef TARGET_EBADMSG
+#define TARGET_EBADMSG         77      /* Not a data message */
+#undef TARGET_ENAMETOOLONG
+#define TARGET_ENAMETOOLONG    78      /* File name too long */
+#undef TARGET_EOVERFLOW
+#define TARGET_EOVERFLOW       79      /* Value too large for defined data type */
+#undef TARGET_ENOTUNIQ
+#define TARGET_ENOTUNIQ        80      /* Name not unique on network */
+#undef TARGET_EBADFD
+#define TARGET_EBADFD          81      /* File descriptor in bad state */
+#undef TARGET_EREMCHG
+#define TARGET_EREMCHG         82      /* Remote address changed */
+#undef TARGET_ELIBACC
+#define TARGET_ELIBACC         83      /* Can not access a needed shared library */
+#undef TARGET_ELIBBAD
+#define TARGET_ELIBBAD         84      /* Accessing a corrupted shared library */
+#undef TARGET_ELIBSCN
+#define TARGET_ELIBSCN         85      /* .lib section in a.out corrupted */
+#undef TARGET_ELIBMAX
+#define TARGET_ELIBMAX         86      /* Attempting to link in too many shared libraries */
+#undef TARGET_ELIBEXEC
+#define TARGET_ELIBEXEC        87      /* Cannot exec a shared library directly */
+#undef TARGET_EILSEQ
+#define TARGET_EILSEQ          88      /* Illegal byte sequence */
+#undef TARGET_ENOSYS
+#define TARGET_ENOSYS          89      /* Function not implemented */
+#undef TARGET_ELOOP
+#define TARGET_ELOOP           90      /* Too many symbolic links encountered */
+#undef TARGET_ERESTART
+#define TARGET_ERESTART        91      /* Interrupted system call should be restarted */
+#undef TARGET_ESTRPIPE
+#define TARGET_ESTRPIPE        92      /* Streams pipe error */
+#undef TARGET_ENOTEMPTY
+#define TARGET_ENOTEMPTY       93      /* Directory not empty */
+#undef TARGET_EUSERS
+#define TARGET_EUSERS          94      /* Too many users */
+#undef TARGET_ENOTSOCK
+#define TARGET_ENOTSOCK        95      /* Socket operation on non-socket */
+#undef TARGET_EDESTADDRREQ
+#define TARGET_EDESTADDRREQ    96      /* Destination address required */
+#undef TARGET_EMSGSIZE
+#define TARGET_EMSGSIZE        97      /* Message too long */
+#undef TARGET_EPROTOTYPE
+#define TARGET_EPROTOTYPE      98      /* Protocol wrong type for socket */
+#undef TARGET_ENOPROTOOPT
+#define TARGET_ENOPROTOOPT     99      /* Protocol not available */
+#undef TARGET_EPROTONOSUPPORT
+#define TARGET_EPROTONOSUPPORT 120     /* Protocol not supported */
+#undef TARGET_ESOCKTNOSUPPORT
+#define TARGET_ESOCKTNOSUPPORT 121     /* Socket type not supported */
+#undef TARGET_EOPNOTSUPP
+#define TARGET_EOPNOTSUPP      122     /* Operation not supported on transport endpoint */
+#undef TARGET_EPFNOSUPPORT
+#define TARGET_EPFNOSUPPORT    123     /* Protocol family not supported */
+#undef TARGET_EAFNOSUPPORT
+#define TARGET_EAFNOSUPPORT    124     /* Address family not supported by protocol */
+#undef TARGET_EADDRINUSE
+#define TARGET_EADDRINUSE      125     /* Address already in use */
+#undef TARGET_EADDRNOTAVAIL
+#define TARGET_EADDRNOTAVAIL   126     /* Cannot assign requested address */
+#undef TARGET_ENETDOWN
+#define TARGET_ENETDOWN        127     /* Network is down */
+#undef TARGET_ENETUNREACH
+#define TARGET_ENETUNREACH     128     /* Network is unreachable */
+#undef TARGET_ENETRESET
+#define TARGET_ENETRESET       129     /* Network dropped connection because of reset */
+#undef TARGET_ECONNABORTED
+#define TARGET_ECONNABORTED    130     /* Software caused connection abort */
+#undef TARGET_ECONNRESET
+#define TARGET_ECONNRESET      131     /* Connection reset by peer */
+#undef TARGET_ENOBUFS
+#define TARGET_ENOBUFS         132     /* No buffer space available */
+#undef TARGET_EISCONN
+#define TARGET_EISCONN         133     /* Transport endpoint is already connected */
+#undef TARGET_ENOTCONN
+#define TARGET_ENOTCONN        134     /* Transport endpoint is not connected */
+#undef TARGET_EUCLEAN
+#define TARGET_EUCLEAN         135     /* Structure needs cleaning */
+#undef TARGET_ENOTNAM
+#define TARGET_ENOTNAM         137     /* Not a XENIX named type file */
+#undef TARGET_ENAVAIL
+#define TARGET_ENAVAIL         138     /* No XENIX semaphores available */
+#undef TARGET_EISNAM
+#define TARGET_EISNAM          139     /* Is a named type file */
+#undef TARGET_EREMOTEIO
+#define TARGET_EREMOTEIO       140     /* Remote I/O error */
+#undef TARGET_EINIT
+#define TARGET_EINIT           141     /* Reserved */
+#undef TARGET_EREMDEV
+#define TARGET_EREMDEV         142     /* TARGET_Error 142 */
+#undef TARGET_ESHUTDOWN
+#define TARGET_ESHUTDOWN       143     /* Cannot send after transport endpoint shutdown */
+#undef TARGET_ETOOMANYREFS
+#define TARGET_ETOOMANYREFS    144     /* Too many references: cannot splice */
+#undef TARGET_ETIMEDOUT
+#define TARGET_ETIMEDOUT       145     /* Connection timed out */
+#undef TARGET_ECONNREFUSED
+#define TARGET_ECONNREFUSED    146     /* Connection refused */
+#undef TARGET_EHOSTDOWN
+#define TARGET_EHOSTDOWN       147     /* Host is down */
+#undef TARGET_EHOSTUNREACH
+#define TARGET_EHOSTUNREACH    148     /* No route to host */
+#undef TARGET_EALREADY
+#define TARGET_EALREADY        149     /* Operation already in progress */
+#undef TARGET_EINPROGRESS
+#define TARGET_EINPROGRESS     150     /* Operation now in progress */
+#undef TARGET_ESTALE
+#define TARGET_ESTALE          151     /* Stale NFS file handle */
+#undef TARGET_ECANCELED
+#define TARGET_ECANCELED       158     /* AIO operation canceled */
+/*
+ * These error are Linux extensions.
+ */
+#undef TARGET_ENOMEDIUM
+#define TARGET_ENOMEDIUM       159     /* No medium found */
+#undef TARGET_EMEDIUMTYPE
+#define TARGET_EMEDIUMTYPE     160     /* Wrong medium type */
+#undef TARGET_ENOKEY
+#define TARGET_ENOKEY          161     /* Required key not available */
+#undef TARGET_EKEYEXPIRED
+#define TARGET_EKEYEXPIRED     162     /* Key has expired */
+#undef TARGET_EKEYREVOKED
+#define TARGET_EKEYREVOKED     163     /* Key has been revoked */
+#undef TARGET_EKEYREJECTED
+#define TARGET_EKEYREJECTED    164     /* Key was rejected by service */
+
+/* for robust mutexes */
+#undef TARGET_EOWNERDEAD
+#define TARGET_EOWNERDEAD      165     /* Owner died */
+#undef TARGET_ENOTRECOVERABLE
+#define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
+
+
+
 #define UNAME_MACHINE "mips"
diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h
index 3593e65..f900ae2 100644
--- a/linux-user/mips/syscall_nr.h
+++ b/linux-user/mips/syscall_nr.h
@@ -2,45 +2,45 @@
  * Linux o32 style syscalls are in the range from 4000 to 4999.
  */
 #define TARGET_NR_Linux			4000
-#define TARGET_NR_syscall			(TARGET_NR_Linux +   0)
+#define TARGET_NR_syscall		(TARGET_NR_Linux +   0)
 #define TARGET_NR_exit			(TARGET_NR_Linux +   1)
 #define TARGET_NR_fork			(TARGET_NR_Linux +   2)
 #define TARGET_NR_read			(TARGET_NR_Linux +   3)
 #define TARGET_NR_write			(TARGET_NR_Linux +   4)
 #define TARGET_NR_open			(TARGET_NR_Linux +   5)
 #define TARGET_NR_close			(TARGET_NR_Linux +   6)
-#define TARGET_NR_waitpid			(TARGET_NR_Linux +   7)
+#define TARGET_NR_waitpid		(TARGET_NR_Linux +   7)
 #define TARGET_NR_creat			(TARGET_NR_Linux +   8)
 #define TARGET_NR_link			(TARGET_NR_Linux +   9)
-#define TARGET_NR_unlink			(TARGET_NR_Linux +  10)
-#define TARGET_NR_execve			(TARGET_NR_Linux +  11)
+#define TARGET_NR_unlink		(TARGET_NR_Linux +  10)
+#define TARGET_NR_execve		(TARGET_NR_Linux +  11)
 #define TARGET_NR_chdir			(TARGET_NR_Linux +  12)
 #define TARGET_NR_time			(TARGET_NR_Linux +  13)
 #define TARGET_NR_mknod			(TARGET_NR_Linux +  14)
 #define TARGET_NR_chmod			(TARGET_NR_Linux +  15)
-#define TARGET_NR_lchown32			(TARGET_NR_Linux +  16)
+#define TARGET_NR_lchown32		(TARGET_NR_Linux +  16)
 #define TARGET_NR_break			(TARGET_NR_Linux +  17)
-#define TARGET_NR_unused18			(TARGET_NR_Linux +  18)
+#define TARGET_NR_unused18		(TARGET_NR_Linux +  18)
 #define TARGET_NR_lseek			(TARGET_NR_Linux +  19)
-#define TARGET_NR_getpid			(TARGET_NR_Linux +  20)
+#define TARGET_NR_getpid		(TARGET_NR_Linux +  20)
 #define TARGET_NR_mount			(TARGET_NR_Linux +  21)
-#define TARGET_NR_umount			(TARGET_NR_Linux +  22)
-#define TARGET_NR_setuid32			(TARGET_NR_Linux +  23)
-#define TARGET_NR_getuid32			(TARGET_NR_Linux +  24)
+#define TARGET_NR_umount		(TARGET_NR_Linux +  22)
+#define TARGET_NR_setuid32		(TARGET_NR_Linux +  23)
+#define TARGET_NR_getuid32		(TARGET_NR_Linux +  24)
 #define TARGET_NR_stime			(TARGET_NR_Linux +  25)
-#define TARGET_NR_ptrace			(TARGET_NR_Linux +  26)
+#define TARGET_NR_ptrace		(TARGET_NR_Linux +  26)
 #define TARGET_NR_alarm			(TARGET_NR_Linux +  27)
-#define TARGET_NR_unused28			(TARGET_NR_Linux +  28)
+#define TARGET_NR_unused28		(TARGET_NR_Linux +  28)
 #define TARGET_NR_pause			(TARGET_NR_Linux +  29)
 #define TARGET_NR_utime			(TARGET_NR_Linux +  30)
 #define TARGET_NR_stty			(TARGET_NR_Linux +  31)
 #define TARGET_NR_gtty			(TARGET_NR_Linux +  32)
-#define TARGET_NR_access			(TARGET_NR_Linux +  33)
+#define TARGET_NR_access		(TARGET_NR_Linux +  33)
 #define TARGET_NR_nice			(TARGET_NR_Linux +  34)
 #define TARGET_NR_ftime			(TARGET_NR_Linux +  35)
 #define TARGET_NR_sync			(TARGET_NR_Linux +  36)
 #define TARGET_NR_kill			(TARGET_NR_Linux +  37)
-#define TARGET_NR_rename			(TARGET_NR_Linux +  38)
+#define TARGET_NR_rename		(TARGET_NR_Linux +  38)
 #define TARGET_NR_mkdir			(TARGET_NR_Linux +  39)
 #define TARGET_NR_rmdir			(TARGET_NR_Linux +  40)
 #define TARGET_NR_dup			(TARGET_NR_Linux +  41)
@@ -48,241 +48,278 @@
 #define TARGET_NR_times			(TARGET_NR_Linux +  43)
 #define TARGET_NR_prof			(TARGET_NR_Linux +  44)
 #define TARGET_NR_brk			(TARGET_NR_Linux +  45)
-#define TARGET_NR_setgid32			(TARGET_NR_Linux +  46)
-#define TARGET_NR_getgid32			(TARGET_NR_Linux +  47)
-#define TARGET_NR_signal			(TARGET_NR_Linux +  48)
-#define TARGET_NR_geteuid32			(TARGET_NR_Linux +  49)
-#define TARGET_NR_getegid32			(TARGET_NR_Linux +  50)
+#define TARGET_NR_setgid32		(TARGET_NR_Linux +  46)
+#define TARGET_NR_getgid32		(TARGET_NR_Linux +  47)
+#define TARGET_NR_signal		(TARGET_NR_Linux +  48)
+#define TARGET_NR_geteuid32		(TARGET_NR_Linux +  49)
+#define TARGET_NR_getegid32		(TARGET_NR_Linux +  50)
 #define TARGET_NR_acct			(TARGET_NR_Linux +  51)
-#define TARGET_NR_umount2			(TARGET_NR_Linux +  52)
+#define TARGET_NR_umount2		(TARGET_NR_Linux +  52)
 #define TARGET_NR_lock			(TARGET_NR_Linux +  53)
 #define TARGET_NR_ioctl			(TARGET_NR_Linux +  54)
 #define TARGET_NR_fcntl			(TARGET_NR_Linux +  55)
 #define TARGET_NR_mpx			(TARGET_NR_Linux +  56)
-#define TARGET_NR_setpgid			(TARGET_NR_Linux +  57)
-#define TARGET_NR_ulimit			(TARGET_NR_Linux +  58)
-#define TARGET_NR_unused59			(TARGET_NR_Linux +  59)
+#define TARGET_NR_setpgid		(TARGET_NR_Linux +  57)
+#define TARGET_NR_ulimit		(TARGET_NR_Linux +  58)
+#define TARGET_NR_unused59		(TARGET_NR_Linux +  59)
 #define TARGET_NR_umask			(TARGET_NR_Linux +  60)
-#define TARGET_NR_chroot			(TARGET_NR_Linux +  61)
+#define TARGET_NR_chroot		(TARGET_NR_Linux +  61)
 #define TARGET_NR_ustat			(TARGET_NR_Linux +  62)
 #define TARGET_NR_dup2			(TARGET_NR_Linux +  63)
-#define TARGET_NR_getppid			(TARGET_NR_Linux +  64)
-#define TARGET_NR_getpgrp			(TARGET_NR_Linux +  65)
-#define TARGET_NR_setsid			(TARGET_NR_Linux +  66)
-#define TARGET_NR_sigaction			(TARGET_NR_Linux +  67)
-#define TARGET_NR_sgetmask			(TARGET_NR_Linux +  68)
-#define TARGET_NR_ssetmask			(TARGET_NR_Linux +  69)
-#define TARGET_NR_setreuid32			(TARGET_NR_Linux +  70)
-#define TARGET_NR_setregid32			(TARGET_NR_Linux +  71)
-#define TARGET_NR_sigsuspend			(TARGET_NR_Linux +  72)
-#define TARGET_NR_sigpending			(TARGET_NR_Linux +  73)
+#define TARGET_NR_getppid		(TARGET_NR_Linux +  64)
+#define TARGET_NR_getpgrp		(TARGET_NR_Linux +  65)
+#define TARGET_NR_setsid		(TARGET_NR_Linux +  66)
+#define TARGET_NR_sigaction		(TARGET_NR_Linux +  67)
+#define TARGET_NR_sgetmask		(TARGET_NR_Linux +  68)
+#define TARGET_NR_ssetmask		(TARGET_NR_Linux +  69)
+#define TARGET_NR_setreuid32		(TARGET_NR_Linux +  70)
+#define TARGET_NR_setregid32		(TARGET_NR_Linux +  71)
+#define TARGET_NR_sigsuspend		(TARGET_NR_Linux +  72)
+#define TARGET_NR_sigpending		(TARGET_NR_Linux +  73)
 #define TARGET_NR_sethostname		(TARGET_NR_Linux +  74)
-#define TARGET_NR_setrlimit			(TARGET_NR_Linux +  75)
-#define TARGET_NR_getrlimit			(TARGET_NR_Linux +  76)
-#define TARGET_NR_getrusage			(TARGET_NR_Linux +  77)
+#define TARGET_NR_setrlimit		(TARGET_NR_Linux +  75)
+#define TARGET_NR_getrlimit		(TARGET_NR_Linux +  76)
+#define TARGET_NR_getrusage		(TARGET_NR_Linux +  77)
 #define TARGET_NR_gettimeofday		(TARGET_NR_Linux +  78)
 #define TARGET_NR_settimeofday		(TARGET_NR_Linux +  79)
-#define TARGET_NR_getgroups32			(TARGET_NR_Linux +  80)
-#define TARGET_NR_setgroups32			(TARGET_NR_Linux +  81)
-#define TARGET_NR_reserved82			(TARGET_NR_Linux +  82)
-#define TARGET_NR_symlink			(TARGET_NR_Linux +  83)
-#define TARGET_NR_unused84			(TARGET_NR_Linux +  84)
-#define TARGET_NR_readlink			(TARGET_NR_Linux +  85)
-#define TARGET_NR_uselib			(TARGET_NR_Linux +  86)
-#define TARGET_NR_swapon			(TARGET_NR_Linux +  87)
-#define TARGET_NR_reboot			(TARGET_NR_Linux +  88)
-#define TARGET_NR_readdir			(TARGET_NR_Linux +  89)
+#define TARGET_NR_getgroups32		(TARGET_NR_Linux +  80)
+#define TARGET_NR_setgroups32		(TARGET_NR_Linux +  81)
+#define TARGET_NR_reserved82		(TARGET_NR_Linux +  82)
+#define TARGET_NR_symlink		(TARGET_NR_Linux +  83)
+#define TARGET_NR_unused84		(TARGET_NR_Linux +  84)
+#define TARGET_NR_readlink		(TARGET_NR_Linux +  85)
+#define TARGET_NR_uselib		(TARGET_NR_Linux +  86)
+#define TARGET_NR_swapon		(TARGET_NR_Linux +  87)
+#define TARGET_NR_reboot		(TARGET_NR_Linux +  88)
+#define TARGET_NR_readdir		(TARGET_NR_Linux +  89)
 #define TARGET_NR_mmap			(TARGET_NR_Linux +  90)
-#define TARGET_NR_munmap			(TARGET_NR_Linux +  91)
-#define TARGET_NR_truncate			(TARGET_NR_Linux +  92)
-#define TARGET_NR_ftruncate			(TARGET_NR_Linux +  93)
-#define TARGET_NR_fchmod			(TARGET_NR_Linux +  94)
-#define TARGET_NR_fchown32			(TARGET_NR_Linux +  95)
+#define TARGET_NR_munmap		(TARGET_NR_Linux +  91)
+#define TARGET_NR_truncate		(TARGET_NR_Linux +  92)
+#define TARGET_NR_ftruncate		(TARGET_NR_Linux +  93)
+#define TARGET_NR_fchmod		(TARGET_NR_Linux +  94)
+#define TARGET_NR_fchown32		(TARGET_NR_Linux +  95)
 #define TARGET_NR_getpriority		(TARGET_NR_Linux +  96)
 #define TARGET_NR_setpriority		(TARGET_NR_Linux +  97)
-#define TARGET_NR_profil			(TARGET_NR_Linux +  98)
-#define TARGET_NR_statfs			(TARGET_NR_Linux +  99)
-#define TARGET_NR_fstatfs			(TARGET_NR_Linux + 100)
-#define TARGET_NR_ioperm			(TARGET_NR_Linux + 101)
-#define TARGET_NR_socketcall			(TARGET_NR_Linux + 102)
-#define TARGET_NR_syslog			(TARGET_NR_Linux + 103)
-#define TARGET_NR_setitimer			(TARGET_NR_Linux + 104)
-#define TARGET_NR_getitimer			(TARGET_NR_Linux + 105)
+#define TARGET_NR_profil		(TARGET_NR_Linux +  98)
+#define TARGET_NR_statfs		(TARGET_NR_Linux +  99)
+#define TARGET_NR_fstatfs		(TARGET_NR_Linux + 100)
+#define TARGET_NR_ioperm		(TARGET_NR_Linux + 101)
+#define TARGET_NR_socketcall		(TARGET_NR_Linux + 102)
+#define TARGET_NR_syslog		(TARGET_NR_Linux + 103)
+#define TARGET_NR_setitimer		(TARGET_NR_Linux + 104)
+#define TARGET_NR_getitimer		(TARGET_NR_Linux + 105)
 #define TARGET_NR_stat			(TARGET_NR_Linux + 106)
 #define TARGET_NR_lstat			(TARGET_NR_Linux + 107)
 #define TARGET_NR_fstat			(TARGET_NR_Linux + 108)
-#define TARGET_NR_unused109			(TARGET_NR_Linux + 109)
+#define TARGET_NR_unused109		(TARGET_NR_Linux + 109)
 #define TARGET_NR_iopl			(TARGET_NR_Linux + 110)
-#define TARGET_NR_vhangup			(TARGET_NR_Linux + 111)
+#define TARGET_NR_vhangup		(TARGET_NR_Linux + 111)
 #define TARGET_NR_idle			(TARGET_NR_Linux + 112)
 #define TARGET_NR_vm86			(TARGET_NR_Linux + 113)
 #define TARGET_NR_wait4			(TARGET_NR_Linux + 114)
-#define TARGET_NR_swapoff			(TARGET_NR_Linux + 115)
-#define TARGET_NR_sysinfo			(TARGET_NR_Linux + 116)
+#define TARGET_NR_swapoff		(TARGET_NR_Linux + 115)
+#define TARGET_NR_sysinfo		(TARGET_NR_Linux + 116)
 #define TARGET_NR_ipc			(TARGET_NR_Linux + 117)
 #define TARGET_NR_fsync			(TARGET_NR_Linux + 118)
-#define TARGET_NR_sigreturn			(TARGET_NR_Linux + 119)
+#define TARGET_NR_sigreturn		(TARGET_NR_Linux + 119)
 #define TARGET_NR_clone			(TARGET_NR_Linux + 120)
 #define TARGET_NR_setdomainname		(TARGET_NR_Linux + 121)
 #define TARGET_NR_uname			(TARGET_NR_Linux + 122)
-#define TARGET_NR_modify_ldt			(TARGET_NR_Linux + 123)
-#define TARGET_NR_adjtimex			(TARGET_NR_Linux + 124)
-#define TARGET_NR_mprotect			(TARGET_NR_Linux + 125)
+#define TARGET_NR_modify_ldt		(TARGET_NR_Linux + 123)
+#define TARGET_NR_adjtimex		(TARGET_NR_Linux + 124)
+#define TARGET_NR_mprotect		(TARGET_NR_Linux + 125)
 #define TARGET_NR_sigprocmask		(TARGET_NR_Linux + 126)
 #define TARGET_NR_create_module		(TARGET_NR_Linux + 127)
 #define TARGET_NR_init_module		(TARGET_NR_Linux + 128)
 #define TARGET_NR_delete_module		(TARGET_NR_Linux + 129)
-#define TARGET_NR_get_kernel_syms		(TARGET_NR_Linux + 130)
-#define TARGET_NR_quotactl			(TARGET_NR_Linux + 131)
-#define TARGET_NR_getpgid			(TARGET_NR_Linux + 132)
-#define TARGET_NR_fchdir			(TARGET_NR_Linux + 133)
-#define TARGET_NR_bdflush			(TARGET_NR_Linux + 134)
+#define TARGET_NR_get_kernel_syms	(TARGET_NR_Linux + 130)
+#define TARGET_NR_quotactl		(TARGET_NR_Linux + 131)
+#define TARGET_NR_getpgid		(TARGET_NR_Linux + 132)
+#define TARGET_NR_fchdir		(TARGET_NR_Linux + 133)
+#define TARGET_NR_bdflush		(TARGET_NR_Linux + 134)
 #define TARGET_NR_sysfs			(TARGET_NR_Linux + 135)
 #define TARGET_NR_personality		(TARGET_NR_Linux + 136)
 #define TARGET_NR_afs_syscall		(TARGET_NR_Linux + 137) /* Syscall for Andrew File System */
-#define TARGET_NR_setfsuid32			(TARGET_NR_Linux + 138)
-#define TARGET_NR_setfsgid32			(TARGET_NR_Linux + 139)
-#define TARGET_NR__llseek			(TARGET_NR_Linux + 140)
-#define TARGET_NR_getdents			(TARGET_NR_Linux + 141)
-#define TARGET_NR__newselect			(TARGET_NR_Linux + 142)
+#define TARGET_NR_setfsuid32		(TARGET_NR_Linux + 138)
+#define TARGET_NR_setfsgid32		(TARGET_NR_Linux + 139)
+#define TARGET_NR__llseek		(TARGET_NR_Linux + 140)
+#define TARGET_NR_getdents		(TARGET_NR_Linux + 141)
+#define TARGET_NR__newselect		(TARGET_NR_Linux + 142)
 #define TARGET_NR_flock			(TARGET_NR_Linux + 143)
 #define TARGET_NR_msync			(TARGET_NR_Linux + 144)
 #define TARGET_NR_readv			(TARGET_NR_Linux + 145)
-#define TARGET_NR_writev			(TARGET_NR_Linux + 146)
-#define TARGET_NR_cacheflush			(TARGET_NR_Linux + 147)
-#define TARGET_NR_cachectl			(TARGET_NR_Linux + 148)
-#define TARGET_NR_sysmips			(TARGET_NR_Linux + 149)
-#define TARGET_NR_unused150			(TARGET_NR_Linux + 150)
-#define TARGET_NR_getsid			(TARGET_NR_Linux + 151)
-#define TARGET_NR_fdatasync			(TARGET_NR_Linux + 152)
-#define TARGET_NR__sysctl			(TARGET_NR_Linux + 153)
+#define TARGET_NR_writev		(TARGET_NR_Linux + 146)
+#define TARGET_NR_cacheflush		(TARGET_NR_Linux + 147)
+#define TARGET_NR_cachectl		(TARGET_NR_Linux + 148)
+#define TARGET_NR_sysmips		(TARGET_NR_Linux + 149)
+#define TARGET_NR_unused150		(TARGET_NR_Linux + 150)
+#define TARGET_NR_getsid		(TARGET_NR_Linux + 151)
+#define TARGET_NR_fdatasync		(TARGET_NR_Linux + 152)
+#define TARGET_NR__sysctl		(TARGET_NR_Linux + 153)
 #define TARGET_NR_mlock			(TARGET_NR_Linux + 154)
-#define TARGET_NR_munlock			(TARGET_NR_Linux + 155)
-#define TARGET_NR_mlockall			(TARGET_NR_Linux + 156)
-#define TARGET_NR_munlockall			(TARGET_NR_Linux + 157)
-#define TARGET_NR_sched_setparam		(TARGET_NR_Linux + 158)
-#define TARGET_NR_sched_getparam		(TARGET_NR_Linux + 159)
-#define TARGET_NR_sched_setscheduler		(TARGET_NR_Linux + 160)
-#define TARGET_NR_sched_getscheduler		(TARGET_NR_Linux + 161)
+#define TARGET_NR_munlock		(TARGET_NR_Linux + 155)
+#define TARGET_NR_mlockall		(TARGET_NR_Linux + 156)
+#define TARGET_NR_munlockall		(TARGET_NR_Linux + 157)
+#define TARGET_NR_sched_setparam	(TARGET_NR_Linux + 158)
+#define TARGET_NR_sched_getparam	(TARGET_NR_Linux + 159)
+#define TARGET_NR_sched_setscheduler	(TARGET_NR_Linux + 160)
+#define TARGET_NR_sched_getscheduler	(TARGET_NR_Linux + 161)
 #define TARGET_NR_sched_yield		(TARGET_NR_Linux + 162)
 #define TARGET_NR_sched_get_priority_max	(TARGET_NR_Linux + 163)
 #define TARGET_NR_sched_get_priority_min	(TARGET_NR_Linux + 164)
 #define TARGET_NR_sched_rr_get_interval	(TARGET_NR_Linux + 165)
-#define TARGET_NR_nanosleep			(TARGET_NR_Linux + 166)
-#define TARGET_NR_mremap			(TARGET_NR_Linux + 167)
-#define TARGET_NR_accept			(TARGET_NR_Linux + 168)
+#define TARGET_NR_nanosleep		(TARGET_NR_Linux + 166)
+#define TARGET_NR_mremap		(TARGET_NR_Linux + 167)
+#define TARGET_NR_accept		(TARGET_NR_Linux + 168)
 #define TARGET_NR_bind			(TARGET_NR_Linux + 169)
-#define TARGET_NR_connect			(TARGET_NR_Linux + 170)
+#define TARGET_NR_connect		(TARGET_NR_Linux + 170)
 #define TARGET_NR_getpeername		(TARGET_NR_Linux + 171)
 #define TARGET_NR_getsockname		(TARGET_NR_Linux + 172)
-#define TARGET_NR_getsockopt			(TARGET_NR_Linux + 173)
-#define TARGET_NR_listen			(TARGET_NR_Linux + 174)
+#define TARGET_NR_getsockopt		(TARGET_NR_Linux + 173)
+#define TARGET_NR_listen		(TARGET_NR_Linux + 174)
 #define TARGET_NR_recv			(TARGET_NR_Linux + 175)
-#define TARGET_NR_recvfrom			(TARGET_NR_Linux + 176)
-#define TARGET_NR_recvmsg			(TARGET_NR_Linux + 177)
+#define TARGET_NR_recvfrom		(TARGET_NR_Linux + 176)
+#define TARGET_NR_recvmsg		(TARGET_NR_Linux + 177)
 #define TARGET_NR_send			(TARGET_NR_Linux + 178)
-#define TARGET_NR_sendmsg			(TARGET_NR_Linux + 179)
-#define TARGET_NR_sendto			(TARGET_NR_Linux + 180)
-#define TARGET_NR_setsockopt			(TARGET_NR_Linux + 181)
-#define TARGET_NR_shutdown			(TARGET_NR_Linux + 182)
-#define TARGET_NR_socket			(TARGET_NR_Linux + 183)
-#define TARGET_NR_socketpair			(TARGET_NR_Linux + 184)
-#define TARGET_NR_setresuid32			(TARGET_NR_Linux + 185)
-#define TARGET_NR_getresuid32			(TARGET_NR_Linux + 186)
+#define TARGET_NR_sendmsg		(TARGET_NR_Linux + 179)
+#define TARGET_NR_sendto		(TARGET_NR_Linux + 180)
+#define TARGET_NR_setsockopt		(TARGET_NR_Linux + 181)
+#define TARGET_NR_shutdown		(TARGET_NR_Linux + 182)
+#define TARGET_NR_socket		(TARGET_NR_Linux + 183)
+#define TARGET_NR_socketpair		(TARGET_NR_Linux + 184)
+#define TARGET_NR_setresuid32		(TARGET_NR_Linux + 185)
+#define TARGET_NR_getresuid32		(TARGET_NR_Linux + 186)
 #define TARGET_NR_query_module		(TARGET_NR_Linux + 187)
 #define TARGET_NR_poll			(TARGET_NR_Linux + 188)
-#define TARGET_NR_nfsservctl			(TARGET_NR_Linux + 189)
-#define TARGET_NR_setresgid32			(TARGET_NR_Linux + 190)
-#define TARGET_NR_getresgid32			(TARGET_NR_Linux + 191)
+#define TARGET_NR_nfsservctl		(TARGET_NR_Linux + 189)
+#define TARGET_NR_setresgid32		(TARGET_NR_Linux + 190)
+#define TARGET_NR_getresgid32		(TARGET_NR_Linux + 191)
 #define TARGET_NR_prctl			(TARGET_NR_Linux + 192)
 #define TARGET_NR_rt_sigreturn		(TARGET_NR_Linux + 193)
 #define TARGET_NR_rt_sigaction		(TARGET_NR_Linux + 194)
-#define TARGET_NR_rt_sigprocmask		(TARGET_NR_Linux + 195)
+#define TARGET_NR_rt_sigprocmask	(TARGET_NR_Linux + 195)
 #define TARGET_NR_rt_sigpending		(TARGET_NR_Linux + 196)
-#define TARGET_NR_rt_sigtimedwait		(TARGET_NR_Linux + 197)
-#define TARGET_NR_rt_sigqueueinfo		(TARGET_NR_Linux + 198)
+#define TARGET_NR_rt_sigtimedwait	(TARGET_NR_Linux + 197)
+#define TARGET_NR_rt_sigqueueinfo	(TARGET_NR_Linux + 198)
 #define TARGET_NR_rt_sigsuspend		(TARGET_NR_Linux + 199)
-#define TARGET_NR_pread64			(TARGET_NR_Linux + 200)
-#define TARGET_NR_pwrite64			(TARGET_NR_Linux + 201)
-#define TARGET_NR_chown32			(TARGET_NR_Linux + 202)
-#define TARGET_NR_getcwd			(TARGET_NR_Linux + 203)
-#define TARGET_NR_capget			(TARGET_NR_Linux + 204)
-#define TARGET_NR_capset			(TARGET_NR_Linux + 205)
+#define TARGET_NR_pread64		(TARGET_NR_Linux + 200)
+#define TARGET_NR_pwrite64		(TARGET_NR_Linux + 201)
+#define TARGET_NR_chown32		(TARGET_NR_Linux + 202)
+#define TARGET_NR_getcwd		(TARGET_NR_Linux + 203)
+#define TARGET_NR_capget		(TARGET_NR_Linux + 204)
+#define TARGET_NR_capset		(TARGET_NR_Linux + 205)
 #define TARGET_NR_sigaltstack		(TARGET_NR_Linux + 206)
-#define TARGET_NR_sendfile			(TARGET_NR_Linux + 207)
-#define TARGET_NR_getpmsg			(TARGET_NR_Linux + 208)
-#define TARGET_NR_putpmsg			(TARGET_NR_Linux + 209)
+#define TARGET_NR_sendfile		(TARGET_NR_Linux + 207)
+#define TARGET_NR_getpmsg		(TARGET_NR_Linux + 208)
+#define TARGET_NR_putpmsg		(TARGET_NR_Linux + 209)
 #define TARGET_NR_mmap2			(TARGET_NR_Linux + 210)
-#define TARGET_NR_truncate64			(TARGET_NR_Linux + 211)
+#define TARGET_NR_truncate64		(TARGET_NR_Linux + 211)
 #define TARGET_NR_ftruncate64		(TARGET_NR_Linux + 212)
-#define TARGET_NR_stat64			(TARGET_NR_Linux + 213)
-#define TARGET_NR_lstat64			(TARGET_NR_Linux + 214)
-#define TARGET_NR_fstat64			(TARGET_NR_Linux + 215)
-#define TARGET_NR_pivot_root			(TARGET_NR_Linux + 216)
-#define TARGET_NR_mincore			(TARGET_NR_Linux + 217)
-#define TARGET_NR_madvise			(TARGET_NR_Linux + 218)
-#define TARGET_NR_getdents64			(TARGET_NR_Linux + 219)
-#define TARGET_NR_fcntl64			(TARGET_NR_Linux + 220)
+#define TARGET_NR_stat64		(TARGET_NR_Linux + 213)
+#define TARGET_NR_lstat64		(TARGET_NR_Linux + 214)
+#define TARGET_NR_fstat64		(TARGET_NR_Linux + 215)
+#define TARGET_NR_pivot_root		(TARGET_NR_Linux + 216)
+#define TARGET_NR_mincore		(TARGET_NR_Linux + 217)
+#define TARGET_NR_madvise		(TARGET_NR_Linux + 218)
+#define TARGET_NR_getdents64		(TARGET_NR_Linux + 219)
+#define TARGET_NR_fcntl64		(TARGET_NR_Linux + 220)
 #define TARGET_NR_reserved221		(TARGET_NR_Linux + 221)
-#define TARGET_NR_gettid			(TARGET_NR_Linux + 222)
-#define TARGET_NR_readahead			(TARGET_NR_Linux + 223)
-#define TARGET_NR_setxattr			(TARGET_NR_Linux + 224)
-#define TARGET_NR_lsetxattr			(TARGET_NR_Linux + 225)
-#define TARGET_NR_fsetxattr			(TARGET_NR_Linux + 226)
-#define TARGET_NR_getxattr			(TARGET_NR_Linux + 227)
-#define TARGET_NR_lgetxattr			(TARGET_NR_Linux + 228)
-#define TARGET_NR_fgetxattr			(TARGET_NR_Linux + 229)
-#define TARGET_NR_listxattr			(TARGET_NR_Linux + 230)
-#define TARGET_NR_llistxattr			(TARGET_NR_Linux + 231)
-#define TARGET_NR_flistxattr			(TARGET_NR_Linux + 232)
+#define TARGET_NR_gettid		(TARGET_NR_Linux + 222)
+#define TARGET_NR_readahead		(TARGET_NR_Linux + 223)
+#define TARGET_NR_setxattr		(TARGET_NR_Linux + 224)
+#define TARGET_NR_lsetxattr		(TARGET_NR_Linux + 225)
+#define TARGET_NR_fsetxattr		(TARGET_NR_Linux + 226)
+#define TARGET_NR_getxattr		(TARGET_NR_Linux + 227)
+#define TARGET_NR_lgetxattr		(TARGET_NR_Linux + 228)
+#define TARGET_NR_fgetxattr		(TARGET_NR_Linux + 229)
+#define TARGET_NR_listxattr		(TARGET_NR_Linux + 230)
+#define TARGET_NR_llistxattr		(TARGET_NR_Linux + 231)
+#define TARGET_NR_flistxattr		(TARGET_NR_Linux + 232)
 #define TARGET_NR_removexattr		(TARGET_NR_Linux + 233)
 #define TARGET_NR_lremovexattr		(TARGET_NR_Linux + 234)
 #define TARGET_NR_fremovexattr		(TARGET_NR_Linux + 235)
 #define TARGET_NR_tkill			(TARGET_NR_Linux + 236)
-#define TARGET_NR_sendfile64			(TARGET_NR_Linux + 237)
+#define TARGET_NR_sendfile64		(TARGET_NR_Linux + 237)
 #define TARGET_NR_futex			(TARGET_NR_Linux + 238)
-#define TARGET_NR_sched_setaffinity		(TARGET_NR_Linux + 239)
-#define TARGET_NR_sched_getaffinity		(TARGET_NR_Linux + 240)
-#define TARGET_NR_io_setup			(TARGET_NR_Linux + 241)
-#define TARGET_NR_io_destroy			(TARGET_NR_Linux + 242)
+#define TARGET_NR_sched_setaffinity	(TARGET_NR_Linux + 239)
+#define TARGET_NR_sched_getaffinity	(TARGET_NR_Linux + 240)
+#define TARGET_NR_io_setup		(TARGET_NR_Linux + 241)
+#define TARGET_NR_io_destroy		(TARGET_NR_Linux + 242)
 #define TARGET_NR_io_getevents		(TARGET_NR_Linux + 243)
-#define TARGET_NR_io_submit			(TARGET_NR_Linux + 244)
-#define TARGET_NR_io_cancel			(TARGET_NR_Linux + 245)
-#define TARGET_NR_exit_group			(TARGET_NR_Linux + 246)
-#define TARGET_NR_lookup_dcookie		(TARGET_NR_Linux + 247)
+#define TARGET_NR_io_submit		(TARGET_NR_Linux + 244)
+#define TARGET_NR_io_cancel		(TARGET_NR_Linux + 245)
+#define TARGET_NR_exit_group		(TARGET_NR_Linux + 246)
+#define TARGET_NR_lookup_dcookie	(TARGET_NR_Linux + 247)
 #define TARGET_NR_epoll_create		(TARGET_NR_Linux + 248)
-#define TARGET_NR_epoll_ctl			(TARGET_NR_Linux + 249)
-#define TARGET_NR_epoll_wait			(TARGET_NR_Linux + 250)
-#define TARGET_NR_remap_file_pages		(TARGET_NR_Linux + 251)
-#define TARGET_NR_set_tid_address		(TARGET_NR_Linux + 252)
-#define TARGET_NR_restart_syscall		(TARGET_NR_Linux + 253)
-#define TARGET_NR_fadvise64			(TARGET_NR_Linux + 254)
-#define TARGET_NR_statfs64			(TARGET_NR_Linux + 255)
-#define TARGET_NR_fstatfs64			(TARGET_NR_Linux + 256)
+#define TARGET_NR_epoll_ctl		(TARGET_NR_Linux + 249)
+#define TARGET_NR_epoll_wait		(TARGET_NR_Linux + 250)
+#define TARGET_NR_remap_file_pages	(TARGET_NR_Linux + 251)
+#define TARGET_NR_set_tid_address	(TARGET_NR_Linux + 252)
+#define TARGET_NR_restart_syscall	(TARGET_NR_Linux + 253)
+#define TARGET_NR_fadvise64		(TARGET_NR_Linux + 254)
+#define TARGET_NR_statfs64		(TARGET_NR_Linux + 255)
+#define TARGET_NR_fstatfs64		(TARGET_NR_Linux + 256)
 #define TARGET_NR_timer_create		(TARGET_NR_Linux + 257)
 #define TARGET_NR_timer_settime		(TARGET_NR_Linux + 258)
 #define TARGET_NR_timer_gettime		(TARGET_NR_Linux + 259)
-#define TARGET_NR_timer_getoverrun		(TARGET_NR_Linux + 260)
+#define TARGET_NR_timer_getoverrun	(TARGET_NR_Linux + 260)
 #define TARGET_NR_timer_delete		(TARGET_NR_Linux + 261)
 #define TARGET_NR_clock_settime		(TARGET_NR_Linux + 262)
 #define TARGET_NR_clock_gettime		(TARGET_NR_Linux + 263)
 #define TARGET_NR_clock_getres		(TARGET_NR_Linux + 264)
-#define TARGET_NR_clock_nanosleep		(TARGET_NR_Linux + 265)
-#define TARGET_NR_tgkill			(TARGET_NR_Linux + 266)
-#define TARGET_NR_utimes			(TARGET_NR_Linux + 267)
+#define TARGET_NR_clock_nanosleep	(TARGET_NR_Linux + 265)
+#define TARGET_NR_tgkill		(TARGET_NR_Linux + 266)
+#define TARGET_NR_utimes		(TARGET_NR_Linux + 267)
 #define TARGET_NR_mbind			(TARGET_NR_Linux + 268)
 #define TARGET_NR_get_mempolicy		(TARGET_NR_Linux + 269)
 #define TARGET_NR_set_mempolicy		(TARGET_NR_Linux + 270)
-#define TARGET_NR_mq_open			(TARGET_NR_Linux + 271)
-#define TARGET_NR_mq_unlink			(TARGET_NR_Linux + 272)
+#define TARGET_NR_mq_open		(TARGET_NR_Linux + 271)
+#define TARGET_NR_mq_unlink		(TARGET_NR_Linux + 272)
 #define TARGET_NR_mq_timedsend		(TARGET_NR_Linux + 273)
-#define TARGET_NR_mq_timedreceive		(TARGET_NR_Linux + 274)
-#define TARGET_NR_mq_notify			(TARGET_NR_Linux + 275)
+#define TARGET_NR_mq_timedreceive	(TARGET_NR_Linux + 274)
+#define TARGET_NR_mq_notify		(TARGET_NR_Linux + 275)
 #define TARGET_NR_mq_getsetattr		(TARGET_NR_Linux + 276)
-#define TARGET_NR_vserver			(TARGET_NR_Linux + 277)
-#define TARGET_NR_waitid			(TARGET_NR_Linux + 278)
-/* #define TARGET_NR_sys_setaltroot		(TARGET_NR_Linux + 279) */
-#define TARGET_NR_add_key			(TARGET_NR_Linux + 280)
+#define TARGET_NR_vserver		(TARGET_NR_Linux + 277)
+#define TARGET_NR_waitid		(TARGET_NR_Linux + 278)
+/* #define TARGET_NR_sys_setaltroot	(TARGET_NR_Linux + 279) */
+#define TARGET_NR_add_key		(TARGET_NR_Linux + 280)
 #define TARGET_NR_request_key		(TARGET_NR_Linux + 281)
-#define TARGET_NR_keyctl			(TARGET_NR_Linux + 282)
-
+#define TARGET_NR_keyctl		(TARGET_NR_Linux + 282)
+#define TARGET_NR_set_thread_area	(TARGET_NR_Linux + 283)
+#define TARGET_NR_inotify_init		(TARGET_NR_Linux + 284)
+#define TARGET_NR_inotify_add_watch	(TARGET_NR_Linux + 285)
+#define TARGET_NR_inotify_rm_watch	(TARGET_NR_Linux + 286)
+#define TARGET_NR_migrate_pages		(TARGET_NR_Linux + 287)
+#define TARGET_NR_openat		(TARGET_NR_Linux + 288)
+#define TARGET_NR_mkdirat		(TARGET_NR_Linux + 289)
+#define TARGET_NR_mknodat		(TARGET_NR_Linux + 290)
+#define TARGET_NR_fchownat		(TARGET_NR_Linux + 291)
+#define TARGET_NR_futimesat		(TARGET_NR_Linux + 292)
+#define TARGET_NR_fstatat64		(TARGET_NR_Linux + 293)
+#define TARGET_NR_unlinkat		(TARGET_NR_Linux + 294)
+#define TARGET_NR_renameat		(TARGET_NR_Linux + 295)
+#define TARGET_NR_linkat		(TARGET_NR_Linux + 296)
+#define TARGET_NR_symlinkat		(TARGET_NR_Linux + 297)
+#define TARGET_NR_readlinkat		(TARGET_NR_Linux + 298)
+#define TARGET_NR_fchmodat		(TARGET_NR_Linux + 299)
+#define TARGET_NR_faccessat		(TARGET_NR_Linux + 300)
+#define TARGET_NR_pselect6		(TARGET_NR_Linux + 301)
+#define TARGET_NR_ppoll			(TARGET_NR_Linux + 302)
+#define TARGET_NR_unshare		(TARGET_NR_Linux + 303)
+#define TARGET_NR_splice		(TARGET_NR_Linux + 304)
+#define TARGET_NR_sync_file_range	(TARGET_NR_Linux + 305)
+#define TARGET_NR_tee			(TARGET_NR_Linux + 306)
+#define TARGET_NR_vmsplice		(TARGET_NR_Linux + 307)
+#define TARGET_NR_move_pages		(TARGET_NR_Linux + 308)
+#define TARGET_NR_set_robust_list	(TARGET_NR_Linux + 309)
+#define TARGET_NR_get_robust_list	(TARGET_NR_Linux + 310)
+#define TARGET_NR_kexec_load		(TARGET_NR_Linux + 311)
+#define TARGET_NR_getcpu		(TARGET_NR_Linux + 312)
+#define TARGET_NR_epoll_pwait		(TARGET_NR_Linux + 313)
+#define TARGET_NR_ioprio_set		(TARGET_NR_Linux + 314)
+#define TARGET_NR_ioprio_get		(TARGET_NR_Linux + 315)
+#define TARGET_NR_utimensat		(TARGET_NR_Linux + 316)
+#define TARGET_NR_signalfd		(TARGET_NR_Linux + 317)
+#define TARGET_NR_timerfd		(TARGET_NR_Linux + 318)
+#define TARGET_NR_eventfd		(TARGET_NR_Linux + 319)
+#define TARGET_NR_fallocate		(TARGET_NR_Linux + 320)
diff --git a/linux-user/mips/target_signal.h b/linux-user/mips/target_signal.h
new file mode 100644
index 0000000..514195c
--- /dev/null
+++ b/linux-user/mips/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_long ss_sp;
+	target_ulong ss_size;
+	target_long ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->gpr[29][state->current_tc];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/mips/termbits.h b/linux-user/mips/termbits.h
index fea7940..d3a6cf8 100644
--- a/linux-user/mips/termbits.h
+++ b/linux-user/mips/termbits.h
@@ -26,6 +26,7 @@
 #define TARGET_IXANY   0004000
 #define TARGET_IXOFF   0010000
 #define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
 
 /* c_oflag bits */
 #define TARGET_OPOST   0000001
@@ -92,12 +93,25 @@
 #define TARGET_HUPCL   0002000
 #define TARGET_CLOCAL  0004000
 #define TARGET_CBAUDEX 0010000
-#define  TARGET_B57600  0010001
-#define  TARGET_B115200 0010002
-#define  TARGET_B230400 0010003
-#define  TARGET_B460800 0010004
+#define  TARGET_BOTHER   0010000
+#define  TARGET_B57600   0010001
+#define  TARGET_B115200  0010002
+#define  TARGET_B230400  0010003
+#define  TARGET_B460800  0010004
+#define  TARGET_B500000  0010005
+#define  TARGET_B576000  0010006
+#define  TARGET_B921600  0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
 #define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
-#define TARGET_CRTSCTS   020000000000          /* flow control */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
 
 /* c_lflag bits */
 #define TARGET_ISIG    0000001
@@ -108,32 +122,34 @@
 #define TARGET_ECHOK   0000040
 #define TARGET_ECHONL  0000100
 #define TARGET_NOFLSH  0000200
-#define TARGET_TOSTOP  0000400
+#define TARGET_IEXTEN  0000400
 #define TARGET_ECHOCTL 0001000
 #define TARGET_ECHOPRT 0002000
 #define TARGET_ECHOKE  0004000
 #define TARGET_FLUSHO  0010000
 #define TARGET_PENDIN  0040000
-#define TARGET_IEXTEN  0100000
+#define TARGET_TOSTOP  0100000
+#define TARGET_ITOSTOP TARGET_TOSTOP
 
 /* c_cc character offsets */
 #define TARGET_VINTR	0
 #define TARGET_VQUIT	1
 #define TARGET_VERASE	2
 #define TARGET_VKILL	3
-#define TARGET_VEOF	4
+#define TARGET_VMIN	4
 #define TARGET_VTIME	5
-#define TARGET_VMIN	6
+#define TARGET_VEOL2	6
 #define TARGET_VSWTC	7
 #define TARGET_VSTART	8
 #define TARGET_VSTOP	9
 #define TARGET_VSUSP	10
-#define TARGET_VEOL	11
+/* VDSUSP not supported */
 #define TARGET_VREPRINT	12
 #define TARGET_VDISCARD	13
 #define TARGET_VWERASE	14
 #define TARGET_VLNEXT	15
-#define TARGET_VEOL2	16
+#define TARGET_VEOF	16
+#define TARGET_VEOL	17
 
 /* ioctls */
 
@@ -154,7 +170,7 @@
 #define TARGET_TIOCEXCL	0x740d		/* set exclusive use of tty */
 #define TARGET_TIOCNXCL	0x740e		/* reset exclusive use of tty */
 #define TARGET_TIOCOUTQ	0x7472		/* output queue size */
-#define TARGET_TIOCSTI		0x5472		/* simulate terminal input */
+#define TARGET_TIOCSTI	0x5472		/* simulate terminal input */
 #define TARGET_TIOCMGET	0x741d		/* get all modem bits */
 #define TARGET_TIOCMBIS	0x741b		/* bis modem bits */
 #define TARGET_TIOCMBIC	0x741c		/* bic modem bits */
diff --git a/linux-user/mips64/syscall.h b/linux-user/mips64/syscall.h
new file mode 100644
index 0000000..4ec506c
--- /dev/null
+++ b/linux-user/mips64/syscall.h
@@ -0,0 +1,221 @@
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct target_pt_regs {
+	/* Saved main processor registers. */
+	target_ulong regs[32];
+
+	/* Saved special registers. */
+	target_ulong cp0_status;
+	target_ulong lo;
+	target_ulong hi;
+	target_ulong cp0_badvaddr;
+	target_ulong cp0_cause;
+	target_ulong cp0_epc;
+};
+
+/* Target errno definitions taken from asm-mips/errno.h */
+#undef TARGET_ENOMSG
+#define TARGET_ENOMSG          35      /* Identifier removed */
+#undef TARGET_EIDRM
+#define TARGET_EIDRM           36      /* Identifier removed */
+#undef TARGET_ECHRNG
+#define TARGET_ECHRNG          37      /* Channel number out of range */
+#undef TARGET_EL2NSYNC
+#define TARGET_EL2NSYNC        38      /* Level 2 not synchronized */
+#undef TARGET_EL3HLT
+#define TARGET_EL3HLT          39      /* Level 3 halted */
+#undef TARGET_EL3RST
+#define TARGET_EL3RST          40      /* Level 3 reset */
+#undef TARGET_ELNRNG
+#define TARGET_ELNRNG          41      /* Link number out of range */
+#undef TARGET_EUNATCH
+#define TARGET_EUNATCH         42      /* Protocol driver not attached */
+#undef TARGET_ENOCSI
+#define TARGET_ENOCSI          43      /* No CSI structure available */
+#undef TARGET_EL2HLT
+#define TARGET_EL2HLT          44      /* Level 2 halted */
+#undef TARGET_EDEADLK
+#define TARGET_EDEADLK         45      /* Resource deadlock would occur */
+#undef TARGET_ENOLCK
+#define TARGET_ENOLCK          46      /* No record locks available */
+#undef TARGET_EBADE
+#define TARGET_EBADE           50      /* Invalid exchange */
+#undef TARGET_EBADR
+#define TARGET_EBADR           51      /* Invalid request descriptor */
+#undef TARGET_EXFULL
+#define TARGET_EXFULL          52      /* TARGET_Exchange full */
+#undef TARGET_ENOANO
+#define TARGET_ENOANO          53      /* No anode */
+#undef TARGET_EBADRQC
+#define TARGET_EBADRQC         54      /* Invalid request code */
+#undef TARGET_EBADSLT
+#define TARGET_EBADSLT         55      /* Invalid slot */
+#undef TARGET_EDEADLOCK
+#define TARGET_EDEADLOCK       56      /* File locking deadlock error */
+#undef TARGET_EBFONT
+#define TARGET_EBFONT          59      /* Bad font file format */
+#undef TARGET_ENOSTR
+#define TARGET_ENOSTR          60      /* Device not a stream */
+#undef TARGET_ENODATA
+#define TARGET_ENODATA         61      /* No data available */
+#undef TARGET_ETIME
+#define TARGET_ETIME           62      /* Timer expired */
+#undef TARGET_ENOSR
+#define TARGET_ENOSR           63      /* Out of streams resources */
+#undef TARGET_ENONET
+#define TARGET_ENONET          64      /* Machine is not on the network */
+#undef TARGET_ENOPKG
+#define TARGET_ENOPKG          65      /* Package not installed */
+#undef TARGET_EREMOTE
+#define TARGET_EREMOTE         66      /* Object is remote */
+#undef TARGET_ENOLINK
+#define TARGET_ENOLINK         67      /* Link has been severed */
+#undef TARGET_EADV
+#define TARGET_EADV            68      /* Advertise error */
+#undef TARGET_ESRMNT
+#define TARGET_ESRMNT          69      /* Srmount error */
+#undef TARGET_ECOMM
+#define TARGET_ECOMM           70      /* Communication error on send */
+#undef TARGET_EPROTO
+#define TARGET_EPROTO          71      /* Protocol error */
+#undef TARGET_EDOTDOT
+#define TARGET_EDOTDOT         73      /* RFS specific error */
+#undef TARGET_EMULTIHOP
+#define TARGET_EMULTIHOP       74      /* Multihop attempted */
+#undef TARGET_EBADMSG
+#define TARGET_EBADMSG         77      /* Not a data message */
+#undef TARGET_ENAMETOOLONG
+#define TARGET_ENAMETOOLONG    78      /* File name too long */
+#undef TARGET_EOVERFLOW
+#define TARGET_EOVERFLOW       79      /* Value too large for defined data type */
+#undef TARGET_ENOTUNIQ
+#define TARGET_ENOTUNIQ        80      /* Name not unique on network */
+#undef TARGET_EBADFD
+#define TARGET_EBADFD          81      /* File descriptor in bad state */
+#undef TARGET_EREMCHG
+#define TARGET_EREMCHG         82      /* Remote address changed */
+#undef TARGET_ELIBACC
+#define TARGET_ELIBACC         83      /* Can not access a needed shared library */
+#undef TARGET_ELIBBAD
+#define TARGET_ELIBBAD         84      /* Accessing a corrupted shared library */
+#undef TARGET_ELIBSCN
+#define TARGET_ELIBSCN         85      /* .lib section in a.out corrupted */
+#undef TARGET_ELIBMAX
+#define TARGET_ELIBMAX         86      /* Attempting to link in too many shared libraries */
+#undef TARGET_ELIBEXEC
+#define TARGET_ELIBEXEC        87      /* Cannot exec a shared library directly */
+#undef TARGET_EILSEQ
+#define TARGET_EILSEQ          88      /* Illegal byte sequence */
+#undef TARGET_ENOSYS
+#define TARGET_ENOSYS          89      /* Function not implemented */
+#undef TARGET_ELOOP
+#define TARGET_ELOOP           90      /* Too many symbolic links encountered */
+#undef TARGET_ERESTART
+#define TARGET_ERESTART        91      /* Interrupted system call should be restarted */
+#undef TARGET_ESTRPIPE
+#define TARGET_ESTRPIPE        92      /* Streams pipe error */
+#undef TARGET_ENOTEMPTY
+#define TARGET_ENOTEMPTY       93      /* Directory not empty */
+#undef TARGET_EUSERS
+#define TARGET_EUSERS          94      /* Too many users */
+#undef TARGET_ENOTSOCK
+#define TARGET_ENOTSOCK        95      /* Socket operation on non-socket */
+#undef TARGET_EDESTADDRREQ
+#define TARGET_EDESTADDRREQ    96      /* Destination address required */
+#undef TARGET_EMSGSIZE
+#define TARGET_EMSGSIZE        97      /* Message too long */
+#undef TARGET_EPROTOTYPE
+#define TARGET_EPROTOTYPE      98      /* Protocol wrong type for socket */
+#undef TARGET_ENOPROTOOPT
+#define TARGET_ENOPROTOOPT     99      /* Protocol not available */
+#undef TARGET_EPROTONOSUPPORT
+#define TARGET_EPROTONOSUPPORT 120     /* Protocol not supported */
+#undef TARGET_ESOCKTNOSUPPORT
+#define TARGET_ESOCKTNOSUPPORT 121     /* Socket type not supported */
+#undef TARGET_EOPNOTSUPP
+#define TARGET_EOPNOTSUPP      122     /* Operation not supported on transport endpoint */
+#undef TARGET_EPFNOSUPPORT
+#define TARGET_EPFNOSUPPORT    123     /* Protocol family not supported */
+#undef TARGET_EAFNOSUPPORT
+#define TARGET_EAFNOSUPPORT    124     /* Address family not supported by protocol */
+#undef TARGET_EADDRINUSE
+#define TARGET_EADDRINUSE      125     /* Address already in use */
+#undef TARGET_EADDRNOTAVAIL
+#define TARGET_EADDRNOTAVAIL   126     /* Cannot assign requested address */
+#undef TARGET_ENETDOWN
+#define TARGET_ENETDOWN        127     /* Network is down */
+#undef TARGET_ENETUNREACH
+#define TARGET_ENETUNREACH     128     /* Network is unreachable */
+#undef TARGET_ENETRESET
+#define TARGET_ENETRESET       129     /* Network dropped connection because of reset */
+#undef TARGET_ECONNABORTED
+#define TARGET_ECONNABORTED    130     /* Software caused connection abort */
+#undef TARGET_ECONNRESET
+#define TARGET_ECONNRESET      131     /* Connection reset by peer */
+#undef TARGET_ENOBUFS
+#define TARGET_ENOBUFS         132     /* No buffer space available */
+#undef TARGET_EISCONN
+#define TARGET_EISCONN         133     /* Transport endpoint is already connected */
+#undef TARGET_ENOTCONN
+#define TARGET_ENOTCONN        134     /* Transport endpoint is not connected */
+#undef TARGET_EUCLEAN
+#define TARGET_EUCLEAN         135     /* Structure needs cleaning */
+#undef TARGET_ENOTNAM
+#define TARGET_ENOTNAM         137     /* Not a XENIX named type file */
+#undef TARGET_ENAVAIL
+#define TARGET_ENAVAIL         138     /* No XENIX semaphores available */
+#undef TARGET_EISNAM
+#define TARGET_EISNAM          139     /* Is a named type file */
+#undef TARGET_EREMOTEIO
+#define TARGET_EREMOTEIO       140     /* Remote I/O error */
+#undef TARGET_EINIT
+#define TARGET_EINIT           141     /* Reserved */
+#undef TARGET_EREMDEV
+#define TARGET_EREMDEV         142     /* TARGET_Error 142 */
+#undef TARGET_ESHUTDOWN
+#define TARGET_ESHUTDOWN       143     /* Cannot send after transport endpoint shutdown */
+#undef TARGET_ETOOMANYREFS
+#define TARGET_ETOOMANYREFS    144     /* Too many references: cannot splice */
+#undef TARGET_ETIMEDOUT
+#define TARGET_ETIMEDOUT       145     /* Connection timed out */
+#undef TARGET_ECONNREFUSED
+#define TARGET_ECONNREFUSED    146     /* Connection refused */
+#undef TARGET_EHOSTDOWN
+#define TARGET_EHOSTDOWN       147     /* Host is down */
+#undef TARGET_EHOSTUNREACH
+#define TARGET_EHOSTUNREACH    148     /* No route to host */
+#undef TARGET_EALREADY
+#define TARGET_EALREADY        149     /* Operation already in progress */
+#undef TARGET_EINPROGRESS
+#define TARGET_EINPROGRESS     150     /* Operation now in progress */
+#undef TARGET_ESTALE
+#define TARGET_ESTALE          151     /* Stale NFS file handle */
+#undef TARGET_ECANCELED
+#define TARGET_ECANCELED       158     /* AIO operation canceled */
+/*
+ * These error are Linux extensions.
+ */
+#undef TARGET_ENOMEDIUM
+#define TARGET_ENOMEDIUM       159     /* No medium found */
+#undef TARGET_EMEDIUMTYPE
+#define TARGET_EMEDIUMTYPE     160     /* Wrong medium type */
+#undef TARGET_ENOKEY
+#define TARGET_ENOKEY          161     /* Required key not available */
+#undef TARGET_EKEYEXPIRED
+#define TARGET_EKEYEXPIRED     162     /* Key has expired */
+#undef TARGET_EKEYREVOKED
+#define TARGET_EKEYREVOKED     163     /* Key has been revoked */
+#undef TARGET_EKEYREJECTED
+#define TARGET_EKEYREJECTED    164     /* Key was rejected by service */
+
+/* for robust mutexes */
+#undef TARGET_EOWNERDEAD
+#define TARGET_EOWNERDEAD      165     /* Owner died */
+#undef TARGET_ENOTRECOVERABLE
+#define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
+
+
+
+#define UNAME_MACHINE "mips64"
diff --git a/linux-user/mips64/syscall_nr.h b/linux-user/mips64/syscall_nr.h
new file mode 100644
index 0000000..28e1883
--- /dev/null
+++ b/linux-user/mips64/syscall_nr.h
@@ -0,0 +1,284 @@
+/*
+ * Linux 64-bit syscalls are in the range from 5000 to 5999.
+ */
+#define TARGET_NR_Linux			5000
+#define TARGET_NR_read			(TARGET_NR_Linux +   0)
+#define TARGET_NR_write			(TARGET_NR_Linux +   1)
+#define TARGET_NR_open			(TARGET_NR_Linux +   2)
+#define TARGET_NR_close			(TARGET_NR_Linux +   3)
+#define TARGET_NR_stat			(TARGET_NR_Linux +   4)
+#define TARGET_NR_fstat			(TARGET_NR_Linux +   5)
+#define TARGET_NR_lstat			(TARGET_NR_Linux +   6)
+#define TARGET_NR_poll			(TARGET_NR_Linux +   7)
+#define TARGET_NR_lseek			(TARGET_NR_Linux +   8)
+#define TARGET_NR_mmap			(TARGET_NR_Linux +   9)
+#define TARGET_NR_mprotect			(TARGET_NR_Linux +  10)
+#define TARGET_NR_munmap			(TARGET_NR_Linux +  11)
+#define TARGET_NR_brk			(TARGET_NR_Linux +  12)
+#define TARGET_NR_rt_sigaction		(TARGET_NR_Linux +  13)
+#define TARGET_NR_rt_sigprocmask		(TARGET_NR_Linux +  14)
+#define TARGET_NR_ioctl			(TARGET_NR_Linux +  15)
+#define TARGET_NR_pread64			(TARGET_NR_Linux +  16)
+#define TARGET_NR_pwrite64			(TARGET_NR_Linux +  17)
+#define TARGET_NR_readv			(TARGET_NR_Linux +  18)
+#define TARGET_NR_writev			(TARGET_NR_Linux +  19)
+#define TARGET_NR_access			(TARGET_NR_Linux +  20)
+#define TARGET_NR_pipe			(TARGET_NR_Linux +  21)
+#define TARGET_NR__newselect			(TARGET_NR_Linux +  22)
+#define TARGET_NR_sched_yield		(TARGET_NR_Linux +  23)
+#define TARGET_NR_mremap			(TARGET_NR_Linux +  24)
+#define TARGET_NR_msync			(TARGET_NR_Linux +  25)
+#define TARGET_NR_mincore			(TARGET_NR_Linux +  26)
+#define TARGET_NR_madvise			(TARGET_NR_Linux +  27)
+#define TARGET_NR_shmget			(TARGET_NR_Linux +  28)
+#define TARGET_NR_shmat			(TARGET_NR_Linux +  29)
+#define TARGET_NR_shmctl			(TARGET_NR_Linux +  30)
+#define TARGET_NR_dup			(TARGET_NR_Linux +  31)
+#define TARGET_NR_dup2			(TARGET_NR_Linux +  32)
+#define TARGET_NR_pause			(TARGET_NR_Linux +  33)
+#define TARGET_NR_nanosleep			(TARGET_NR_Linux +  34)
+#define TARGET_NR_getitimer			(TARGET_NR_Linux +  35)
+#define TARGET_NR_setitimer			(TARGET_NR_Linux +  36)
+#define TARGET_NR_alarm			(TARGET_NR_Linux +  37)
+#define TARGET_NR_getpid			(TARGET_NR_Linux +  38)
+#define TARGET_NR_sendfile			(TARGET_NR_Linux +  39)
+#define TARGET_NR_socket			(TARGET_NR_Linux +  40)
+#define TARGET_NR_connect			(TARGET_NR_Linux +  41)
+#define TARGET_NR_accept			(TARGET_NR_Linux +  42)
+#define TARGET_NR_sendto			(TARGET_NR_Linux +  43)
+#define TARGET_NR_recvfrom			(TARGET_NR_Linux +  44)
+#define TARGET_NR_sendmsg			(TARGET_NR_Linux +  45)
+#define TARGET_NR_recvmsg			(TARGET_NR_Linux +  46)
+#define TARGET_NR_shutdown			(TARGET_NR_Linux +  47)
+#define TARGET_NR_bind			(TARGET_NR_Linux +  48)
+#define TARGET_NR_listen			(TARGET_NR_Linux +  49)
+#define TARGET_NR_getsockname		(TARGET_NR_Linux +  50)
+#define TARGET_NR_getpeername		(TARGET_NR_Linux +  51)
+#define TARGET_NR_socketpair			(TARGET_NR_Linux +  52)
+#define TARGET_NR_setsockopt			(TARGET_NR_Linux +  53)
+#define TARGET_NR_getsockopt			(TARGET_NR_Linux +  54)
+#define TARGET_NR_clone			(TARGET_NR_Linux +  55)
+#define TARGET_NR_fork			(TARGET_NR_Linux +  56)
+#define TARGET_NR_execve			(TARGET_NR_Linux +  57)
+#define TARGET_NR_exit			(TARGET_NR_Linux +  58)
+#define TARGET_NR_wait4			(TARGET_NR_Linux +  59)
+#define TARGET_NR_kill			(TARGET_NR_Linux +  60)
+#define TARGET_NR_uname			(TARGET_NR_Linux +  61)
+#define TARGET_NR_semget			(TARGET_NR_Linux +  62)
+#define TARGET_NR_semop			(TARGET_NR_Linux +  63)
+#define TARGET_NR_semctl			(TARGET_NR_Linux +  64)
+#define TARGET_NR_shmdt			(TARGET_NR_Linux +  65)
+#define TARGET_NR_msgget			(TARGET_NR_Linux +  66)
+#define TARGET_NR_msgsnd			(TARGET_NR_Linux +  67)
+#define TARGET_NR_msgrcv			(TARGET_NR_Linux +  68)
+#define TARGET_NR_msgctl			(TARGET_NR_Linux +  69)
+#define TARGET_NR_fcntl			(TARGET_NR_Linux +  70)
+#define TARGET_NR_flock			(TARGET_NR_Linux +  71)
+#define TARGET_NR_fsync			(TARGET_NR_Linux +  72)
+#define TARGET_NR_fdatasync			(TARGET_NR_Linux +  73)
+#define TARGET_NR_truncate			(TARGET_NR_Linux +  74)
+#define TARGET_NR_ftruncate			(TARGET_NR_Linux +  75)
+#define TARGET_NR_getdents			(TARGET_NR_Linux +  76)
+#define TARGET_NR_getcwd			(TARGET_NR_Linux +  77)
+#define TARGET_NR_chdir			(TARGET_NR_Linux +  78)
+#define TARGET_NR_fchdir			(TARGET_NR_Linux +  79)
+#define TARGET_NR_rename			(TARGET_NR_Linux +  80)
+#define TARGET_NR_mkdir			(TARGET_NR_Linux +  81)
+#define TARGET_NR_rmdir			(TARGET_NR_Linux +  82)
+#define TARGET_NR_creat			(TARGET_NR_Linux +  83)
+#define TARGET_NR_link			(TARGET_NR_Linux +  84)
+#define TARGET_NR_unlink			(TARGET_NR_Linux +  85)
+#define TARGET_NR_symlink			(TARGET_NR_Linux +  86)
+#define TARGET_NR_readlink			(TARGET_NR_Linux +  87)
+#define TARGET_NR_chmod			(TARGET_NR_Linux +  88)
+#define TARGET_NR_fchmod			(TARGET_NR_Linux +  89)
+#define TARGET_NR_chown			(TARGET_NR_Linux +  90)
+#define TARGET_NR_fchown			(TARGET_NR_Linux +  91)
+#define TARGET_NR_lchown			(TARGET_NR_Linux +  92)
+#define TARGET_NR_umask			(TARGET_NR_Linux +  93)
+#define TARGET_NR_gettimeofday		(TARGET_NR_Linux +  94)
+#define TARGET_NR_getrlimit			(TARGET_NR_Linux +  95)
+#define TARGET_NR_getrusage			(TARGET_NR_Linux +  96)
+#define TARGET_NR_sysinfo			(TARGET_NR_Linux +  97)
+#define TARGET_NR_times			(TARGET_NR_Linux +  98)
+#define TARGET_NR_ptrace			(TARGET_NR_Linux +  99)
+#define TARGET_NR_getuid			(TARGET_NR_Linux + 100)
+#define TARGET_NR_syslog			(TARGET_NR_Linux + 101)
+#define TARGET_NR_getgid			(TARGET_NR_Linux + 102)
+#define TARGET_NR_setuid			(TARGET_NR_Linux + 103)
+#define TARGET_NR_setgid			(TARGET_NR_Linux + 104)
+#define TARGET_NR_geteuid			(TARGET_NR_Linux + 105)
+#define TARGET_NR_getegid			(TARGET_NR_Linux + 106)
+#define TARGET_NR_setpgid			(TARGET_NR_Linux + 107)
+#define TARGET_NR_getppid			(TARGET_NR_Linux + 108)
+#define TARGET_NR_getpgrp			(TARGET_NR_Linux + 109)
+#define TARGET_NR_setsid			(TARGET_NR_Linux + 110)
+#define TARGET_NR_setreuid			(TARGET_NR_Linux + 111)
+#define TARGET_NR_setregid			(TARGET_NR_Linux + 112)
+#define TARGET_NR_getgroups			(TARGET_NR_Linux + 113)
+#define TARGET_NR_setgroups			(TARGET_NR_Linux + 114)
+#define TARGET_NR_setresuid			(TARGET_NR_Linux + 115)
+#define TARGET_NR_getresuid			(TARGET_NR_Linux + 116)
+#define TARGET_NR_setresgid			(TARGET_NR_Linux + 117)
+#define TARGET_NR_getresgid			(TARGET_NR_Linux + 118)
+#define TARGET_NR_getpgid			(TARGET_NR_Linux + 119)
+#define TARGET_NR_setfsuid			(TARGET_NR_Linux + 120)
+#define TARGET_NR_setfsgid			(TARGET_NR_Linux + 121)
+#define TARGET_NR_getsid			(TARGET_NR_Linux + 122)
+#define TARGET_NR_capget			(TARGET_NR_Linux + 123)
+#define TARGET_NR_capset			(TARGET_NR_Linux + 124)
+#define TARGET_NR_rt_sigpending		(TARGET_NR_Linux + 125)
+#define TARGET_NR_rt_sigtimedwait		(TARGET_NR_Linux + 126)
+#define TARGET_NR_rt_sigqueueinfo		(TARGET_NR_Linux + 127)
+#define TARGET_NR_rt_sigsuspend		(TARGET_NR_Linux + 128)
+#define TARGET_NR_sigaltstack		(TARGET_NR_Linux + 129)
+#define TARGET_NR_utime			(TARGET_NR_Linux + 130)
+#define TARGET_NR_mknod			(TARGET_NR_Linux + 131)
+#define TARGET_NR_personality		(TARGET_NR_Linux + 132)
+#define TARGET_NR_ustat			(TARGET_NR_Linux + 133)
+#define TARGET_NR_statfs			(TARGET_NR_Linux + 134)
+#define TARGET_NR_fstatfs			(TARGET_NR_Linux + 135)
+#define TARGET_NR_sysfs			(TARGET_NR_Linux + 136)
+#define TARGET_NR_getpriority		(TARGET_NR_Linux + 137)
+#define TARGET_NR_setpriority		(TARGET_NR_Linux + 138)
+#define TARGET_NR_sched_setparam		(TARGET_NR_Linux + 139)
+#define TARGET_NR_sched_getparam		(TARGET_NR_Linux + 140)
+#define TARGET_NR_sched_setscheduler		(TARGET_NR_Linux + 141)
+#define TARGET_NR_sched_getscheduler		(TARGET_NR_Linux + 142)
+#define TARGET_NR_sched_get_priority_max	(TARGET_NR_Linux + 143)
+#define TARGET_NR_sched_get_priority_min	(TARGET_NR_Linux + 144)
+#define TARGET_NR_sched_rr_get_interval	(TARGET_NR_Linux + 145)
+#define TARGET_NR_mlock			(TARGET_NR_Linux + 146)
+#define TARGET_NR_munlock			(TARGET_NR_Linux + 147)
+#define TARGET_NR_mlockall			(TARGET_NR_Linux + 148)
+#define TARGET_NR_munlockall			(TARGET_NR_Linux + 149)
+#define TARGET_NR_vhangup			(TARGET_NR_Linux + 150)
+#define TARGET_NR_pivot_root			(TARGET_NR_Linux + 151)
+#define TARGET_NR__sysctl			(TARGET_NR_Linux + 152)
+#define TARGET_NR_prctl			(TARGET_NR_Linux + 153)
+#define TARGET_NR_adjtimex			(TARGET_NR_Linux + 154)
+#define TARGET_NR_setrlimit			(TARGET_NR_Linux + 155)
+#define TARGET_NR_chroot			(TARGET_NR_Linux + 156)
+#define TARGET_NR_sync			(TARGET_NR_Linux + 157)
+#define TARGET_NR_acct			(TARGET_NR_Linux + 158)
+#define TARGET_NR_settimeofday		(TARGET_NR_Linux + 159)
+#define TARGET_NR_mount			(TARGET_NR_Linux + 160)
+#define TARGET_NR_umount2			(TARGET_NR_Linux + 161)
+#define TARGET_NR_swapon			(TARGET_NR_Linux + 162)
+#define TARGET_NR_swapoff			(TARGET_NR_Linux + 163)
+#define TARGET_NR_reboot			(TARGET_NR_Linux + 164)
+#define TARGET_NR_sethostname		(TARGET_NR_Linux + 165)
+#define TARGET_NR_setdomainname		(TARGET_NR_Linux + 166)
+#define TARGET_NR_create_module		(TARGET_NR_Linux + 167)
+#define TARGET_NR_init_module		(TARGET_NR_Linux + 168)
+#define TARGET_NR_delete_module		(TARGET_NR_Linux + 169)
+#define TARGET_NR_get_kernel_syms		(TARGET_NR_Linux + 170)
+#define TARGET_NR_query_module		(TARGET_NR_Linux + 171)
+#define TARGET_NR_quotactl			(TARGET_NR_Linux + 172)
+#define TARGET_NR_nfsservctl			(TARGET_NR_Linux + 173)
+#define TARGET_NR_getpmsg			(TARGET_NR_Linux + 174)
+#define TARGET_NR_putpmsg			(TARGET_NR_Linux + 175)
+#define TARGET_NR_afs_syscall		(TARGET_NR_Linux + 176)
+#define TARGET_NR_reserved177		(TARGET_NR_Linux + 177)
+#define TARGET_NR_gettid			(TARGET_NR_Linux + 178)
+#define TARGET_NR_readahead			(TARGET_NR_Linux + 179)
+#define TARGET_NR_setxattr			(TARGET_NR_Linux + 180)
+#define TARGET_NR_lsetxattr			(TARGET_NR_Linux + 181)
+#define TARGET_NR_fsetxattr			(TARGET_NR_Linux + 182)
+#define TARGET_NR_getxattr			(TARGET_NR_Linux + 183)
+#define TARGET_NR_lgetxattr			(TARGET_NR_Linux + 184)
+#define TARGET_NR_fgetxattr			(TARGET_NR_Linux + 185)
+#define TARGET_NR_listxattr			(TARGET_NR_Linux + 186)
+#define TARGET_NR_llistxattr			(TARGET_NR_Linux + 187)
+#define TARGET_NR_flistxattr			(TARGET_NR_Linux + 188)
+#define TARGET_NR_removexattr		(TARGET_NR_Linux + 189)
+#define TARGET_NR_lremovexattr		(TARGET_NR_Linux + 190)
+#define TARGET_NR_fremovexattr		(TARGET_NR_Linux + 191)
+#define TARGET_NR_tkill			(TARGET_NR_Linux + 192)
+#define TARGET_NR_reserved193		(TARGET_NR_Linux + 193)
+#define TARGET_NR_futex			(TARGET_NR_Linux + 194)
+#define TARGET_NR_sched_setaffinity		(TARGET_NR_Linux + 195)
+#define TARGET_NR_sched_getaffinity		(TARGET_NR_Linux + 196)
+#define TARGET_NR_cacheflush			(TARGET_NR_Linux + 197)
+#define TARGET_NR_cachectl			(TARGET_NR_Linux + 198)
+#define TARGET_NR_sysmips			(TARGET_NR_Linux + 199)
+#define TARGET_NR_io_setup			(TARGET_NR_Linux + 200)
+#define TARGET_NR_io_destroy			(TARGET_NR_Linux + 201)
+#define TARGET_NR_io_getevents		(TARGET_NR_Linux + 202)
+#define TARGET_NR_io_submit			(TARGET_NR_Linux + 203)
+#define TARGET_NR_io_cancel			(TARGET_NR_Linux + 204)
+#define TARGET_NR_exit_group			(TARGET_NR_Linux + 205)
+#define TARGET_NR_lookup_dcookie		(TARGET_NR_Linux + 206)
+#define TARGET_NR_epoll_create		(TARGET_NR_Linux + 207)
+#define TARGET_NR_epoll_ctl			(TARGET_NR_Linux + 208)
+#define TARGET_NR_epoll_wait			(TARGET_NR_Linux + 209)
+#define TARGET_NR_remap_file_pages		(TARGET_NR_Linux + 210)
+#define TARGET_NR_rt_sigreturn		(TARGET_NR_Linux + 211)
+#define TARGET_NR_set_tid_address		(TARGET_NR_Linux + 212)
+#define TARGET_NR_restart_syscall		(TARGET_NR_Linux + 213)
+#define TARGET_NR_semtimedop			(TARGET_NR_Linux + 214)
+#define TARGET_NR_fadvise64			(TARGET_NR_Linux + 215)
+#define TARGET_NR_timer_create		(TARGET_NR_Linux + 216)
+#define TARGET_NR_timer_settime		(TARGET_NR_Linux + 217)
+#define TARGET_NR_timer_gettime		(TARGET_NR_Linux + 218)
+#define TARGET_NR_timer_getoverrun		(TARGET_NR_Linux + 219)
+#define TARGET_NR_timer_delete		(TARGET_NR_Linux + 220)
+#define TARGET_NR_clock_settime		(TARGET_NR_Linux + 221)
+#define TARGET_NR_clock_gettime		(TARGET_NR_Linux + 222)
+#define TARGET_NR_clock_getres		(TARGET_NR_Linux + 223)
+#define TARGET_NR_clock_nanosleep		(TARGET_NR_Linux + 224)
+#define TARGET_NR_tgkill			(TARGET_NR_Linux + 225)
+#define TARGET_NR_utimes			(TARGET_NR_Linux + 226)
+#define TARGET_NR_mbind			(TARGET_NR_Linux + 227)
+#define TARGET_NR_get_mempolicy		(TARGET_NR_Linux + 228)
+#define TARGET_NR_set_mempolicy		(TARGET_NR_Linux + 229)
+#define TARGET_NR_mq_open			(TARGET_NR_Linux + 230)
+#define TARGET_NR_mq_unlink			(TARGET_NR_Linux + 231)
+#define TARGET_NR_mq_timedsend		(TARGET_NR_Linux + 232)
+#define TARGET_NR_mq_timedreceive		(TARGET_NR_Linux + 233)
+#define TARGET_NR_mq_notify			(TARGET_NR_Linux + 234)
+#define TARGET_NR_mq_getsetattr		(TARGET_NR_Linux + 235)
+#define TARGET_NR_vserver			(TARGET_NR_Linux + 236)
+#define TARGET_NR_waitid			(TARGET_NR_Linux + 237)
+/* #define TARGET_NR_sys_setaltroot		(TARGET_NR_Linux + 238) */
+#define TARGET_NR_add_key			(TARGET_NR_Linux + 239)
+#define TARGET_NR_request_key		(TARGET_NR_Linux + 240)
+#define TARGET_NR_keyctl			(TARGET_NR_Linux + 241)
+#define TARGET_NR_set_thread_area		(TARGET_NR_Linux + 242)
+#define TARGET_NR_inotify_init		(TARGET_NR_Linux + 243)
+#define TARGET_NR_inotify_add_watch		(TARGET_NR_Linux + 244)
+#define TARGET_NR_inotify_rm_watch		(TARGET_NR_Linux + 245)
+#define TARGET_NR_migrate_pages		(TARGET_NR_Linux + 246)
+#define TARGET_NR_openat			(TARGET_NR_Linux + 247)
+#define TARGET_NR_mkdirat			(TARGET_NR_Linux + 248)
+#define TARGET_NR_mknodat			(TARGET_NR_Linux + 249)
+#define TARGET_NR_fchownat			(TARGET_NR_Linux + 250)
+#define TARGET_NR_futimesat			(TARGET_NR_Linux + 251)
+#define TARGET_NR_newfstatat			(TARGET_NR_Linux + 252)
+#define TARGET_NR_unlinkat			(TARGET_NR_Linux + 253)
+#define TARGET_NR_renameat			(TARGET_NR_Linux + 254)
+#define TARGET_NR_linkat			(TARGET_NR_Linux + 255)
+#define TARGET_NR_symlinkat			(TARGET_NR_Linux + 256)
+#define TARGET_NR_readlinkat			(TARGET_NR_Linux + 257)
+#define TARGET_NR_fchmodat			(TARGET_NR_Linux + 258)
+#define TARGET_NR_faccessat			(TARGET_NR_Linux + 259)
+#define TARGET_NR_pselect6			(TARGET_NR_Linux + 260)
+#define TARGET_NR_ppoll			(TARGET_NR_Linux + 261)
+#define TARGET_NR_unshare			(TARGET_NR_Linux + 262)
+#define TARGET_NR_splice			(TARGET_NR_Linux + 263)
+#define TARGET_NR_sync_file_range		(TARGET_NR_Linux + 264)
+#define TARGET_NR_tee			(TARGET_NR_Linux + 265)
+#define TARGET_NR_vmsplice			(TARGET_NR_Linux + 266)
+#define TARGET_NR_move_pages			(TARGET_NR_Linux + 267)
+#define TARGET_NR_set_robust_list		(TARGET_NR_Linux + 268)
+#define TARGET_NR_get_robust_list		(TARGET_NR_Linux + 269)
+#define TARGET_NR_kexec_load			(TARGET_NR_Linux + 270)
+#define TARGET_NR_getcpu			(TARGET_NR_Linux + 271)
+#define TARGET_NR_epoll_pwait		(TARGET_NR_Linux + 272)
+#define TARGET_NR_ioprio_set			(TARGET_NR_Linux + 273)
+#define TARGET_NR_ioprio_get			(TARGET_NR_Linux + 274)
+#define TARGET_NR_utimensat			(TARGET_NR_Linux + 275)
+#define TARGET_NR_signalfd			(TARGET_NR_Linux + 276)
+#define TARGET_NR_timerfd			(TARGET_NR_Linux + 277)
+#define TARGET_NR_eventfd			(TARGET_NR_Linux + 278)
+#define TARGET_NR_fallocate			(TARGET_NR_Linux + 279)
diff --git a/linux-user/mips64/target_signal.h b/linux-user/mips64/target_signal.h
new file mode 100644
index 0000000..514195c
--- /dev/null
+++ b/linux-user/mips64/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_long ss_sp;
+	target_ulong ss_size;
+	target_long ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->gpr[29][state->current_tc];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/mips64/termbits.h b/linux-user/mips64/termbits.h
new file mode 100644
index 0000000..d3a6cf8
--- /dev/null
+++ b/linux-user/mips64/termbits.h
@@ -0,0 +1,245 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 23
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_BOTHER   0010000
+#define  TARGET_B57600   0010001
+#define  TARGET_B115200  0010002
+#define  TARGET_B230400  0010003
+#define  TARGET_B460800  0010004
+#define  TARGET_B500000  0010005
+#define  TARGET_B576000  0010006
+#define  TARGET_B921600  0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_IEXTEN  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_TOSTOP  0100000
+#define TARGET_ITOSTOP TARGET_TOSTOP
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VMIN	4
+#define TARGET_VTIME	5
+#define TARGET_VEOL2	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+/* VDSUSP not supported */
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOF	16
+#define TARGET_VEOL	17
+
+/* ioctls */
+
+#define TARGET_TCGETA		0x5401
+#define TARGET_TCSETA		0x5402	/* Clashes with SNDCTL_TMR_START sound ioctl */
+#define TARGET_TCSETAW		0x5403
+#define TARGET_TCSETAF		0x5404
+
+#define TARGET_TCSBRK		0x5405
+#define TARGET_TCXONC		0x5406
+#define TARGET_TCFLSH		0x5407
+
+#define TARGET_TCGETS		0x540d
+#define TARGET_TCSETS		0x540e
+#define TARGET_TCSETSW		0x540f
+#define TARGET_TCSETSF		0x5410
+
+#define TARGET_TIOCEXCL	0x740d		/* set exclusive use of tty */
+#define TARGET_TIOCNXCL	0x740e		/* reset exclusive use of tty */
+#define TARGET_TIOCOUTQ	0x7472		/* output queue size */
+#define TARGET_TIOCSTI	0x5472		/* simulate terminal input */
+#define TARGET_TIOCMGET	0x741d		/* get all modem bits */
+#define TARGET_TIOCMBIS	0x741b		/* bis modem bits */
+#define TARGET_TIOCMBIC	0x741c		/* bic modem bits */
+#define TARGET_TIOCMSET	0x741a		/* set all modem bits */
+#define TARGET_TIOCPKT		0x5470		/* pty: set/clear packet mode */
+#define	 TARGET_TIOCPKT_DATA		0x00	/* data packet */
+#define	 TARGET_TIOCPKT_FLUSHREAD	0x01	/* flush packet */
+#define	 TARGET_TIOCPKT_FLUSHWRITE	0x02	/* flush packet */
+#define	 TARGET_TIOCPKT_STOP		0x04	/* stop output */
+#define	 TARGET_TIOCPKT_START		0x08	/* start output */
+#define	 TARGET_TIOCPKT_NOSTOP		0x10	/* no more ^S, ^Q */
+#define	 TARGET_TIOCPKT_DOSTOP		0x20	/* now do ^S ^Q */
+/* #define  TIOCPKT_IOCTL		0x40	state change of pty driver */
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct winsize)	/* set window size */
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct winsize)	/* get window size */
+#define TARGET_TIOCNOTTY	0x5471		/* void tty association */
+#define TARGET_TIOCSETD	0x7401
+#define TARGET_TIOCGETD	0x7400
+
+#define TARGET_FIOCLEX		0x6601
+#define TARGET_FIONCLEX	0x6602
+#define TARGET_FIOASYNC	0x667d
+#define TARGET_FIONBIO		0x667e
+#define TARGET_FIOQSIZE	0x667f
+
+#define TARGET_TIOCGLTC	0x7474			/* get special local chars */
+#define TARGET_TIOCSLTC	0x7475			/* set special local chars */
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 118, int)	/* set pgrp of tty */
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 119, int)	/* get pgrp of tty */
+#define TARGET_TIOCCONS	TARGET_IOW('t', 120, int)	/* become virtual console */
+
+#define TARGET_FIONREAD	0x467f
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+
+#define TARGET_TIOCGETP        0x7408
+#define TARGET_TIOCSETP        0x7409
+#define TARGET_TIOCSETN        0x740a			/* TIOCSETP wo flush */
+
+/* #define TARGET_TIOCSETA	TARGET_IOW('t', 20, struct termios) set termios struct */
+/* #define TARGET_TIOCSETAW	TARGET_IOW('t', 21, struct termios) drain output, set */
+/* #define TARGET_TIOCSETAF	TARGET_IOW('t', 22, struct termios) drn out, fls in, set */
+/* #define TARGET_TIOCGETD	TARGET_IOR('t', 26, int)	get line discipline */
+/* #define TARGET_TIOCSETD	TARGET_IOW('t', 27, int)	set line discipline */
+						/* 127-124 compat */
+
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x7416  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+/* I hope the range from 0x5480 on is free ... */
+#define TARGET_TIOCSCTTY	0x5480		/* become controlling tty */
+#define TARGET_TIOCGSOFTCAR	0x5481
+#define TARGET_TIOCSSOFTCAR	0x5482
+#define TARGET_TIOCLINUX	0x5483
+#define TARGET_TIOCGSERIAL	0x5484
+#define TARGET_TIOCSSERIAL	0x5485
+#define TARGET_TCSBRKP		0x5486	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSERCONFIG	0x5488
+#define TARGET_TIOCSERGWILD	0x5489
+#define TARGET_TIOCSERSWILD	0x548a
+#define TARGET_TIOCGLCKTRMIOS	0x548b
+#define TARGET_TIOCSLCKTRMIOS	0x548c
+#define TARGET_TIOCSERGSTRUCT	0x548d /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x548e /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */
+#define TARGET_TIOCMIWAIT      0x5491 /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT     0x5492 /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP	0x5493 /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP	0x5494 /* Set Hayes ESP configuration */
diff --git a/linux-user/mipsn32/syscall.h b/linux-user/mipsn32/syscall.h
new file mode 100644
index 0000000..4ec506c
--- /dev/null
+++ b/linux-user/mipsn32/syscall.h
@@ -0,0 +1,221 @@
+
+/* this struct defines the way the registers are stored on the
+   stack during a system call. */
+
+struct target_pt_regs {
+	/* Saved main processor registers. */
+	target_ulong regs[32];
+
+	/* Saved special registers. */
+	target_ulong cp0_status;
+	target_ulong lo;
+	target_ulong hi;
+	target_ulong cp0_badvaddr;
+	target_ulong cp0_cause;
+	target_ulong cp0_epc;
+};
+
+/* Target errno definitions taken from asm-mips/errno.h */
+#undef TARGET_ENOMSG
+#define TARGET_ENOMSG          35      /* Identifier removed */
+#undef TARGET_EIDRM
+#define TARGET_EIDRM           36      /* Identifier removed */
+#undef TARGET_ECHRNG
+#define TARGET_ECHRNG          37      /* Channel number out of range */
+#undef TARGET_EL2NSYNC
+#define TARGET_EL2NSYNC        38      /* Level 2 not synchronized */
+#undef TARGET_EL3HLT
+#define TARGET_EL3HLT          39      /* Level 3 halted */
+#undef TARGET_EL3RST
+#define TARGET_EL3RST          40      /* Level 3 reset */
+#undef TARGET_ELNRNG
+#define TARGET_ELNRNG          41      /* Link number out of range */
+#undef TARGET_EUNATCH
+#define TARGET_EUNATCH         42      /* Protocol driver not attached */
+#undef TARGET_ENOCSI
+#define TARGET_ENOCSI          43      /* No CSI structure available */
+#undef TARGET_EL2HLT
+#define TARGET_EL2HLT          44      /* Level 2 halted */
+#undef TARGET_EDEADLK
+#define TARGET_EDEADLK         45      /* Resource deadlock would occur */
+#undef TARGET_ENOLCK
+#define TARGET_ENOLCK          46      /* No record locks available */
+#undef TARGET_EBADE
+#define TARGET_EBADE           50      /* Invalid exchange */
+#undef TARGET_EBADR
+#define TARGET_EBADR           51      /* Invalid request descriptor */
+#undef TARGET_EXFULL
+#define TARGET_EXFULL          52      /* TARGET_Exchange full */
+#undef TARGET_ENOANO
+#define TARGET_ENOANO          53      /* No anode */
+#undef TARGET_EBADRQC
+#define TARGET_EBADRQC         54      /* Invalid request code */
+#undef TARGET_EBADSLT
+#define TARGET_EBADSLT         55      /* Invalid slot */
+#undef TARGET_EDEADLOCK
+#define TARGET_EDEADLOCK       56      /* File locking deadlock error */
+#undef TARGET_EBFONT
+#define TARGET_EBFONT          59      /* Bad font file format */
+#undef TARGET_ENOSTR
+#define TARGET_ENOSTR          60      /* Device not a stream */
+#undef TARGET_ENODATA
+#define TARGET_ENODATA         61      /* No data available */
+#undef TARGET_ETIME
+#define TARGET_ETIME           62      /* Timer expired */
+#undef TARGET_ENOSR
+#define TARGET_ENOSR           63      /* Out of streams resources */
+#undef TARGET_ENONET
+#define TARGET_ENONET          64      /* Machine is not on the network */
+#undef TARGET_ENOPKG
+#define TARGET_ENOPKG          65      /* Package not installed */
+#undef TARGET_EREMOTE
+#define TARGET_EREMOTE         66      /* Object is remote */
+#undef TARGET_ENOLINK
+#define TARGET_ENOLINK         67      /* Link has been severed */
+#undef TARGET_EADV
+#define TARGET_EADV            68      /* Advertise error */
+#undef TARGET_ESRMNT
+#define TARGET_ESRMNT          69      /* Srmount error */
+#undef TARGET_ECOMM
+#define TARGET_ECOMM           70      /* Communication error on send */
+#undef TARGET_EPROTO
+#define TARGET_EPROTO          71      /* Protocol error */
+#undef TARGET_EDOTDOT
+#define TARGET_EDOTDOT         73      /* RFS specific error */
+#undef TARGET_EMULTIHOP
+#define TARGET_EMULTIHOP       74      /* Multihop attempted */
+#undef TARGET_EBADMSG
+#define TARGET_EBADMSG         77      /* Not a data message */
+#undef TARGET_ENAMETOOLONG
+#define TARGET_ENAMETOOLONG    78      /* File name too long */
+#undef TARGET_EOVERFLOW
+#define TARGET_EOVERFLOW       79      /* Value too large for defined data type */
+#undef TARGET_ENOTUNIQ
+#define TARGET_ENOTUNIQ        80      /* Name not unique on network */
+#undef TARGET_EBADFD
+#define TARGET_EBADFD          81      /* File descriptor in bad state */
+#undef TARGET_EREMCHG
+#define TARGET_EREMCHG         82      /* Remote address changed */
+#undef TARGET_ELIBACC
+#define TARGET_ELIBACC         83      /* Can not access a needed shared library */
+#undef TARGET_ELIBBAD
+#define TARGET_ELIBBAD         84      /* Accessing a corrupted shared library */
+#undef TARGET_ELIBSCN
+#define TARGET_ELIBSCN         85      /* .lib section in a.out corrupted */
+#undef TARGET_ELIBMAX
+#define TARGET_ELIBMAX         86      /* Attempting to link in too many shared libraries */
+#undef TARGET_ELIBEXEC
+#define TARGET_ELIBEXEC        87      /* Cannot exec a shared library directly */
+#undef TARGET_EILSEQ
+#define TARGET_EILSEQ          88      /* Illegal byte sequence */
+#undef TARGET_ENOSYS
+#define TARGET_ENOSYS          89      /* Function not implemented */
+#undef TARGET_ELOOP
+#define TARGET_ELOOP           90      /* Too many symbolic links encountered */
+#undef TARGET_ERESTART
+#define TARGET_ERESTART        91      /* Interrupted system call should be restarted */
+#undef TARGET_ESTRPIPE
+#define TARGET_ESTRPIPE        92      /* Streams pipe error */
+#undef TARGET_ENOTEMPTY
+#define TARGET_ENOTEMPTY       93      /* Directory not empty */
+#undef TARGET_EUSERS
+#define TARGET_EUSERS          94      /* Too many users */
+#undef TARGET_ENOTSOCK
+#define TARGET_ENOTSOCK        95      /* Socket operation on non-socket */
+#undef TARGET_EDESTADDRREQ
+#define TARGET_EDESTADDRREQ    96      /* Destination address required */
+#undef TARGET_EMSGSIZE
+#define TARGET_EMSGSIZE        97      /* Message too long */
+#undef TARGET_EPROTOTYPE
+#define TARGET_EPROTOTYPE      98      /* Protocol wrong type for socket */
+#undef TARGET_ENOPROTOOPT
+#define TARGET_ENOPROTOOPT     99      /* Protocol not available */
+#undef TARGET_EPROTONOSUPPORT
+#define TARGET_EPROTONOSUPPORT 120     /* Protocol not supported */
+#undef TARGET_ESOCKTNOSUPPORT
+#define TARGET_ESOCKTNOSUPPORT 121     /* Socket type not supported */
+#undef TARGET_EOPNOTSUPP
+#define TARGET_EOPNOTSUPP      122     /* Operation not supported on transport endpoint */
+#undef TARGET_EPFNOSUPPORT
+#define TARGET_EPFNOSUPPORT    123     /* Protocol family not supported */
+#undef TARGET_EAFNOSUPPORT
+#define TARGET_EAFNOSUPPORT    124     /* Address family not supported by protocol */
+#undef TARGET_EADDRINUSE
+#define TARGET_EADDRINUSE      125     /* Address already in use */
+#undef TARGET_EADDRNOTAVAIL
+#define TARGET_EADDRNOTAVAIL   126     /* Cannot assign requested address */
+#undef TARGET_ENETDOWN
+#define TARGET_ENETDOWN        127     /* Network is down */
+#undef TARGET_ENETUNREACH
+#define TARGET_ENETUNREACH     128     /* Network is unreachable */
+#undef TARGET_ENETRESET
+#define TARGET_ENETRESET       129     /* Network dropped connection because of reset */
+#undef TARGET_ECONNABORTED
+#define TARGET_ECONNABORTED    130     /* Software caused connection abort */
+#undef TARGET_ECONNRESET
+#define TARGET_ECONNRESET      131     /* Connection reset by peer */
+#undef TARGET_ENOBUFS
+#define TARGET_ENOBUFS         132     /* No buffer space available */
+#undef TARGET_EISCONN
+#define TARGET_EISCONN         133     /* Transport endpoint is already connected */
+#undef TARGET_ENOTCONN
+#define TARGET_ENOTCONN        134     /* Transport endpoint is not connected */
+#undef TARGET_EUCLEAN
+#define TARGET_EUCLEAN         135     /* Structure needs cleaning */
+#undef TARGET_ENOTNAM
+#define TARGET_ENOTNAM         137     /* Not a XENIX named type file */
+#undef TARGET_ENAVAIL
+#define TARGET_ENAVAIL         138     /* No XENIX semaphores available */
+#undef TARGET_EISNAM
+#define TARGET_EISNAM          139     /* Is a named type file */
+#undef TARGET_EREMOTEIO
+#define TARGET_EREMOTEIO       140     /* Remote I/O error */
+#undef TARGET_EINIT
+#define TARGET_EINIT           141     /* Reserved */
+#undef TARGET_EREMDEV
+#define TARGET_EREMDEV         142     /* TARGET_Error 142 */
+#undef TARGET_ESHUTDOWN
+#define TARGET_ESHUTDOWN       143     /* Cannot send after transport endpoint shutdown */
+#undef TARGET_ETOOMANYREFS
+#define TARGET_ETOOMANYREFS    144     /* Too many references: cannot splice */
+#undef TARGET_ETIMEDOUT
+#define TARGET_ETIMEDOUT       145     /* Connection timed out */
+#undef TARGET_ECONNREFUSED
+#define TARGET_ECONNREFUSED    146     /* Connection refused */
+#undef TARGET_EHOSTDOWN
+#define TARGET_EHOSTDOWN       147     /* Host is down */
+#undef TARGET_EHOSTUNREACH
+#define TARGET_EHOSTUNREACH    148     /* No route to host */
+#undef TARGET_EALREADY
+#define TARGET_EALREADY        149     /* Operation already in progress */
+#undef TARGET_EINPROGRESS
+#define TARGET_EINPROGRESS     150     /* Operation now in progress */
+#undef TARGET_ESTALE
+#define TARGET_ESTALE          151     /* Stale NFS file handle */
+#undef TARGET_ECANCELED
+#define TARGET_ECANCELED       158     /* AIO operation canceled */
+/*
+ * These error are Linux extensions.
+ */
+#undef TARGET_ENOMEDIUM
+#define TARGET_ENOMEDIUM       159     /* No medium found */
+#undef TARGET_EMEDIUMTYPE
+#define TARGET_EMEDIUMTYPE     160     /* Wrong medium type */
+#undef TARGET_ENOKEY
+#define TARGET_ENOKEY          161     /* Required key not available */
+#undef TARGET_EKEYEXPIRED
+#define TARGET_EKEYEXPIRED     162     /* Key has expired */
+#undef TARGET_EKEYREVOKED
+#define TARGET_EKEYREVOKED     163     /* Key has been revoked */
+#undef TARGET_EKEYREJECTED
+#define TARGET_EKEYREJECTED    164     /* Key was rejected by service */
+
+/* for robust mutexes */
+#undef TARGET_EOWNERDEAD
+#define TARGET_EOWNERDEAD      165     /* Owner died */
+#undef TARGET_ENOTRECOVERABLE
+#define TARGET_ENOTRECOVERABLE 166     /* State not recoverable */
+
+
+
+#define UNAME_MACHINE "mips64"
diff --git a/linux-user/mipsn32/syscall_nr.h b/linux-user/mipsn32/syscall_nr.h
new file mode 100644
index 0000000..a83c4c9
--- /dev/null
+++ b/linux-user/mipsn32/syscall_nr.h
@@ -0,0 +1,288 @@
+/*
+ * Linux N32 syscalls are in the range from 6000 to 6999.
+ */
+#define TARGET_NR_Linux			6000
+#define TARGET_NR_read			(TARGET_NR_Linux +   0)
+#define TARGET_NR_write			(TARGET_NR_Linux +   1)
+#define TARGET_NR_open			(TARGET_NR_Linux +   2)
+#define TARGET_NR_close			(TARGET_NR_Linux +   3)
+#define TARGET_NR_stat			(TARGET_NR_Linux +   4)
+#define TARGET_NR_fstat			(TARGET_NR_Linux +   5)
+#define TARGET_NR_lstat			(TARGET_NR_Linux +   6)
+#define TARGET_NR_poll			(TARGET_NR_Linux +   7)
+#define TARGET_NR_lseek			(TARGET_NR_Linux +   8)
+#define TARGET_NR_mmap			(TARGET_NR_Linux +   9)
+#define TARGET_NR_mprotect			(TARGET_NR_Linux +  10)
+#define TARGET_NR_munmap			(TARGET_NR_Linux +  11)
+#define TARGET_NR_brk			(TARGET_NR_Linux +  12)
+#define TARGET_NR_rt_sigaction		(TARGET_NR_Linux +  13)
+#define TARGET_NR_rt_sigprocmask		(TARGET_NR_Linux +  14)
+#define TARGET_NR_ioctl			(TARGET_NR_Linux +  15)
+#define TARGET_NR_pread64			(TARGET_NR_Linux +  16)
+#define TARGET_NR_pwrite64			(TARGET_NR_Linux +  17)
+#define TARGET_NR_readv			(TARGET_NR_Linux +  18)
+#define TARGET_NR_writev			(TARGET_NR_Linux +  19)
+#define TARGET_NR_access			(TARGET_NR_Linux +  20)
+#define TARGET_NR_pipe			(TARGET_NR_Linux +  21)
+#define TARGET_NR__newselect			(TARGET_NR_Linux +  22)
+#define TARGET_NR_sched_yield		(TARGET_NR_Linux +  23)
+#define TARGET_NR_mremap			(TARGET_NR_Linux +  24)
+#define TARGET_NR_msync			(TARGET_NR_Linux +  25)
+#define TARGET_NR_mincore			(TARGET_NR_Linux +  26)
+#define TARGET_NR_madvise			(TARGET_NR_Linux +  27)
+#define TARGET_NR_shmget			(TARGET_NR_Linux +  28)
+#define TARGET_NR_shmat			(TARGET_NR_Linux +  29)
+#define TARGET_NR_shmctl			(TARGET_NR_Linux +  30)
+#define TARGET_NR_dup			(TARGET_NR_Linux +  31)
+#define TARGET_NR_dup2			(TARGET_NR_Linux +  32)
+#define TARGET_NR_pause			(TARGET_NR_Linux +  33)
+#define TARGET_NR_nanosleep			(TARGET_NR_Linux +  34)
+#define TARGET_NR_getitimer			(TARGET_NR_Linux +  35)
+#define TARGET_NR_setitimer			(TARGET_NR_Linux +  36)
+#define TARGET_NR_alarm			(TARGET_NR_Linux +  37)
+#define TARGET_NR_getpid			(TARGET_NR_Linux +  38)
+#define TARGET_NR_sendfile			(TARGET_NR_Linux +  39)
+#define TARGET_NR_socket			(TARGET_NR_Linux +  40)
+#define TARGET_NR_connect			(TARGET_NR_Linux +  41)
+#define TARGET_NR_accept			(TARGET_NR_Linux +  42)
+#define TARGET_NR_sendto			(TARGET_NR_Linux +  43)
+#define TARGET_NR_recvfrom			(TARGET_NR_Linux +  44)
+#define TARGET_NR_sendmsg			(TARGET_NR_Linux +  45)
+#define TARGET_NR_recvmsg			(TARGET_NR_Linux +  46)
+#define TARGET_NR_shutdown			(TARGET_NR_Linux +  47)
+#define TARGET_NR_bind			(TARGET_NR_Linux +  48)
+#define TARGET_NR_listen			(TARGET_NR_Linux +  49)
+#define TARGET_NR_getsockname		(TARGET_NR_Linux +  50)
+#define TARGET_NR_getpeername		(TARGET_NR_Linux +  51)
+#define TARGET_NR_socketpair			(TARGET_NR_Linux +  52)
+#define TARGET_NR_setsockopt			(TARGET_NR_Linux +  53)
+#define TARGET_NR_getsockopt			(TARGET_NR_Linux +  54)
+#define TARGET_NR_clone			(TARGET_NR_Linux +  55)
+#define TARGET_NR_fork			(TARGET_NR_Linux +  56)
+#define TARGET_NR_execve			(TARGET_NR_Linux +  57)
+#define TARGET_NR_exit			(TARGET_NR_Linux +  58)
+#define TARGET_NR_wait4			(TARGET_NR_Linux +  59)
+#define TARGET_NR_kill			(TARGET_NR_Linux +  60)
+#define TARGET_NR_uname			(TARGET_NR_Linux +  61)
+#define TARGET_NR_semget			(TARGET_NR_Linux +  62)
+#define TARGET_NR_semop			(TARGET_NR_Linux +  63)
+#define TARGET_NR_semctl			(TARGET_NR_Linux +  64)
+#define TARGET_NR_shmdt			(TARGET_NR_Linux +  65)
+#define TARGET_NR_msgget			(TARGET_NR_Linux +  66)
+#define TARGET_NR_msgsnd			(TARGET_NR_Linux +  67)
+#define TARGET_NR_msgrcv			(TARGET_NR_Linux +  68)
+#define TARGET_NR_msgctl			(TARGET_NR_Linux +  69)
+#define TARGET_NR_fcntl			(TARGET_NR_Linux +  70)
+#define TARGET_NR_flock			(TARGET_NR_Linux +  71)
+#define TARGET_NR_fsync			(TARGET_NR_Linux +  72)
+#define TARGET_NR_fdatasync			(TARGET_NR_Linux +  73)
+#define TARGET_NR_truncate			(TARGET_NR_Linux +  74)
+#define TARGET_NR_ftruncate			(TARGET_NR_Linux +  75)
+#define TARGET_NR_getdents			(TARGET_NR_Linux +  76)
+#define TARGET_NR_getcwd			(TARGET_NR_Linux +  77)
+#define TARGET_NR_chdir			(TARGET_NR_Linux +  78)
+#define TARGET_NR_fchdir			(TARGET_NR_Linux +  79)
+#define TARGET_NR_rename			(TARGET_NR_Linux +  80)
+#define TARGET_NR_mkdir			(TARGET_NR_Linux +  81)
+#define TARGET_NR_rmdir			(TARGET_NR_Linux +  82)
+#define TARGET_NR_creat			(TARGET_NR_Linux +  83)
+#define TARGET_NR_link			(TARGET_NR_Linux +  84)
+#define TARGET_NR_unlink			(TARGET_NR_Linux +  85)
+#define TARGET_NR_symlink			(TARGET_NR_Linux +  86)
+#define TARGET_NR_readlink			(TARGET_NR_Linux +  87)
+#define TARGET_NR_chmod			(TARGET_NR_Linux +  88)
+#define TARGET_NR_fchmod			(TARGET_NR_Linux +  89)
+#define TARGET_NR_chown			(TARGET_NR_Linux +  90)
+#define TARGET_NR_fchown			(TARGET_NR_Linux +  91)
+#define TARGET_NR_lchown			(TARGET_NR_Linux +  92)
+#define TARGET_NR_umask			(TARGET_NR_Linux +  93)
+#define TARGET_NR_gettimeofday		(TARGET_NR_Linux +  94)
+#define TARGET_NR_getrlimit			(TARGET_NR_Linux +  95)
+#define TARGET_NR_getrusage			(TARGET_NR_Linux +  96)
+#define TARGET_NR_sysinfo			(TARGET_NR_Linux +  97)
+#define TARGET_NR_times			(TARGET_NR_Linux +  98)
+#define TARGET_NR_ptrace			(TARGET_NR_Linux +  99)
+#define TARGET_NR_getuid			(TARGET_NR_Linux + 100)
+#define TARGET_NR_syslog			(TARGET_NR_Linux + 101)
+#define TARGET_NR_getgid			(TARGET_NR_Linux + 102)
+#define TARGET_NR_setuid			(TARGET_NR_Linux + 103)
+#define TARGET_NR_setgid			(TARGET_NR_Linux + 104)
+#define TARGET_NR_geteuid			(TARGET_NR_Linux + 105)
+#define TARGET_NR_getegid			(TARGET_NR_Linux + 106)
+#define TARGET_NR_setpgid			(TARGET_NR_Linux + 107)
+#define TARGET_NR_getppid			(TARGET_NR_Linux + 108)
+#define TARGET_NR_getpgrp			(TARGET_NR_Linux + 109)
+#define TARGET_NR_setsid			(TARGET_NR_Linux + 110)
+#define TARGET_NR_setreuid			(TARGET_NR_Linux + 111)
+#define TARGET_NR_setregid			(TARGET_NR_Linux + 112)
+#define TARGET_NR_getgroups			(TARGET_NR_Linux + 113)
+#define TARGET_NR_setgroups			(TARGET_NR_Linux + 114)
+#define TARGET_NR_setresuid			(TARGET_NR_Linux + 115)
+#define TARGET_NR_getresuid			(TARGET_NR_Linux + 116)
+#define TARGET_NR_setresgid			(TARGET_NR_Linux + 117)
+#define TARGET_NR_getresgid			(TARGET_NR_Linux + 118)
+#define TARGET_NR_getpgid			(TARGET_NR_Linux + 119)
+#define TARGET_NR_setfsuid			(TARGET_NR_Linux + 120)
+#define TARGET_NR_setfsgid			(TARGET_NR_Linux + 121)
+#define TARGET_NR_getsid			(TARGET_NR_Linux + 122)
+#define TARGET_NR_capget			(TARGET_NR_Linux + 123)
+#define TARGET_NR_capset			(TARGET_NR_Linux + 124)
+#define TARGET_NR_rt_sigpending		(TARGET_NR_Linux + 125)
+#define TARGET_NR_rt_sigtimedwait		(TARGET_NR_Linux + 126)
+#define TARGET_NR_rt_sigqueueinfo		(TARGET_NR_Linux + 127)
+#define TARGET_NR_rt_sigsuspend		(TARGET_NR_Linux + 128)
+#define TARGET_NR_sigaltstack		(TARGET_NR_Linux + 129)
+#define TARGET_NR_utime			(TARGET_NR_Linux + 130)
+#define TARGET_NR_mknod			(TARGET_NR_Linux + 131)
+#define TARGET_NR_personality		(TARGET_NR_Linux + 132)
+#define TARGET_NR_ustat			(TARGET_NR_Linux + 133)
+#define TARGET_NR_statfs			(TARGET_NR_Linux + 134)
+#define TARGET_NR_fstatfs			(TARGET_NR_Linux + 135)
+#define TARGET_NR_sysfs			(TARGET_NR_Linux + 136)
+#define TARGET_NR_getpriority		(TARGET_NR_Linux + 137)
+#define TARGET_NR_setpriority		(TARGET_NR_Linux + 138)
+#define TARGET_NR_sched_setparam		(TARGET_NR_Linux + 139)
+#define TARGET_NR_sched_getparam		(TARGET_NR_Linux + 140)
+#define TARGET_NR_sched_setscheduler		(TARGET_NR_Linux + 141)
+#define TARGET_NR_sched_getscheduler		(TARGET_NR_Linux + 142)
+#define TARGET_NR_sched_get_priority_max	(TARGET_NR_Linux + 143)
+#define TARGET_NR_sched_get_priority_min	(TARGET_NR_Linux + 144)
+#define TARGET_NR_sched_rr_get_interval	(TARGET_NR_Linux + 145)
+#define TARGET_NR_mlock			(TARGET_NR_Linux + 146)
+#define TARGET_NR_munlock			(TARGET_NR_Linux + 147)
+#define TARGET_NR_mlockall			(TARGET_NR_Linux + 148)
+#define TARGET_NR_munlockall			(TARGET_NR_Linux + 149)
+#define TARGET_NR_vhangup			(TARGET_NR_Linux + 150)
+#define TARGET_NR_pivot_root			(TARGET_NR_Linux + 151)
+#define TARGET_NR__sysctl			(TARGET_NR_Linux + 152)
+#define TARGET_NR_prctl			(TARGET_NR_Linux + 153)
+#define TARGET_NR_adjtimex			(TARGET_NR_Linux + 154)
+#define TARGET_NR_setrlimit			(TARGET_NR_Linux + 155)
+#define TARGET_NR_chroot			(TARGET_NR_Linux + 156)
+#define TARGET_NR_sync			(TARGET_NR_Linux + 157)
+#define TARGET_NR_acct			(TARGET_NR_Linux + 158)
+#define TARGET_NR_settimeofday		(TARGET_NR_Linux + 159)
+#define TARGET_NR_mount			(TARGET_NR_Linux + 160)
+#define TARGET_NR_umount2			(TARGET_NR_Linux + 161)
+#define TARGET_NR_swapon			(TARGET_NR_Linux + 162)
+#define TARGET_NR_swapoff			(TARGET_NR_Linux + 163)
+#define TARGET_NR_reboot			(TARGET_NR_Linux + 164)
+#define TARGET_NR_sethostname		(TARGET_NR_Linux + 165)
+#define TARGET_NR_setdomainname		(TARGET_NR_Linux + 166)
+#define TARGET_NR_create_module		(TARGET_NR_Linux + 167)
+#define TARGET_NR_init_module		(TARGET_NR_Linux + 168)
+#define TARGET_NR_delete_module		(TARGET_NR_Linux + 169)
+#define TARGET_NR_get_kernel_syms		(TARGET_NR_Linux + 170)
+#define TARGET_NR_query_module		(TARGET_NR_Linux + 171)
+#define TARGET_NR_quotactl			(TARGET_NR_Linux + 172)
+#define TARGET_NR_nfsservctl			(TARGET_NR_Linux + 173)
+#define TARGET_NR_getpmsg			(TARGET_NR_Linux + 174)
+#define TARGET_NR_putpmsg			(TARGET_NR_Linux + 175)
+#define TARGET_NR_afs_syscall		(TARGET_NR_Linux + 176)
+#define TARGET_NR_reserved177		(TARGET_NR_Linux + 177)
+#define TARGET_NR_gettid			(TARGET_NR_Linux + 178)
+#define TARGET_NR_readahead			(TARGET_NR_Linux + 179)
+#define TARGET_NR_setxattr			(TARGET_NR_Linux + 180)
+#define TARGET_NR_lsetxattr			(TARGET_NR_Linux + 181)
+#define TARGET_NR_fsetxattr			(TARGET_NR_Linux + 182)
+#define TARGET_NR_getxattr			(TARGET_NR_Linux + 183)
+#define TARGET_NR_lgetxattr			(TARGET_NR_Linux + 184)
+#define TARGET_NR_fgetxattr			(TARGET_NR_Linux + 185)
+#define TARGET_NR_listxattr			(TARGET_NR_Linux + 186)
+#define TARGET_NR_llistxattr			(TARGET_NR_Linux + 187)
+#define TARGET_NR_flistxattr			(TARGET_NR_Linux + 188)
+#define TARGET_NR_removexattr		(TARGET_NR_Linux + 189)
+#define TARGET_NR_lremovexattr		(TARGET_NR_Linux + 190)
+#define TARGET_NR_fremovexattr		(TARGET_NR_Linux + 191)
+#define TARGET_NR_tkill			(TARGET_NR_Linux + 192)
+#define TARGET_NR_reserved193		(TARGET_NR_Linux + 193)
+#define TARGET_NR_futex			(TARGET_NR_Linux + 194)
+#define TARGET_NR_sched_setaffinity		(TARGET_NR_Linux + 195)
+#define TARGET_NR_sched_getaffinity		(TARGET_NR_Linux + 196)
+#define TARGET_NR_cacheflush			(TARGET_NR_Linux + 197)
+#define TARGET_NR_cachectl			(TARGET_NR_Linux + 198)
+#define TARGET_NR_sysmips			(TARGET_NR_Linux + 199)
+#define TARGET_NR_io_setup			(TARGET_NR_Linux + 200)
+#define TARGET_NR_io_destroy			(TARGET_NR_Linux + 201)
+#define TARGET_NR_io_getevents		(TARGET_NR_Linux + 202)
+#define TARGET_NR_io_submit			(TARGET_NR_Linux + 203)
+#define TARGET_NR_io_cancel			(TARGET_NR_Linux + 204)
+#define TARGET_NR_exit_group			(TARGET_NR_Linux + 205)
+#define TARGET_NR_lookup_dcookie		(TARGET_NR_Linux + 206)
+#define TARGET_NR_epoll_create		(TARGET_NR_Linux + 207)
+#define TARGET_NR_epoll_ctl			(TARGET_NR_Linux + 208)
+#define TARGET_NR_epoll_wait			(TARGET_NR_Linux + 209)
+#define TARGET_NR_remap_file_pages		(TARGET_NR_Linux + 210)
+#define TARGET_NR_rt_sigreturn		(TARGET_NR_Linux + 211)
+#define TARGET_NR_fcntl64			(TARGET_NR_Linux + 212)
+#define TARGET_NR_set_tid_address		(TARGET_NR_Linux + 213)
+#define TARGET_NR_restart_syscall		(TARGET_NR_Linux + 214)
+#define TARGET_NR_semtimedop			(TARGET_NR_Linux + 215)
+#define TARGET_NR_fadvise64			(TARGET_NR_Linux + 216)
+#define TARGET_NR_statfs64			(TARGET_NR_Linux + 217)
+#define TARGET_NR_fstatfs64			(TARGET_NR_Linux + 218)
+#define TARGET_NR_sendfile64			(TARGET_NR_Linux + 219)
+#define TARGET_NR_timer_create		(TARGET_NR_Linux + 220)
+#define TARGET_NR_timer_settime		(TARGET_NR_Linux + 221)
+#define TARGET_NR_timer_gettime		(TARGET_NR_Linux + 222)
+#define TARGET_NR_timer_getoverrun		(TARGET_NR_Linux + 223)
+#define TARGET_NR_timer_delete		(TARGET_NR_Linux + 224)
+#define TARGET_NR_clock_settime		(TARGET_NR_Linux + 225)
+#define TARGET_NR_clock_gettime		(TARGET_NR_Linux + 226)
+#define TARGET_NR_clock_getres		(TARGET_NR_Linux + 227)
+#define TARGET_NR_clock_nanosleep		(TARGET_NR_Linux + 228)
+#define TARGET_NR_tgkill			(TARGET_NR_Linux + 229)
+#define TARGET_NR_utimes			(TARGET_NR_Linux + 230)
+#define TARGET_NR_mbind			(TARGET_NR_Linux + 231)
+#define TARGET_NR_get_mempolicy		(TARGET_NR_Linux + 232)
+#define TARGET_NR_set_mempolicy		(TARGET_NR_Linux + 233)
+#define TARGET_NR_mq_open			(TARGET_NR_Linux + 234)
+#define TARGET_NR_mq_unlink			(TARGET_NR_Linux + 235)
+#define TARGET_NR_mq_timedsend		(TARGET_NR_Linux + 236)
+#define TARGET_NR_mq_timedreceive		(TARGET_NR_Linux + 237)
+#define TARGET_NR_mq_notify			(TARGET_NR_Linux + 238)
+#define TARGET_NR_mq_getsetattr		(TARGET_NR_Linux + 239)
+#define TARGET_NR_vserver			(TARGET_NR_Linux + 240)
+#define TARGET_NR_waitid			(TARGET_NR_Linux + 241)
+/* #define TARGET_NR_sys_setaltroot		(TARGET_NR_Linux + 242) */
+#define TARGET_NR_add_key			(TARGET_NR_Linux + 243)
+#define TARGET_NR_request_key		(TARGET_NR_Linux + 244)
+#define TARGET_NR_keyctl			(TARGET_NR_Linux + 245)
+#define TARGET_NR_set_thread_area		(TARGET_NR_Linux + 246)
+#define TARGET_NR_inotify_init		(TARGET_NR_Linux + 247)
+#define TARGET_NR_inotify_add_watch		(TARGET_NR_Linux + 248)
+#define TARGET_NR_inotify_rm_watch		(TARGET_NR_Linux + 249)
+#define TARGET_NR_migrate_pages		(TARGET_NR_Linux + 250)
+#define TARGET_NR_openat			(TARGET_NR_Linux + 251)
+#define TARGET_NR_mkdirat			(TARGET_NR_Linux + 252)
+#define TARGET_NR_mknodat			(TARGET_NR_Linux + 253)
+#define TARGET_NR_fchownat			(TARGET_NR_Linux + 254)
+#define TARGET_NR_futimesat			(TARGET_NR_Linux + 255)
+#define TARGET_NR_newfstatat			(TARGET_NR_Linux + 256)
+#define TARGET_NR_unlinkat			(TARGET_NR_Linux + 257)
+#define TARGET_NR_renameat			(TARGET_NR_Linux + 258)
+#define TARGET_NR_linkat			(TARGET_NR_Linux + 259)
+#define TARGET_NR_symlinkat			(TARGET_NR_Linux + 260)
+#define TARGET_NR_readlinkat			(TARGET_NR_Linux + 261)
+#define TARGET_NR_fchmodat			(TARGET_NR_Linux + 262)
+#define TARGET_NR_faccessat			(TARGET_NR_Linux + 263)
+#define TARGET_NR_pselect6			(TARGET_NR_Linux + 264)
+#define TARGET_NR_ppoll			(TARGET_NR_Linux + 265)
+#define TARGET_NR_unshare			(TARGET_NR_Linux + 266)
+#define TARGET_NR_splice			(TARGET_NR_Linux + 267)
+#define TARGET_NR_sync_file_range		(TARGET_NR_Linux + 268)
+#define TARGET_NR_tee			(TARGET_NR_Linux + 269)
+#define TARGET_NR_vmsplice			(TARGET_NR_Linux + 270)
+#define TARGET_NR_move_pages			(TARGET_NR_Linux + 271)
+#define TARGET_NR_set_robust_list		(TARGET_NR_Linux + 272)
+#define TARGET_NR_get_robust_list		(TARGET_NR_Linux + 273)
+#define TARGET_NR_kexec_load			(TARGET_NR_Linux + 274)
+#define TARGET_NR_getcpu			(TARGET_NR_Linux + 275)
+#define TARGET_NR_epoll_pwait		(TARGET_NR_Linux + 276)
+#define TARGET_NR_ioprio_set			(TARGET_NR_Linux + 277)
+#define TARGET_NR_ioprio_get			(TARGET_NR_Linux + 278)
+#define TARGET_NR_utimensat			(TARGET_NR_Linux + 279)
+#define TARGET_NR_signalfd			(TARGET_NR_Linux + 280)
+#define TARGET_NR_timerfd			(TARGET_NR_Linux + 281)
+#define TARGET_NR_eventfd			(TARGET_NR_Linux + 282)
+#define TARGET_NR_fallocate			(TARGET_NR_Linux + 283)
diff --git a/linux-user/mipsn32/target_signal.h b/linux-user/mipsn32/target_signal.h
new file mode 100644
index 0000000..4adf726
--- /dev/null
+++ b/linux-user/mipsn32/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	int32_t ss_sp;
+	uint32_t ss_size;
+	int32_t ss_flags;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline target_ulong get_sp_from_cpustate(CPUMIPSState *state)
+{
+    return state->gpr[29][state->current_tc];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/mipsn32/termbits.h b/linux-user/mipsn32/termbits.h
new file mode 100644
index 0000000..d3a6cf8
--- /dev/null
+++ b/linux-user/mipsn32/termbits.h
@@ -0,0 +1,245 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 23
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_line;                    /* line discipline */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK  0000001
+#define TARGET_BRKINT  0000002
+#define TARGET_IGNPAR  0000004
+#define TARGET_PARMRK  0000010
+#define TARGET_INPCK   0000020
+#define TARGET_ISTRIP  0000040
+#define TARGET_INLCR   0000100
+#define TARGET_IGNCR   0000200
+#define TARGET_ICRNL   0000400
+#define TARGET_IUCLC   0001000
+#define TARGET_IXON    0002000
+#define TARGET_IXANY   0004000
+#define TARGET_IXOFF   0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8   0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST   0000001
+#define TARGET_OLCUC   0000002
+#define TARGET_ONLCR   0000004
+#define TARGET_OCRNL   0000010
+#define TARGET_ONOCR   0000020
+#define TARGET_ONLRET  0000040
+#define TARGET_OFILL   0000100
+#define TARGET_OFDEL   0000200
+#define TARGET_NLDLY   0000400
+#define   TARGET_NL0   0000000
+#define   TARGET_NL1   0000400
+#define TARGET_CRDLY   0003000
+#define   TARGET_CR0   0000000
+#define   TARGET_CR1   0001000
+#define   TARGET_CR2   0002000
+#define   TARGET_CR3   0003000
+#define TARGET_TABDLY  0014000
+#define   TARGET_TAB0  0000000
+#define   TARGET_TAB1  0004000
+#define   TARGET_TAB2  0010000
+#define   TARGET_TAB3  0014000
+#define   TARGET_XTABS 0014000
+#define TARGET_BSDLY   0020000
+#define   TARGET_BS0   0000000
+#define   TARGET_BS1   0020000
+#define TARGET_VTDLY   0040000
+#define   TARGET_VT0   0000000
+#define   TARGET_VT1   0040000
+#define TARGET_FFDLY   0100000
+#define   TARGET_FF0   0000000
+#define   TARGET_FF1   0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD   0010017
+#define  TARGET_B0     0000000         /* hang up */
+#define  TARGET_B50    0000001
+#define  TARGET_B75    0000002
+#define  TARGET_B110   0000003
+#define  TARGET_B134   0000004
+#define  TARGET_B150   0000005
+#define  TARGET_B200   0000006
+#define  TARGET_B300   0000007
+#define  TARGET_B600   0000010
+#define  TARGET_B1200  0000011
+#define  TARGET_B1800  0000012
+#define  TARGET_B2400  0000013
+#define  TARGET_B4800  0000014
+#define  TARGET_B9600  0000015
+#define  TARGET_B19200 0000016
+#define  TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE   0000060
+#define   TARGET_CS5   0000000
+#define   TARGET_CS6   0000020
+#define   TARGET_CS7   0000040
+#define   TARGET_CS8   0000060
+#define TARGET_CSTOPB  0000100
+#define TARGET_CREAD   0000200
+#define TARGET_PARENB  0000400
+#define TARGET_PARODD  0001000
+#define TARGET_HUPCL   0002000
+#define TARGET_CLOCAL  0004000
+#define TARGET_CBAUDEX 0010000
+#define  TARGET_BOTHER   0010000
+#define  TARGET_B57600   0010001
+#define  TARGET_B115200  0010002
+#define  TARGET_B230400  0010003
+#define  TARGET_B460800  0010004
+#define  TARGET_B500000  0010005
+#define  TARGET_B576000  0010006
+#define  TARGET_B921600  0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD    002003600000  /* input baud rate (not used) */
+#define TARGET_CMSPAR    010000000000  /* mark or space (stick) parity */
+#define TARGET_CRTSCTS   020000000000  /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG    0000001
+#define TARGET_ICANON  0000002
+#define TARGET_XCASE   0000004
+#define TARGET_ECHO    0000010
+#define TARGET_ECHOE   0000020
+#define TARGET_ECHOK   0000040
+#define TARGET_ECHONL  0000100
+#define TARGET_NOFLSH  0000200
+#define TARGET_IEXTEN  0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE  0004000
+#define TARGET_FLUSHO  0010000
+#define TARGET_PENDIN  0040000
+#define TARGET_TOSTOP  0100000
+#define TARGET_ITOSTOP TARGET_TOSTOP
+
+/* c_cc character offsets */
+#define TARGET_VINTR	0
+#define TARGET_VQUIT	1
+#define TARGET_VERASE	2
+#define TARGET_VKILL	3
+#define TARGET_VMIN	4
+#define TARGET_VTIME	5
+#define TARGET_VEOL2	6
+#define TARGET_VSWTC	7
+#define TARGET_VSTART	8
+#define TARGET_VSTOP	9
+#define TARGET_VSUSP	10
+/* VDSUSP not supported */
+#define TARGET_VREPRINT	12
+#define TARGET_VDISCARD	13
+#define TARGET_VWERASE	14
+#define TARGET_VLNEXT	15
+#define TARGET_VEOF	16
+#define TARGET_VEOL	17
+
+/* ioctls */
+
+#define TARGET_TCGETA		0x5401
+#define TARGET_TCSETA		0x5402	/* Clashes with SNDCTL_TMR_START sound ioctl */
+#define TARGET_TCSETAW		0x5403
+#define TARGET_TCSETAF		0x5404
+
+#define TARGET_TCSBRK		0x5405
+#define TARGET_TCXONC		0x5406
+#define TARGET_TCFLSH		0x5407
+
+#define TARGET_TCGETS		0x540d
+#define TARGET_TCSETS		0x540e
+#define TARGET_TCSETSW		0x540f
+#define TARGET_TCSETSF		0x5410
+
+#define TARGET_TIOCEXCL	0x740d		/* set exclusive use of tty */
+#define TARGET_TIOCNXCL	0x740e		/* reset exclusive use of tty */
+#define TARGET_TIOCOUTQ	0x7472		/* output queue size */
+#define TARGET_TIOCSTI	0x5472		/* simulate terminal input */
+#define TARGET_TIOCMGET	0x741d		/* get all modem bits */
+#define TARGET_TIOCMBIS	0x741b		/* bis modem bits */
+#define TARGET_TIOCMBIC	0x741c		/* bic modem bits */
+#define TARGET_TIOCMSET	0x741a		/* set all modem bits */
+#define TARGET_TIOCPKT		0x5470		/* pty: set/clear packet mode */
+#define	 TARGET_TIOCPKT_DATA		0x00	/* data packet */
+#define	 TARGET_TIOCPKT_FLUSHREAD	0x01	/* flush packet */
+#define	 TARGET_TIOCPKT_FLUSHWRITE	0x02	/* flush packet */
+#define	 TARGET_TIOCPKT_STOP		0x04	/* stop output */
+#define	 TARGET_TIOCPKT_START		0x08	/* start output */
+#define	 TARGET_TIOCPKT_NOSTOP		0x10	/* no more ^S, ^Q */
+#define	 TARGET_TIOCPKT_DOSTOP		0x20	/* now do ^S ^Q */
+/* #define  TIOCPKT_IOCTL		0x40	state change of pty driver */
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct winsize)	/* set window size */
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct winsize)	/* get window size */
+#define TARGET_TIOCNOTTY	0x5471		/* void tty association */
+#define TARGET_TIOCSETD	0x7401
+#define TARGET_TIOCGETD	0x7400
+
+#define TARGET_FIOCLEX		0x6601
+#define TARGET_FIONCLEX	0x6602
+#define TARGET_FIOASYNC	0x667d
+#define TARGET_FIONBIO		0x667e
+#define TARGET_FIOQSIZE	0x667f
+
+#define TARGET_TIOCGLTC	0x7474			/* get special local chars */
+#define TARGET_TIOCSLTC	0x7475			/* set special local chars */
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 118, int)	/* set pgrp of tty */
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 119, int)	/* get pgrp of tty */
+#define TARGET_TIOCCONS	TARGET_IOW('t', 120, int)	/* become virtual console */
+
+#define TARGET_FIONREAD	0x467f
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+
+#define TARGET_TIOCGETP        0x7408
+#define TARGET_TIOCSETP        0x7409
+#define TARGET_TIOCSETN        0x740a			/* TIOCSETP wo flush */
+
+/* #define TARGET_TIOCSETA	TARGET_IOW('t', 20, struct termios) set termios struct */
+/* #define TARGET_TIOCSETAW	TARGET_IOW('t', 21, struct termios) drain output, set */
+/* #define TARGET_TIOCSETAF	TARGET_IOW('t', 22, struct termios) drn out, fls in, set */
+/* #define TARGET_TIOCGETD	TARGET_IOR('t', 26, int)	get line discipline */
+/* #define TARGET_TIOCSETD	TARGET_IOW('t', 27, int)	set line discipline */
+						/* 127-124 compat */
+
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x7416  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+/* I hope the range from 0x5480 on is free ... */
+#define TARGET_TIOCSCTTY	0x5480		/* become controlling tty */
+#define TARGET_TIOCGSOFTCAR	0x5481
+#define TARGET_TIOCSSOFTCAR	0x5482
+#define TARGET_TIOCLINUX	0x5483
+#define TARGET_TIOCGSERIAL	0x5484
+#define TARGET_TIOCSSERIAL	0x5485
+#define TARGET_TCSBRKP		0x5486	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSERCONFIG	0x5488
+#define TARGET_TIOCSERGWILD	0x5489
+#define TARGET_TIOCSERSWILD	0x548a
+#define TARGET_TIOCGLCKTRMIOS	0x548b
+#define TARGET_TIOCSLCKTRMIOS	0x548c
+#define TARGET_TIOCSERGSTRUCT	0x548d /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x548e /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */
+#define TARGET_TIOCMIWAIT      0x5491 /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT     0x5492 /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP	0x5493 /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP	0x5494 /* Set Hayes ESP configuration */
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
index cbaa7ce..ea916b8 100644
--- a/linux-user/mmap.c
+++ b/linux-user/mmap.c
@@ -1,6 +1,6 @@
 /*
  *  mmap support for qemu
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -36,7 +36,8 @@
     int prot1, ret;
 
 #ifdef DEBUG_MMAP
-    printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
+    printf("mprotect: start=0x" TARGET_FMT_lx
+	   "len=0x" TARGET_FMT_lx " prot=%c%c%c\n", start, len,
            prot & PROT_READ ? 'r' : '-',
            prot & PROT_WRITE ? 'w' : '-',
            prot & PROT_EXEC ? 'x' : '-');
@@ -52,7 +53,7 @@
         return -EINVAL;
     if (len == 0)
         return 0;
-    
+
     host_start = start & qemu_host_page_mask;
     host_end = HOST_PAGE_ALIGN(end);
     if (start > host_start) {
@@ -77,13 +78,13 @@
         for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
             prot1 |= page_get_flags(addr);
         }
-        ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size, 
+        ret = mprotect(g2h(host_end - qemu_host_page_size), qemu_host_page_size,
                        prot1 & PAGE_BITS);
         if (ret != 0)
             return ret;
         host_end -= qemu_host_page_size;
     }
-    
+
     /* handle the pages in the middle */
     if (host_start < host_end) {
         ret = mprotect(g2h(host_start), host_end - host_start, prot);
@@ -95,8 +96,8 @@
 }
 
 /* map an incomplete host page */
-static int mmap_frag(target_ulong real_start, 
-                     target_ulong start, target_ulong end, 
+static int mmap_frag(target_ulong real_start,
+                     target_ulong start, target_ulong end,
                      int prot, int flags, int fd, target_ulong offset)
 {
     target_ulong real_end, ret, addr;
@@ -112,10 +113,10 @@
         if (addr < start || addr >= end)
             prot1 |= page_get_flags(addr);
     }
-    
+
     if (prot1 == 0) {
         /* no page was there, so we allocate one */
-        ret = (long)mmap(host_start, qemu_host_page_size, prot, 
+        ret = (long)mmap(host_start, qemu_host_page_size, prot,
                          flags | MAP_ANONYMOUS, -1, 0);
         if (ret == -1)
             return ret;
@@ -134,10 +135,10 @@
         /* adjust protection to be able to read */
         if (!(prot1 & PROT_WRITE))
             mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
-        
+
         /* read the corresponding file data */
         pread(fd, g2h(start), end - start, offset);
-        
+
         /* put final protection */
         if (prot_new != (prot1 | PROT_WRITE))
             mprotect(host_start, qemu_host_page_size, prot_new);
@@ -151,13 +152,13 @@
 }
 
 /* NOTE: all the constants are the HOST ones */
-long target_mmap(target_ulong start, target_ulong len, int prot, 
+target_long target_mmap(target_ulong start, target_ulong len, int prot,
                  int flags, int fd, target_ulong offset)
 {
     target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
-    long host_start;
+    unsigned long host_start;
 #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
-    defined(__ia64)
+        defined(__ia64) || defined(__mips__)
     static target_ulong last_start = 0x40000000;
 #elif defined(__CYGWIN__)
     /* Cygwin doesn't have a whole lot of address space.  */
@@ -166,8 +167,9 @@
 
 #ifdef DEBUG_MMAP
     {
-        printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
-               start, len, 
+        printf("mmap: start=0x" TARGET_FMT_lx
+	       " len=0x" TARGET_FMT_lx " prot=%c%c%c flags=",
+               start, len,
                prot & PROT_READ ? 'r' : '-',
                prot & PROT_WRITE ? 'w' : '-',
                prot & PROT_EXEC ? 'x' : '-');
@@ -186,7 +188,7 @@
             printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
             break;
         }
-        printf("fd=%d offset=%lx\n", fd, offset);
+        printf("fd=%d offset=" TARGET_FMT_lx "\n", fd, offset);
     }
 #endif
 
@@ -202,49 +204,74 @@
 
     if (!(flags & MAP_FIXED)) {
 #if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
-    defined(__ia64) || defined(__CYGWIN__)
-        /* tell the kenel to search at the same place as i386 */
+    defined(__ia64) || defined(__mips__) || defined(__CYGWIN__)
+        /* tell the kernel to search at the same place as i386 */
         if (real_start == 0) {
             real_start = last_start;
             last_start += HOST_PAGE_ALIGN(len);
         }
 #endif
-        if (0 && qemu_host_page_size != qemu_real_host_page_size) {
-            /* NOTE: this code is only for debugging with '-p' option */
-            /* ??? Can also occur when TARGET_PAGE_SIZE > host page size.  */
-            /* reserve a memory area */
-            /* ??? This needs fixing for remapping.  */
-abort();
-            host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
-            real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE, 
-                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-            if (real_start == -1)
-                return real_start;
-            real_end = real_start + host_len;
-            start = HOST_PAGE_ALIGN(real_start);
-            end = start + HOST_PAGE_ALIGN(len);
-            if (start > real_start)
-                munmap((void *)real_start, start - real_start);
-            if (end < real_end)
-                munmap((void *)end, real_end - end);
-            /* use it as a fixed mapping */
-            flags |= MAP_FIXED;
-        } else {
-            /* if not fixed, no need to do anything */
             host_offset = offset & qemu_host_page_mask;
             host_len = len + offset - host_offset;
+
+        if (qemu_host_page_size > qemu_real_host_page_size) {
+            /*
+             * The guest expects to see mmapped areas aligned to it's pagesize.
+             * If the host's real page size is smaller than the guest's, we need
+             * to fixup the maps. It is done by allocating a larger area,
+             * displacing the map (if needed) and finally chopping off the spare
+             * room at the edges.
+             */
+
+            /*
+             * We assume qemu_host_page_size is always the same as
+             * TARGET_PAGE_SIZE, see exec.c. qemu_real_host_page_size is the
+             * hosts real page size.
+             */
+            target_ulong host_end;
+            unsigned long host_aligned_start;
+
+            host_len = HOST_PAGE_ALIGN(host_len + qemu_host_page_size
+                                       - qemu_real_host_page_size);
+            host_start = (unsigned long) mmap(real_start ?
+					      g2h(real_start) : NULL,
+					      host_len, prot, flags,
+					      fd, host_offset);
+            if (host_start == -1)
+                return -1;
+
+            host_end = host_start + host_len;
+
+            /* Find start and end, aligned to the targets pagesize with-in the
+               large mmaped area.  */
+            host_aligned_start = TARGET_PAGE_ALIGN(host_start);
+            if (!(flags & MAP_ANONYMOUS))
+                host_aligned_start += offset - host_offset;
+
+            start = h2g(host_aligned_start);
+            end = start + TARGET_PAGE_ALIGN(len);
+
+            /* Chop off the leftovers, if any.  */
+            if (host_aligned_start > host_start)
+                munmap((void *)host_start, host_aligned_start - host_start);
+            if (end < host_end)
+                munmap((void *)g2h(end), host_end - end);
+
+            goto the_end1;
+        } else {
+            /* if not fixed, no need to do anything */
             host_start = (long)mmap(real_start ? g2h(real_start) : NULL,
                                     host_len, prot, flags, fd, host_offset);
             if (host_start == -1)
-                return host_start;
+                return -1;
             /* update start so that it points to the file position at 'offset' */
-            if (!(flags & MAP_ANONYMOUS)) 
+            if (!(flags & MAP_ANONYMOUS))
                 host_start += offset - host_offset;
             start = h2g(host_start);
             goto the_end1;
         }
     }
-    
+
     if (start & ~TARGET_PAGE_MASK) {
         errno = EINVAL;
         return -1;
@@ -263,11 +290,11 @@
             errno = EINVAL;
             return -1;
         }
-        retaddr = target_mmap(start, len, prot | PROT_WRITE, 
-                              MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, 
+        retaddr = target_mmap(start, len, prot | PROT_WRITE,
+                              MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
                               -1, 0);
         if (retaddr == -1)
-            return retaddr;
+            return -1;
         pread(fd, g2h(start), len, offset);
         if (!(prot & PROT_WRITE)) {
             ret = target_mprotect(start, len, prot);
@@ -295,15 +322,15 @@
     }
     /* handle the end of the mapping */
     if (end < real_end) {
-        ret = mmap_frag(real_end - qemu_host_page_size, 
+        ret = mmap_frag(real_end - qemu_host_page_size,
                         real_end - qemu_host_page_size, real_end,
-                        prot, flags, fd, 
+                        prot, flags, fd,
                         offset + real_end - qemu_host_page_size - start);
         if (ret == -1)
-            return ret;
+            return -1;
         real_end -= qemu_host_page_size;
     }
-    
+
     /* map the middle (easier) */
     if (real_start < real_end) {
         unsigned long offset1;
@@ -311,16 +338,16 @@
 	  offset1 = 0;
 	else
 	  offset1 = offset + real_start - start;
-        ret = (long)mmap(g2h(real_start), real_end - real_start, 
+        ret = (long)mmap(g2h(real_start), real_end - real_start,
                          prot, flags, fd, offset1);
         if (ret == -1)
-            return ret;
+            return -1;
     }
  the_end1:
     page_set_flags(start, start + len, prot | PAGE_VALID);
  the_end:
 #ifdef DEBUG_MMAP
-    printf("ret=0x%lx\n", (long)start);
+    printf("ret=0x%llx\n", start);
     page_dump(stdout);
     printf("\n");
 #endif
@@ -367,10 +394,10 @@
         if (prot != 0)
             real_end -= qemu_host_page_size;
     }
-    
+
     /* unmap what we can */
     if (real_start < real_end) {
-        ret = munmap((void *)real_start, real_end - real_start);
+        ret = munmap(g2h(real_start), real_end - real_start);
         if (ret != 0)
             return ret;
     }
@@ -381,17 +408,18 @@
 
 /* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
    blocks which have been allocated starting on a host page */
-long target_mremap(target_ulong old_addr, target_ulong old_size, 
+target_long target_mremap(target_ulong old_addr, target_ulong old_size,
                    target_ulong new_size, unsigned long flags,
                    target_ulong new_addr)
 {
     int prot;
+    unsigned long host_addr;
 
     /* XXX: use 5 args syscall */
-    new_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags);
-    if (new_addr == -1)
-        return new_addr;
-    new_addr = h2g(new_addr);
+    host_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags);
+    if (host_addr == -1)
+        return -1;
+    new_addr = h2g(host_addr);
     prot = page_get_flags(old_addr);
     page_set_flags(old_addr, old_addr + old_size, 0);
     page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
@@ -410,7 +438,7 @@
         return -EINVAL;
     if (end == start)
         return 0;
-    
+
     start &= qemu_host_page_mask;
     return msync(g2h(start), end - start, flags);
 }
diff --git a/linux-user/path.c b/linux-user/path.c
index 7680970..7da0a8b 100644
--- a/linux-user/path.c
+++ b/linux-user/path.c
@@ -92,23 +92,6 @@
 	set_parents(child->entries[i], child);
 }
 
-void init_paths(const char *prefix)
-{
-    if (prefix[0] != '/' ||
-        prefix[0] == '\0' ||
-        !strcmp(prefix, "/"))
-        return;
-
-    base = new_entry("", NULL, prefix+1);
-    base = add_dir_maybe(base);
-    if (base->num_entries == 0) {
-        free (base);
-        base = NULL;
-    } else {
-        set_parents(base, base);
-    }
-}
-
 /* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
 static const char *
 follow_path(const struct pathelem *cursor, const char *name)
@@ -135,6 +118,35 @@
     return NULL;
 }
 
+void init_paths(const char *prefix)
+{
+    char pref_buf[PATH_MAX];
+
+    if (prefix[0] == '\0' ||
+        !strcmp(prefix, "/"))
+        return;
+
+    if (prefix[0] != '/') {
+        char *cwd = get_current_dir_name();
+	if (!cwd)
+            abort();
+	strcpy(pref_buf, cwd);
+        strcat(pref_buf, "/");
+        strcat(pref_buf, prefix);
+        free(cwd);
+    } else
+        strcpy(pref_buf,prefix + 1);
+
+    base = new_entry("", NULL, pref_buf);
+    base = add_dir_maybe(base);
+    if (base->num_entries == 0) {
+        free (base);
+        base = NULL;
+    } else {
+        set_parents(base, base);
+    }
+}
+
 /* Look for path in emulation dir, otherwise return name. */
 const char *path(const char *name)
 {
diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h
index eea8a7c..bf6b21b 100644
--- a/linux-user/ppc/syscall.h
+++ b/linux-user/ppc/syscall.h
@@ -1,6 +1,6 @@
 /*
  *  PPC emulation for qemu: syscall definitions.
- * 
+ *
  *  Copyright (c) 2003 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
@@ -51,80 +51,4 @@
  * flags masks
  */
 
-/* ipcs */
-
-#define TARGET_SEMOP           1
-#define TARGET_SEMGET          2
-#define TARGET_SEMCTL          3 
-#define TARGET_MSGSND          11 
-#define TARGET_MSGRCV          12
-#define TARGET_MSGGET          13
-#define TARGET_MSGCTL          14
-#define TARGET_SHMAT           21
-#define TARGET_SHMDT           22
-#define TARGET_SHMGET          23
-#define TARGET_SHMCTL          24
-
-struct target_msgbuf {
-	int mtype;
-	char mtext[1];
-};
-
-struct target_ipc_kludge {
-	unsigned int	msgp;	/* Really (struct msgbuf *) */
-	int msgtyp;
-};	
-
-struct target_ipc_perm {
-	int	key;
-	unsigned short	uid;
-	unsigned short	gid;
-	unsigned short	cuid;
-	unsigned short	cgid;
-	unsigned short	mode;
-	unsigned short	seq;
-};
-
-struct target_msqid_ds {
-	struct target_ipc_perm	msg_perm;
-	unsigned int		msg_first;	/* really struct target_msg* */
-	unsigned int		msg_last;	/* really struct target_msg* */
-	unsigned int		msg_stime;	/* really target_time_t */
-	unsigned int		msg_rtime;	/* really target_time_t */
-	unsigned int		msg_ctime;	/* really target_time_t */
-	unsigned int		wwait;		/* really struct wait_queue* */
-	unsigned int		rwait;		/* really struct wait_queue* */
-	unsigned short		msg_cbytes;
-	unsigned short		msg_qnum;
-	unsigned short		msg_qbytes;
-	unsigned short		msg_lspid;
-	unsigned short		msg_lrpid;
-};
-
-struct target_shmid_ds {
-	struct target_ipc_perm	shm_perm;
-	int			shm_segsz;
-	unsigned int		shm_atime;	/* really target_time_t */
-	unsigned int		shm_dtime;	/* really target_time_t */
-	unsigned int		shm_ctime;	/* really target_time_t */
-	unsigned short		shm_cpid;
-	unsigned short		shm_lpid;
-	short			shm_nattch;
-	unsigned short		shm_npages;
-	unsigned long		*shm_pages;
-	void 			*attaches;	/* really struct shm_desc * */
-};
-
-#define TARGET_IPC_RMID	0
-#define TARGET_IPC_SET	1
-#define TARGET_IPC_STAT	2
-
-union target_semun {
-    int val;
-    unsigned int buf;	/* really struct semid_ds * */
-    unsigned int array; /* really unsigned short * */
-    unsigned int __buf;	/* really struct seminfo * */
-    unsigned int __pad;	/* really void* */
-};
-
 #define UNAME_MACHINE "ppc"
diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h
index b97189a..1e5ced7 100644
--- a/linux-user/ppc/syscall_nr.h
+++ b/linux-user/ppc/syscall_nr.h
@@ -256,3 +256,58 @@
 #define TARGET_NR_statfs64               252
 #define TARGET_NR_fstatfs64              253
 #define TARGET_NR_fadvise64_64           254
+#define TARGET_NR_rtas		255
+#define TARGET_NR_sys_debug_setcontext 256
+/* Number 257 is reserved for vserver */
+#define TARGET_NR_migrate_pages	258
+#define TARGET_NR_mbind		259
+#define TARGET_NR_get_mempolicy	260
+#define TARGET_NR_set_mempolicy	261
+#define TARGET_NR_mq_open		262
+#define TARGET_NR_mq_unlink		263
+#define TARGET_NR_mq_timedsend	264
+#define TARGET_NR_mq_timedreceive	265
+#define TARGET_NR_mq_notify		266
+#define TARGET_NR_mq_getsetattr	267
+#define TARGET_NR_kexec_load		268
+#define TARGET_NR_add_key		269
+#define TARGET_NR_request_key	270
+#define TARGET_NR_keyctl		271
+#define TARGET_NR_waitid		272
+#define TARGET_NR_ioprio_set		273
+#define TARGET_NR_ioprio_get		274
+#define TARGET_NR_inotify_init	275
+#define TARGET_NR_inotify_add_watch	276
+#define TARGET_NR_inotify_rm_watch	277
+#define TARGET_NR_spu_run		278
+#define TARGET_NR_spu_create		279
+#define TARGET_NR_pselect6		280
+#define TARGET_NR_ppoll		281
+#define TARGET_NR_unshare		282
+#define TARGET_NR_splice		283
+#define TARGET_NR_tee		284
+#define TARGET_NR_vmsplice		285
+#define TARGET_NR_openat		286
+#define TARGET_NR_mkdirat		287
+#define TARGET_NR_mknodat		288
+#define TARGET_NR_fchownat		289
+#define TARGET_NR_futimesat		290
+#define TARGET_NR_fstatat64		291
+#define TARGET_NR_unlinkat		292
+#define TARGET_NR_renameat		293
+#define TARGET_NR_linkat		294
+#define TARGET_NR_symlinkat		295
+#define TARGET_NR_readlinkat		296
+#define TARGET_NR_fchmodat		297
+#define TARGET_NR_faccessat		298
+#define TARGET_NR_get_robust_list	299
+#define TARGET_NR_set_robust_list	300
+#define TARGET_NR_move_pages		301
+#define TARGET_NR_getcpu		302
+#define TARGET_NR_epoll_pwait	303
+#define TARGET_NR_utimensat		304
+#define TARGET_NR_signalfd		305
+#define TARGET_NR_timerfd		306
+#define TARGET_NR_eventfd		307
+#define TARGET_NR_sync_file_range2	308
+#define TARGET_NR_fallocate		309
diff --git a/linux-user/ppc/target_signal.h b/linux-user/ppc/target_signal.h
new file mode 100644
index 0000000..80ad211
--- /dev/null
+++ b/linux-user/ppc/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline target_ulong get_sp_from_cpustate(CPUPPCState *state)
+{
+    return state->gpr[1];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/ppc/termbits.h b/linux-user/ppc/termbits.h
index 6326747..002de95 100644
--- a/linux-user/ppc/termbits.h
+++ b/linux-user/ppc/termbits.h
@@ -7,8 +7,8 @@
     unsigned int c_oflag;               /* output mode flags */
     unsigned int c_cflag;               /* control mode flags */
     unsigned int c_lflag;               /* local mode flags */
-    unsigned char c_line;                    /* line discipline */
     unsigned char c_cc[TARGET_NCCS];                /* control characters */
+    unsigned char c_line;                    /* line discipline */
     unsigned int c_ispeed;		/* input speed */
     unsigned int c_ospeed;		/* output speed */
 };
@@ -47,6 +47,7 @@
 #define TARGET_IXANY	0004000
 #define TARGET_IUCLC	0010000
 #define TARGET_IMAXBEL	0020000
+#define	TARGET_IUTF8	0040000
 
 /* c_oflag bits */
 #define TARGET_OPOST	0000001
@@ -69,6 +70,7 @@
 #define   TARGET_TAB1	00002000
 #define   TARGET_TAB2	00004000
 #define   TARGET_TAB3	00006000
+#define   TARGET_XTABS	00006000	/* required by POSIX to == TAB3 */
 #define TARGET_CRDLY	00030000
 #define   TARGET_CR0	00000000
 #define   TARGET_CR1	00010000
@@ -83,7 +85,6 @@
 #define TARGET_VTDLY	00200000
 #define   TARGET_VT0	00000000
 #define   TARGET_VT1	00200000
-#define TARGET_XTABS	01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
 
 /* c_cflag bit meaning */
 #define TARGET_CBAUD	0000377
@@ -135,7 +136,8 @@
 #define TARGET_HUPCL	00040000
 
 #define TARGET_CLOCAL	00100000
-#define TARGET_CRTSCTS	  020000000000		/* flow control */
+#define TARGET_CMSPAR	010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	020000000000		/* flow control */
 
 /* c_lflag bits */
 #define TARGET_ISIG	0x00000080
diff --git a/linux-user/ppc64/syscall.h b/linux-user/ppc64/syscall.h
new file mode 100644
index 0000000..c47e58a
--- /dev/null
+++ b/linux-user/ppc64/syscall.h
@@ -0,0 +1,130 @@
+/*
+ *  PPC emulation for qemu: syscall definitions.
+ *
+ *  Copyright (c) 2003 Jocelyn Mayer
+ *
+ * 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
+ */
+
+/* XXX: ABSOLUTELY BUGGY:
+ * for now, this is quite just a cut-and-paste from i386 target...
+ */
+
+/* default linux values for the selectors */
+#define __USER_DS	(1)
+
+struct target_pt_regs {
+	unsigned long gpr[32];
+	unsigned long nip;
+	unsigned long msr;
+	unsigned long orig_gpr3;	/* Used for restarting system calls */
+	unsigned long ctr;
+	unsigned long link;
+	unsigned long xer;
+	unsigned long ccr;
+	unsigned long mq;		/* 601 only (not used at present) */
+					/* Used on APUS to hold IPL value. */
+	unsigned long trap;		/* Reason for being here */
+	unsigned long dar;		/* Fault registers */
+	unsigned long dsisr;
+	unsigned long result; 		/* Result of a system call */
+};
+
+/* ioctls */
+struct target_revectored_struct {
+	target_ulong __map[8];			/* 256 bits */
+};
+
+/*
+ * flags masks
+ */
+
+/* ipcs */
+
+#define TARGET_SEMOP           1
+#define TARGET_SEMGET          2
+#define TARGET_SEMCTL          3
+#define TARGET_MSGSND          11
+#define TARGET_MSGRCV          12
+#define TARGET_MSGGET          13
+#define TARGET_MSGCTL          14
+#define TARGET_SHMAT           21
+#define TARGET_SHMDT           22
+#define TARGET_SHMGET          23
+#define TARGET_SHMCTL          24
+
+#if 0 // To make it compile, even if the definition in syscall.c is bugged
+struct target_msgbuf {
+	int mtype;
+	char mtext[1];
+};
+#endif
+
+struct target_ipc_kludge {
+	unsigned int	msgp;	/* Really (struct msgbuf *) */
+	int msgtyp;
+};
+
+#if 0 // To make it compile, even if the definition in syscall.c is bugged
+struct target_ipc_perm {
+	int	__key;
+	unsigned short	uid;
+	unsigned short	gid;
+	unsigned short	cuid;
+	unsigned short	cgid;
+	unsigned short	mode;
+	unsigned short	seq;
+};
+#endif
+
+#if 0 // To make it compile, even if the definition in syscall.c is bugged
+struct target_msqid_ds {
+	struct target_ipc_perm	msg_perm;
+	unsigned int		msg_first;	/* really struct target_msg* */
+	unsigned int		msg_last;	/* really struct target_msg* */
+	unsigned int		msg_stime;	/* really target_time_t */
+	unsigned int		msg_rtime;	/* really target_time_t */
+	unsigned int		msg_ctime;	/* really target_time_t */
+	unsigned int		wwait;		/* really struct wait_queue* */
+	unsigned int		rwait;		/* really struct wait_queue* */
+	unsigned short		msg_cbytes;
+	unsigned short		msg_qnum;
+	unsigned short		msg_qbytes;
+	unsigned short		msg_lspid;
+	unsigned short		msg_lrpid;
+};
+#endif
+
+#if 0 // To make it compile, even if the definition in syscall.c is bugged
+struct target_shmid_ds {
+	struct target_ipc_perm	shm_perm;
+	int			shm_segsz;
+	unsigned int		shm_atime;	/* really target_time_t */
+	unsigned int		shm_dtime;	/* really target_time_t */
+	unsigned int		shm_ctime;	/* really target_time_t */
+	unsigned short		shm_cpid;
+	unsigned short		shm_lpid;
+	short			shm_nattch;
+	unsigned short		shm_npages;
+	unsigned long		*shm_pages;
+	void 			*attaches;	/* really struct shm_desc * */
+};
+#endif
+
+#define TARGET_IPC_RMID	0
+#define TARGET_IPC_SET	1
+#define TARGET_IPC_STAT	2
+
+#define UNAME_MACHINE "ppc64"
diff --git a/linux-user/ppc64/syscall_nr.h b/linux-user/ppc64/syscall_nr.h
new file mode 100644
index 0000000..d78ce53
--- /dev/null
+++ b/linux-user/ppc64/syscall_nr.h
@@ -0,0 +1,313 @@
+/*
+ * This file contains the system call numbers.
+ */
+#define TARGET_NR_restart_syscall          0
+#define TARGET_NR_exit                     1
+#define TARGET_NR_fork                     2
+#define TARGET_NR_read                     3
+#define TARGET_NR_write                    4
+#define TARGET_NR_open                     5
+#define TARGET_NR_close                    6
+#define TARGET_NR_waitpid                  7
+#define TARGET_NR_creat                    8
+#define TARGET_NR_link                     9
+#define TARGET_NR_unlink                  10
+#define TARGET_NR_execve                  11
+#define TARGET_NR_chdir                   12
+#define TARGET_NR_time                    13
+#define TARGET_NR_mknod                   14
+#define TARGET_NR_chmod                   15
+#define TARGET_NR_lchown32                16
+#define TARGET_NR_break                   17
+#define TARGET_NR_oldstat                 18
+#define TARGET_NR_lseek                   19
+#define TARGET_NR_getpid                  20
+#define TARGET_NR_mount                   21
+#define TARGET_NR_umount                  22
+#define TARGET_NR_setuid32                23
+#define TARGET_NR_getuid32                24
+#define TARGET_NR_stime                   25
+#define TARGET_NR_ptrace                  26
+#define TARGET_NR_alarm                   27
+#define TARGET_NR_oldfstat                28
+#define TARGET_NR_pause                   29
+#define TARGET_NR_utime                   30
+#define TARGET_NR_stty                    31
+#define TARGET_NR_gtty                    32
+#define TARGET_NR_access                  33
+#define TARGET_NR_nice                    34
+#define TARGET_NR_ftime                   35
+#define TARGET_NR_sync                    36
+#define TARGET_NR_kill                    37
+#define TARGET_NR_rename                  38
+#define TARGET_NR_mkdir                   39
+#define TARGET_NR_rmdir                   40
+#define TARGET_NR_dup                     41
+#define TARGET_NR_pipe                    42
+#define TARGET_NR_times                   43
+#define TARGET_NR_prof                    44
+#define TARGET_NR_brk                     45
+#define TARGET_NR_setgid32                46
+#define TARGET_NR_getgid32                47
+#define TARGET_NR_signal                  48
+#define TARGET_NR_geteuid32               49
+#define TARGET_NR_getegid32               50
+#define TARGET_NR_acct                    51
+#define TARGET_NR_umount2                 52
+#define TARGET_NR_lock                    53
+#define TARGET_NR_ioctl                   54
+#define TARGET_NR_fcntl                   55
+#define TARGET_NR_mpx                     56
+#define TARGET_NR_setpgid                 57
+#define TARGET_NR_ulimit                  58
+#define TARGET_NR_oldolduname             59
+#define TARGET_NR_umask                   60
+#define TARGET_NR_chroot                  61
+#define TARGET_NR_ustat                   62
+#define TARGET_NR_dup2                    63
+#define TARGET_NR_getppid                 64
+#define TARGET_NR_getpgrp                 65
+#define TARGET_NR_setsid                  66
+#define TARGET_NR_sigaction               67
+#define TARGET_NR_sgetmask                68
+#define TARGET_NR_ssetmask                69
+#define TARGET_NR_setreuid32              70
+#define TARGET_NR_setregid32              71
+#define TARGET_NR_sigsuspend              72
+#define TARGET_NR_sigpending              73
+#define TARGET_NR_sethostname             74
+#define TARGET_NR_setrlimit               75
+#define TARGET_NR_getrlimit               76
+#define TARGET_NR_getrusage               77
+#define TARGET_NR_gettimeofday            78
+#define TARGET_NR_settimeofday            79
+#define TARGET_NR_getgroups32             80
+#define TARGET_NR_setgroups32             81
+#define TARGET_NR_select                  82
+#define TARGET_NR_symlink                 83
+#define TARGET_NR_oldlstat                84
+#define TARGET_NR_readlink                85
+#define TARGET_NR_uselib                  86
+#define TARGET_NR_swapon                  87
+#define TARGET_NR_reboot                  88
+#define TARGET_NR_readdir                 89
+#define TARGET_NR_mmap                    90
+#define TARGET_NR_munmap                  91
+#define TARGET_NR_truncate                92
+#define TARGET_NR_ftruncate               93
+#define TARGET_NR_fchmod                  94
+#define TARGET_NR_fchown32                95
+#define TARGET_NR_getpriority             96
+#define TARGET_NR_setpriority             97
+#define TARGET_NR_profil                  98
+#define TARGET_NR_statfs                  99
+#define TARGET_NR_fstatfs                100
+#define TARGET_NR_ioperm                 101
+#define TARGET_NR_socketcall             102
+#define TARGET_NR_syslog                 103
+#define TARGET_NR_setitimer              104
+#define TARGET_NR_getitimer              105
+#define TARGET_NR_stat                   106
+#define TARGET_NR_lstat                  107
+#define TARGET_NR_fstat                  108
+#define TARGET_NR_olduname               109
+#define TARGET_NR_iopl                   110
+#define TARGET_NR_vhangup                111
+#define TARGET_NR_idle                   112
+#define TARGET_NR_vm86                   113
+#define TARGET_NR_wait4                  114
+#define TARGET_NR_swapoff                115
+#define TARGET_NR_sysinfo                116
+#define TARGET_NR_ipc                    117
+#define TARGET_NR_fsync                  118
+#define TARGET_NR_sigreturn              119
+#define TARGET_NR_clone                  120
+#define TARGET_NR_setdomainname          121
+#define TARGET_NR_uname                  122
+#define TARGET_NR_modify_ldt             123
+#define TARGET_NR_adjtimex               124
+#define TARGET_NR_mprotect               125
+#define TARGET_NR_sigprocmask            126
+#define TARGET_NR_create_module          127
+#define TARGET_NR_init_module            128
+#define TARGET_NR_delete_module          129
+#define TARGET_NR_get_kernel_syms        130
+#define TARGET_NR_quotactl               131
+#define TARGET_NR_getpgid                132
+#define TARGET_NR_fchdir                 133
+#define TARGET_NR_bdflush                134
+#define TARGET_NR_sysfs                  135
+#define TARGET_NR_personality            136
+#define TARGET_NR_afs_syscall            137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid32             138
+#define TARGET_NR_setfsgid32             139
+#define TARGET_NR__llseek                140
+#define TARGET_NR_getdents               141
+#define TARGET_NR__newselect             142
+#define TARGET_NR_flock                  143
+#define TARGET_NR_msync                  144
+#define TARGET_NR_readv                  145
+#define TARGET_NR_writev                 146
+#define TARGET_NR_getsid                 147
+#define TARGET_NR_fdatasync              148
+#define TARGET_NR__sysctl                149
+#define TARGET_NR_mlock                  150
+#define TARGET_NR_munlock                151
+#define TARGET_NR_mlockall               152
+#define TARGET_NR_munlockall             153
+#define TARGET_NR_sched_setparam         154
+#define TARGET_NR_sched_getparam         155
+#define TARGET_NR_sched_setscheduler     156
+#define TARGET_NR_sched_getscheduler     157
+#define TARGET_NR_sched_yield            158
+#define TARGET_NR_sched_get_priority_max 159
+#define TARGET_NR_sched_get_priority_min 160
+#define TARGET_NR_sched_rr_get_interval  161
+#define TARGET_NR_nanosleep              162
+#define TARGET_NR_mremap                 163
+#define TARGET_NR_setresuid32            164
+#define TARGET_NR_getresuid32            165
+#define TARGET_NR_query_module           166
+#define TARGET_NR_poll                   167
+#define TARGET_NR_nfsservctl             168
+#define TARGET_NR_setresgid32            169
+#define TARGET_NR_getresgid32            170
+#define TARGET_NR_prctl                  171
+#define TARGET_NR_rt_sigreturn           172
+#define TARGET_NR_rt_sigaction           173
+#define TARGET_NR_rt_sigprocmask         174
+#define TARGET_NR_rt_sigpending          175
+#define TARGET_NR_rt_sigtimedwait        176
+#define TARGET_NR_rt_sigqueueinfo        177
+#define TARGET_NR_rt_sigsuspend          178
+#define TARGET_NR_pread64                179
+#define TARGET_NR_pwrite64               180
+#define TARGET_NR_chown32                181
+#define TARGET_NR_getcwd                 182
+#define TARGET_NR_capget                 183
+#define TARGET_NR_capset                 184
+#define TARGET_NR_sigaltstack            185
+#define TARGET_NR_sendfile               186
+#define TARGET_NR_getpmsg                187     /* some people actually want streams */
+#define TARGET_NR_putpmsg                188     /* some people actually want streams */
+#define TARGET_NR_vfork                  189
+#define TARGET_NR_ugetrlimit             190     /* SuS compliant getrlimit */
+#define TARGET_NR_readahead              191
+#define TARGET_NR_mmap2                  192
+#define TARGET_NR_truncate64             193
+#define TARGET_NR_ftruncate64            194
+#define TARGET_NR_stat64                 195
+#define TARGET_NR_lstat64                196
+#define TARGET_NR_fstat64                197
+#define TARGET_NR_pciconfig_read         198
+#define TARGET_NR_pciconfig_write        199
+#define TARGET_NR_pciconfig_iobase       200
+#define TARGET_NR_multiplexer            201
+#define TARGET_NR_getdents64             202
+#define TARGET_NR_pivot_root             203
+#define TARGET_NR_fcntl64                204
+#define TARGET_NR_madvise                205
+#define TARGET_NR_mincore                206
+#define TARGET_NR_gettid                 207
+#define TARGET_NR_tkill                  208
+#define TARGET_NR_setxattr               209
+#define TARGET_NR_lsetxattr              210
+#define TARGET_NR_fsetxattr              211
+#define TARGET_NR_getxattr               212
+#define TARGET_NR_lgetxattr              213
+#define TARGET_NR_fgetxattr              214
+#define TARGET_NR_listxattr              215
+#define TARGET_NR_llistxattr             216
+#define TARGET_NR_flistxattr             217
+#define TARGET_NR_removexattr            218
+#define TARGET_NR_lremovexattr           219
+#define TARGET_NR_fremovexattr           220
+#define TARGET_NR_futex                  221
+#define TARGET_NR_sched_setaffinity      222
+#define TARGET_NR_sched_getaffinity      223
+/* 224 currently unused */
+#define TARGET_NR_tuxcall                225
+#define TARGET_NR_sendfile64             226
+#define TARGET_NR_io_setup               227
+#define TARGET_NR_io_destroy             228
+#define TARGET_NR_io_getevents           229
+#define TARGET_NR_io_submit              230
+#define TARGET_NR_io_cancel              231
+#define TARGET_NR_set_tid_address        232
+#define TARGET_NR_fadvise64              233
+#define TARGET_NR_exit_group             234
+#define TARGET_NR_lookup_dcookie         235
+#define TARGET_NR_epoll_create           236
+#define TARGET_NR_epoll_ctl              237
+#define TARGET_NR_epoll_wait             238
+#define TARGET_NR_remap_file_pages       239
+#define TARGET_NR_timer_create           240
+#define TARGET_NR_timer_settime          241
+#define TARGET_NR_timer_gettime          242
+#define TARGET_NR_timer_getoverrun       243
+#define TARGET_NR_timer_delete           244
+#define TARGET_NR_clock_settime          245
+#define TARGET_NR_clock_gettime          246
+#define TARGET_NR_clock_getres           247
+#define TARGET_NR_clock_nanosleep        248
+#define TARGET_NR_swapcontext            249
+#define TARGET_NR_tgkill                 250
+#define TARGET_NR_utimes                 251
+#define TARGET_NR_statfs64               252
+#define TARGET_NR_fstatfs64              253
+#define TARGET_NR_fadvise64_64           254
+#define TARGET_NR_rtas		255
+#define TARGET_NR_sys_debug_setcontext 256
+/* Number 257 is reserved for vserver */
+#define TARGET_NR_migrate_pages	258
+#define TARGET_NR_mbind		259
+#define TARGET_NR_get_mempolicy	260
+#define TARGET_NR_set_mempolicy	261
+#define TARGET_NR_mq_open		262
+#define TARGET_NR_mq_unlink		263
+#define TARGET_NR_mq_timedsend	264
+#define TARGET_NR_mq_timedreceive	265
+#define TARGET_NR_mq_notify		266
+#define TARGET_NR_mq_getsetattr	267
+#define TARGET_NR_kexec_load		268
+#define TARGET_NR_add_key		269
+#define TARGET_NR_request_key	270
+#define TARGET_NR_keyctl		271
+#define TARGET_NR_waitid		272
+#define TARGET_NR_ioprio_set		273
+#define TARGET_NR_ioprio_get		274
+#define TARGET_NR_inotify_init	275
+#define TARGET_NR_inotify_add_watch	276
+#define TARGET_NR_inotify_rm_watch	277
+#define TARGET_NR_spu_run		278
+#define TARGET_NR_spu_create		279
+#define TARGET_NR_pselect6		280
+#define TARGET_NR_ppoll		281
+#define TARGET_NR_unshare		282
+#define TARGET_NR_splice		283
+#define TARGET_NR_tee		284
+#define TARGET_NR_vmsplice		285
+#define TARGET_NR_openat		286
+#define TARGET_NR_mkdirat		287
+#define TARGET_NR_mknodat		288
+#define TARGET_NR_fchownat		289
+#define TARGET_NR_futimesat		290
+#define TARGET_NR_newfstatat		291
+#define TARGET_NR_unlinkat		292
+#define TARGET_NR_renameat		293
+#define TARGET_NR_linkat		294
+#define TARGET_NR_symlinkat		295
+#define TARGET_NR_readlinkat		296
+#define TARGET_NR_fchmodat		297
+#define TARGET_NR_faccessat		298
+#define TARGET_NR_get_robust_list	299
+#define TARGET_NR_set_robust_list	300
+#define TARGET_NR_move_pages		301
+#define TARGET_NR_getcpu		302
+#define TARGET_NR_epoll_pwait	303
+#define TARGET_NR_utimensat		304
+#define TARGET_NR_signalfd		305
+#define TARGET_NR_timerfd		306
+#define TARGET_NR_eventfd		307
+#define TARGET_NR_sync_file_range2	308
+#define TARGET_NR_fallocate		309
diff --git a/linux-user/ppc64/target_signal.h b/linux-user/ppc64/target_signal.h
new file mode 100644
index 0000000..80ad211
--- /dev/null
+++ b/linux-user/ppc64/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+static inline target_ulong get_sp_from_cpustate(CPUPPCState *state)
+{
+    return state->gpr[1];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/ppc64/termbits.h b/linux-user/ppc64/termbits.h
new file mode 100644
index 0000000..41537ed
--- /dev/null
+++ b/linux-user/ppc64/termbits.h
@@ -0,0 +1,237 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+    unsigned int c_iflag;               /* input mode flags */
+    unsigned int c_oflag;               /* output mode flags */
+    unsigned int c_cflag;               /* control mode flags */
+    unsigned int c_lflag;               /* local mode flags */
+    unsigned char c_cc[TARGET_NCCS];                /* control characters */
+    unsigned char c_line;                    /* line discipline */
+    unsigned int c_ispeed;		/* input speed */
+    unsigned int c_ospeed;		/* output speed */
+};
+
+/* c_cc character offsets */
+#define TARGET_VINTR 	0
+#define TARGET_VQUIT 	1
+#define TARGET_VERASE 	2
+#define TARGET_VKILL	3
+#define TARGET_VEOF	4
+#define TARGET_VMIN	5
+#define TARGET_VEOL	6
+#define TARGET_VTIME	7
+#define TARGET_VEOL2	8
+#define TARGET_VSWTC	9
+
+#define TARGET_VWERASE 	10
+#define TARGET_VREPRINT	11
+#define TARGET_VSUSP    12
+#define TARGET_VSTART   13
+#define TARGET_VSTOP    14
+#define TARGET_VLNEXT   15
+#define TARGET_VDISCARD	16
+
+#define TARGET_IGNBRK	0000001
+#define TARGET_BRKINT	0000002
+#define TARGET_IGNPAR	0000004
+#define TARGET_PARMRK	0000010
+#define TARGET_INPCK	0000020
+#define TARGET_ISTRIP	0000040
+#define TARGET_INLCR	0000100
+#define TARGET_IGNCR	0000200
+#define TARGET_ICRNL	0000400
+#define TARGET_IXON	0001000
+#define TARGET_IXOFF	0002000
+#define TARGET_IXANY	0004000
+#define TARGET_IUCLC	0010000
+#define TARGET_IMAXBEL	0020000
+#define	TARGET_IUTF8	0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0000001
+#define TARGET_ONLCR	0000002
+#define TARGET_OLCUC	0000004
+
+#define TARGET_OCRNL	0000010
+#define TARGET_ONOCR	0000020
+#define TARGET_ONLRET	0000040
+
+#define TARGET_OFILL	00000100
+#define TARGET_OFDEL	00000200
+#define TARGET_NLDLY	00001400
+#define   TARGET_NL0	00000000
+#define   TARGET_NL1	00000400
+#define   TARGET_NL2	00001000
+#define   TARGET_NL3	00001400
+#define TARGET_TABDLY	00006000
+#define   TARGET_TAB0	00000000
+#define   TARGET_TAB1	00002000
+#define   TARGET_TAB2	00004000
+#define   TARGET_TAB3	00006000
+#define   TARGET_XTABS	00006000	/* required by POSIX to == TAB3 */
+#define TARGET_CRDLY	00030000
+#define   TARGET_CR0	00000000
+#define   TARGET_CR1	00010000
+#define   TARGET_CR2	00020000
+#define   TARGET_CR3	00030000
+#define TARGET_FFDLY	00040000
+#define   TARGET_FF0	00000000
+#define   TARGET_FF1	00040000
+#define TARGET_BSDLY	00100000
+#define   TARGET_BS0	00000000
+#define   TARGET_BS1	00100000
+#define TARGET_VTDLY	00200000
+#define   TARGET_VT0	00000000
+#define   TARGET_VT1	00200000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	0000377
+#define  TARGET_B0	0000000		/* hang up */
+#define  TARGET_B50	0000001
+#define  TARGET_B75	0000002
+#define  TARGET_B110	0000003
+#define  TARGET_B134	0000004
+#define  TARGET_B150	0000005
+#define  TARGET_B200	0000006
+#define  TARGET_B300	0000007
+#define  TARGET_B600	0000010
+#define  TARGET_B1200	0000011
+#define  TARGET_B1800	0000012
+#define  TARGET_B2400	0000013
+#define  TARGET_B4800	0000014
+#define  TARGET_B9600	0000015
+#define  TARGET_B19200	0000016
+#define  TARGET_B38400	0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CBAUDEX 0000000
+#define  TARGET_B57600   00020
+#define  TARGET_B115200  00021
+#define  TARGET_B230400  00022
+#define  TARGET_B460800  00023
+#define  TARGET_B500000  00024
+#define  TARGET_B576000  00025
+#define  TARGET_B921600  00026
+#define TARGET_B1000000  00027
+#define TARGET_B1152000  00030
+#define TARGET_B1500000  00031
+#define TARGET_B2000000  00032
+#define TARGET_B2500000  00033
+#define TARGET_B3000000  00034
+#define TARGET_B3500000  00035
+#define TARGET_B4000000  00036
+
+#define TARGET_CSIZE	00001400
+#define   TARGET_CS5	00000000
+#define   TARGET_CS6	00000400
+#define   TARGET_CS7	00001000
+#define   TARGET_CS8	00001400
+
+#define TARGET_CSTOPB	00002000
+#define TARGET_CREAD	00004000
+#define TARGET_PARENB	00010000
+#define TARGET_PARODD	00020000
+#define TARGET_HUPCL	00040000
+
+#define TARGET_CLOCAL	00100000
+#define TARGET_CMSPAR	010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	020000000000		/* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0x00000080
+#define TARGET_ICANON	0x00000100
+#define TARGET_XCASE	0x00004000
+#define TARGET_ECHO	0x00000008
+#define TARGET_ECHOE	0x00000002
+#define TARGET_ECHOK	0x00000004
+#define TARGET_ECHONL	0x00000010
+#define TARGET_NOFLSH	0x80000000
+#define TARGET_TOSTOP	0x00400000
+#define TARGET_ECHOCTL	0x00000040
+#define TARGET_ECHOPRT	0x00000020
+#define TARGET_ECHOKE	0x00000001
+#define TARGET_FLUSHO	0x00800000
+#define TARGET_PENDIN	0x20000000
+#define TARGET_IEXTEN	0x00000400
+
+/* ioctls */
+
+#define TARGET_FIOCLEX		TARGET_IO('f', 1)
+#define TARGET_FIONCLEX	        TARGET_IO('f', 2)
+#define TARGET_FIOASYNC	        TARGET_IOW('f', 125, int)
+#define TARGET_FIONBIO		TARGET_IOW('f', 126, int)
+#define TARGET_FIONREAD	        TARGET_IOR('f', 127, int)
+#define TARGET_TIOCINQ		TARGET_FIONREAD
+//#define TARGET_FIOQSIZE	        TARGET_IOR('f', 128, loff_t)
+
+#define TARGET_TCGETS		TARGET_IOR('t', 19, struct target_termios)
+#define TARGET_TCSETS		TARGET_IOW('t', 20, struct target_termios)
+#define TARGET_TCSETSW		TARGET_IOW('t', 21, struct target_termios)
+#define TARGET_TCSETSF		TARGET_IOW('t', 22, struct target_termios)
+
+#define TARGET_TCGETA		TARGET_IOR('t', 23, struct target_termio)
+#define TARGET_TCSETA		TARGET_IOW('t', 24, struct target_termio)
+#define TARGET_TCSETAW		TARGET_IOW('t', 25, struct target_termio)
+#define TARGET_TCSETAF		TARGET_IOW('t', 28, struct target_termio)
+
+#define TARGET_TCSBRK		TARGET_IO('t', 29)
+#define TARGET_TCXONC		TARGET_IO('t', 30)
+#define TARGET_TCFLSH		TARGET_IO('t', 31)
+
+#define TARGET_TIOCSWINSZ	TARGET_IOW('t', 103, struct target_winsize)
+#define TARGET_TIOCGWINSZ	TARGET_IOR('t', 104, struct target_winsize)
+#define	TARGET_TIOCSTART	TARGET_IO('t', 110)		/* start output, like ^Q */
+#define	TARGET_TIOCSTOP	TARGET_IO('t', 111)		/* stop output, like ^S */
+#define TARGET_TIOCOUTQ        TARGET_IOR('t', 115, int)     /* output queue size */
+
+#define TARGET_TIOCGLTC	TARGET_IOR('t', 116, struct target_ltchars)
+#define TARGET_TIOCSLTC	TARGET_IOW('t', 117, struct target_ltchars)
+#define TARGET_TIOCSPGRP	TARGET_IOW('t', 118, int)
+#define TARGET_TIOCGPGRP	TARGET_IOR('t', 119, int)
+
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT	0x5426  /* For debugging only */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TIOCGPTN	TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	TARGET_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+  /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
index f894dde..e07ac7b 100644
--- a/linux-user/qemu.h
+++ b/linux-user/qemu.h
@@ -9,6 +9,7 @@
 
 #include "cpu.h"
 #include "syscall.h"
+#include "target_signal.h"
 #include "gdbstub.h"
 
 /* This struct is used to hold certain information about the image.
@@ -16,6 +17,7 @@
  * task_struct fields in the kernel
  */
 struct image_info {
+        target_ulong    load_addr;
 	unsigned long	start_code;
 	unsigned long	end_code;
         unsigned long   start_data;
@@ -62,13 +64,9 @@
 #ifdef TARGET_ARM
     /* FPA state */
     FPA11 fpa;
-    /* Extra fields for semihosted binaries.  */
-    uint32_t stack_base;
-    uint32_t heap_base;
-    uint32_t heap_limit;
     int swi_errno;
 #endif
-#ifdef TARGET_I386
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
     target_ulong target_v86;
     struct vm86_saved_state vm86_saved_regs;
     struct target_vm86plus_struct vm86plus;
@@ -78,6 +76,12 @@
 #ifdef TARGET_M68K
     int sim_syscalls;
 #endif
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
+    /* Extra fields for semihosted binaries.  */
+    uint32_t stack_base;
+    uint32_t heap_base;
+    uint32_t heap_limit;
+#endif
     int used; /* non zero if used */
     struct image_info *info;
     uint8_t stack[0];
@@ -95,7 +99,7 @@
 #define MAX_ARG_PAGES 32
 
 /*
- * This structure is used to hold the arguments that are 
+ * This structure is used to hold the arguments that are
  * used when loading binaries.
  */
 struct linux_binprm {
@@ -113,7 +117,7 @@
 void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
 target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
                                  target_ulong stringp, int push_ptr);
-int loader_exec(const char * filename, char ** argv, char ** envp, 
+int loader_exec(const char * filename, char ** argv, char ** envp,
              struct target_pt_regs * regs, struct image_info *infop);
 
 int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
@@ -124,10 +128,11 @@
 void memcpy_to_target(target_ulong dest, const void *src,
                       unsigned long len);
 void target_set_brk(target_ulong new_brk);
-long do_brk(target_ulong new_brk);
+target_long do_brk(target_ulong new_brk);
 void syscall_init(void);
-long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
-                long arg4, long arg5, long arg6);
+target_long do_syscall(void *cpu_env, int num, target_long arg1,
+                       target_long arg2, target_long arg3, target_long arg4,
+                       target_long arg5, target_long arg6);
 void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
 extern CPUState *global_env;
 void cpu_loop(CPUState *env);
@@ -145,6 +150,9 @@
 void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
 long do_sigreturn(CPUState *env);
 long do_rt_sigreturn(CPUState *env);
+int do_sigaltstack(const struct target_sigaltstack *uss,
+                   struct target_sigaltstack *uoss,
+                   target_ulong sp);
 
 #ifdef TARGET_I386
 /* vm86.c */
@@ -156,10 +164,10 @@
 
 /* mmap.c */
 int target_mprotect(target_ulong start, target_ulong len, int prot);
-long target_mmap(target_ulong start, target_ulong len, int prot, 
+target_long target_mmap(target_ulong start, target_ulong len, int prot,
                  int flags, int fd, target_ulong offset);
 int target_munmap(target_ulong start, target_ulong len);
-long target_mremap(target_ulong old_addr, target_ulong old_size, 
+target_long target_mremap(target_ulong old_addr, target_ulong old_size,
                    target_ulong new_size, unsigned long flags,
                    target_ulong new_addr);
 int target_msync(target_ulong start, target_ulong len, int flags);
diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h
index c91ba1b..b29705c 100644
--- a/linux-user/sh4/syscall_nr.h
+++ b/linux-user/sh4/syscall_nr.h
@@ -226,6 +226,7 @@
 #define TARGET_NR_fcntl64		221
 /* 223 is unused */
 #define TARGET_NR_gettid		224
+#define TARGET_NR_readahead		225
 #define TARGET_NR_setxattr		226
 #define TARGET_NR_lsetxattr		227
 #define TARGET_NR_fsetxattr		228
@@ -288,5 +289,40 @@
 #define TARGET_NR_add_key		285
 #define TARGET_NR_request_key	286
 #define TARGET_NR_keyctl		287
-
-#define TARGET_NR_readahead             225        /* XXXXX */
+#define TARGET_NR_ioprio_set		288
+#define TARGET_NR_ioprio_get		289
+#define TARGET_NR_inotify_init	290
+#define TARGET_NR_inotify_add_watch	291
+#define TARGET_NR_inotify_rm_watch	292
+/* 293 is unused */
+#define TARGET_NR_migrate_pages	294
+#define TARGET_NR_openat		295
+#define TARGET_NR_mkdirat		296
+#define TARGET_NR_mknodat		297
+#define TARGET_NR_fchownat		298
+#define TARGET_NR_futimesat		299
+#define TARGET_NR_fstatat64		300
+#define TARGET_NR_unlinkat		301
+#define TARGET_NR_renameat		302
+#define TARGET_NR_linkat		303
+#define TARGET_NR_symlinkat		304
+#define TARGET_NR_readlinkat		305
+#define TARGET_NR_fchmodat		306
+#define TARGET_NR_faccessat		307
+#define TARGET_NR_pselect6		308
+#define TARGET_NR_ppoll		309
+#define TARGET_NR_unshare		310
+#define TARGET_NR_set_robust_list	311
+#define TARGET_NR_get_robust_list	312
+#define TARGET_NR_splice		313
+#define TARGET_NR_sync_file_range	314
+#define TARGET_NR_tee		315
+#define TARGET_NR_vmsplice		316
+#define TARGET_NR_move_pages		317
+#define TARGET_NR_getcpu		318
+#define TARGET_NR_epoll_pwait	319
+#define TARGET_NR_utimensat		320
+#define TARGET_NR_signalfd		321
+#define TARGET_NR_timerfd		322
+#define TARGET_NR_eventfd		323
+#define TARGET_NR_fallocate		324
diff --git a/linux-user/sh4/target_signal.h b/linux-user/sh4/target_signal.h
new file mode 100644
index 0000000..e210e7a
--- /dev/null
+++ b/linux-user/sh4/target_signal.h
@@ -0,0 +1,24 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK     1
+#define TARGET_SS_DISABLE     2
+
+#define TARGET_MINSIGSTKSZ    2048
+#define TARGET_SIGSTKSZ       8192
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/sh4/termbits.h b/linux-user/sh4/termbits.h
index 6dd5845..2ff774f 100644
--- a/linux-user/sh4/termbits.h
+++ b/linux-user/sh4/termbits.h
@@ -245,7 +245,7 @@
 ndbreak() */
 #define TARGET_TIOCSBRK        TARGET_IO('T', 39) /* 0x5427 */ /* BSD compatibility */
 #define TARGET_TIOCCBRK        TARGET_IO('T', 40) /* 0x5428 */ /* BSD compatibility */
-#define TARGET_TIOCGSID        TARGET_IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session 
+#define TARGET_TIOCGSID        TARGET_IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session
 ID of FD */
 #define TARGET_TIOCGPTN        TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-m
 ux device) */
@@ -263,12 +263,12 @@
 tus register */
   /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
 # define TIOCSER_TEMT    0x01   /* Transmitter physically empty */
-#define TARGET_TIOCSERGETMULTI TARGET_IOR('T', 90, int) /* 0x545A 
+#define TARGET_TIOCSERGETMULTI TARGET_IOR('T', 90, int) /* 0x545A
 */ /* Get multiport config  */
-#define TARGET_TIOCSERSETMULTI TARGET_IOW('T', 91, int) /* 0x545B 
+#define TARGET_TIOCSERSETMULTI TARGET_IOW('T', 91, int) /* 0x545B
 */ /* Set multiport config */
 
-#define TARGET_TIOCMIWAIT      TARGET_IO('T', 92) /* 0x545C */       /* wait for a change on 
+#define TARGET_TIOCMIWAIT      TARGET_IO('T', 92) /* 0x545C */       /* wait for a change on
 serial input line(s) */
-#define TARGET_TIOCGICOUNT     TARGET_IOR('T', 93, int) /* 0x545D */ /* read 
+#define TARGET_TIOCGICOUNT     TARGET_IOR('T', 93, int) /* 0x545D */ /* read
 serial port inline interrupt counts */
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 8ee5c4b..d17c506 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -1,6 +1,6 @@
 /*
  *  Emulation of Linux signals
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include <sys/ucontext.h>
 
+#include "target_signal.h"
 #include "qemu.h"
 
 //#define DEBUG_SIGNAL
@@ -45,12 +46,18 @@
                              first signal, we put it here */
 };
 
+struct target_sigaltstack target_sigaltstack_used = {
+    .ss_sp = 0,
+    .ss_size = 0,
+    .ss_flags = TARGET_SS_DISABLE,
+};
+
 static struct emulated_sigaction sigact_table[TARGET_NSIG];
 static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
 static struct sigqueue *first_free; /* first free siginfo queue entry */
 static int signal_pending; /* non zero if a signal may be pending */
 
-static void host_signal_handler(int host_signum, siginfo_t *info, 
+static void host_signal_handler(int host_signum, siginfo_t *info,
                                 void *puc);
 
 static uint8_t host_to_target_signal_table[65] = {
@@ -92,6 +99,18 @@
 };
 static uint8_t target_to_host_signal_table[65];
 
+static inline int on_sig_stack(unsigned long sp)
+{
+    return (sp - target_sigaltstack_used.ss_sp
+            < target_sigaltstack_used.ss_size);
+}
+
+static inline int sas_ss_flags(unsigned long sp)
+{
+    return (target_sigaltstack_used.ss_size == 0 ? SS_DISABLE
+            : on_sig_stack(sp) ? SS_ONSTACK : 0);
+}
+
 static inline int host_to_target_signal(int sig)
 {
     return host_to_target_signal_table[sig];
@@ -102,17 +121,17 @@
     return target_to_host_signal_table[sig];
 }
 
-static void host_to_target_sigset_internal(target_sigset_t *d, 
+static void host_to_target_sigset_internal(target_sigset_t *d,
                                            const sigset_t *s)
 {
     int i;
     unsigned long sigmask;
     uint32_t target_sigmask;
-    
+
     sigmask = ((unsigned long *)s)[0];
     target_sigmask = 0;
     for(i = 0; i < 32; i++) {
-        if (sigmask & (1 << i)) 
+        if (sigmask & (1 << i))
             target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
     }
 #if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
@@ -147,7 +166,7 @@
     target_sigmask = s->sig[0];
     sigmask = 0;
     for(i = 0; i < 32; i++) {
-        if (target_sigmask & (1 << i)) 
+        if (target_sigmask & (1 << i))
             sigmask |= 1 << (target_to_host_signal(i + 1) - 1);
     }
 #if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
@@ -171,8 +190,8 @@
         s1.sig[i] = tswapl(s->sig[i]);
     target_to_host_sigset_internal(d, &s1);
 }
-    
-void host_to_target_old_sigset(target_ulong *old_sigset, 
+
+void host_to_target_old_sigset(target_ulong *old_sigset,
                                const sigset_t *sigset)
 {
     target_sigset_t d;
@@ -180,7 +199,7 @@
     *old_sigset = d.sig[0];
 }
 
-void target_to_host_old_sigset(sigset_t *sigset, 
+void target_to_host_old_sigset(sigset_t *sigset,
                                const target_ulong *old_sigset)
 {
     target_sigset_t d;
@@ -194,7 +213,7 @@
 
 /* siginfo conversion */
 
-static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo, 
+static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
                                                  const siginfo_t *info)
 {
     int sig;
@@ -202,21 +221,23 @@
     tinfo->si_signo = sig;
     tinfo->si_errno = 0;
     tinfo->si_code = 0;
-    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || 
+    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
         sig == SIGBUS || sig == SIGTRAP) {
         /* should never come here, but who knows. The information for
            the target is irrelevant */
         tinfo->_sifields._sigfault._addr = 0;
+    } else if (sig == SIGIO) {
+	tinfo->_sifields._sigpoll._fd = info->si_fd;
     } else if (sig >= TARGET_SIGRTMIN) {
         tinfo->_sifields._rt._pid = info->si_pid;
         tinfo->_sifields._rt._uid = info->si_uid;
         /* XXX: potential problem if 64 bit */
-        tinfo->_sifields._rt._sigval.sival_ptr = 
+        tinfo->_sifields._rt._sigval.sival_ptr =
             (target_ulong)info->si_value.sival_ptr;
     }
 }
 
-static void tswap_siginfo(target_siginfo_t *tinfo, 
+static void tswap_siginfo(target_siginfo_t *tinfo,
                           const target_siginfo_t *info)
 {
     int sig;
@@ -224,14 +245,16 @@
     tinfo->si_signo = tswap32(sig);
     tinfo->si_errno = tswap32(info->si_errno);
     tinfo->si_code = tswap32(info->si_code);
-    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV || 
+    if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
         sig == SIGBUS || sig == SIGTRAP) {
-        tinfo->_sifields._sigfault._addr = 
+        tinfo->_sifields._sigfault._addr =
             tswapl(info->_sifields._sigfault._addr);
+    } else if (sig == SIGIO) {
+	tinfo->_sifields._sigpoll._fd = tswap32(info->_sifields._sigpoll._fd);
     } else if (sig >= TARGET_SIGRTMIN) {
         tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
         tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
-        tinfo->_sifields._rt._sigval.sival_ptr = 
+        tinfo->_sifields._rt._sigval.sival_ptr =
             tswapl(info->_sifields._rt._sigval.sival_ptr);
     }
 }
@@ -244,7 +267,7 @@
 }
 
 /* XXX: we support only POSIX RT signals are used. */
-/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */
+/* XXX: find a solution for 64 bit (additional malloced data is needed) */
 void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
 {
     info->si_signo = tswap32(tinfo->si_signo);
@@ -252,7 +275,7 @@
     info->si_code = tswap32(tinfo->si_code);
     info->si_pid = tswap32(tinfo->_sifields._rt._pid);
     info->si_uid = tswap32(tinfo->_sifields._rt._uid);
-    info->si_value.sival_ptr = 
+    info->si_value.sival_ptr =
         (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
 }
 
@@ -270,7 +293,7 @@
         j = host_to_target_signal_table[i];
         target_to_host_signal_table[j] = i;
     }
-        
+
     /* set all host signal handlers. ALL signals are blocked during
        the handlers to serialize them. */
     sigfillset(&act.sa_mask);
@@ -279,11 +302,11 @@
     for(i = 1; i < NSIG; i++) {
         sigaction(i, &act, NULL);
     }
-    
+
     memset(sigact_table, 0, sizeof(sigact_table));
 
     first_free = &sigqueue_table[0];
-    for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++) 
+    for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
         sigqueue_table[i].next = &sigqueue_table[i + 1];
     sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
 }
@@ -310,7 +333,7 @@
 {
     int host_sig;
     host_sig = target_to_host_signal(sig);
-    fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n", 
+    fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
             sig, strsignal(host_sig));
 #if 1
     _exit(-host_sig);
@@ -335,15 +358,15 @@
     target_ulong handler;
 
 #if defined(DEBUG_SIGNAL)
-    fprintf(stderr, "queue_signal: sig=%d\n", 
+    fprintf(stderr, "queue_signal: sig=%d\n",
             sig);
 #endif
     k = &sigact_table[sig - 1];
     handler = k->sa._sa_handler;
     if (handler == TARGET_SIG_DFL) {
         /* default handler : ignore some signal. The other are fatal */
-        if (sig != TARGET_SIGCHLD && 
-            sig != TARGET_SIGURG && 
+        if (sig != TARGET_SIGCHLD &&
+            sig != TARGET_SIGURG &&
             sig != TARGET_SIGWINCH) {
             force_sig(sig);
         } else {
@@ -384,7 +407,7 @@
     }
 }
 
-static void host_signal_handler(int host_signum, siginfo_t *info, 
+static void host_signal_handler(int host_signum, siginfo_t *info,
                                 void *puc)
 {
     int sig;
@@ -392,7 +415,7 @@
 
     /* the CPU emulator uses some host signals to detect exceptions,
        we we forward to it some signals */
-    if (host_signum == SIGSEGV || host_signum == SIGBUS 
+    if (host_signum == SIGSEGV || host_signum == SIGBUS
 #if defined(TARGET_I386) && defined(USE_CODE_COPY)
         || host_signum == SIGFPE
 #endif
@@ -415,6 +438,67 @@
     }
 }
 
+int do_sigaltstack(const struct target_sigaltstack *uss,
+                   struct target_sigaltstack *uoss,
+                   target_ulong sp)
+{
+    int ret;
+    struct target_sigaltstack oss;
+
+    /* XXX: test errors */
+    if(uoss)
+    {
+        __put_user(target_sigaltstack_used.ss_sp, &oss.ss_sp);
+        __put_user(target_sigaltstack_used.ss_size, &oss.ss_size);
+        __put_user(sas_ss_flags(sp), &oss.ss_flags);
+    }
+
+    if(uss)
+    {
+	struct target_sigaltstack ss;
+
+	ret = -EFAULT;
+	if (!access_ok(VERIFY_READ, uss, sizeof(*uss))
+	    || __get_user(ss.ss_sp, &uss->ss_sp)
+	    || __get_user(ss.ss_size, &uss->ss_size)
+	    || __get_user(ss.ss_flags, &uss->ss_flags))
+            goto out;
+
+	ret = -EPERM;
+	if (on_sig_stack(sp))
+            goto out;
+
+	ret = -EINVAL;
+	if (ss.ss_flags != TARGET_SS_DISABLE
+            && ss.ss_flags != TARGET_SS_ONSTACK
+            && ss.ss_flags != 0)
+            goto out;
+
+	if (ss.ss_flags == TARGET_SS_DISABLE) {
+            ss.ss_size = 0;
+            ss.ss_sp = 0;
+	} else {
+            ret = -ENOMEM;
+            if (ss.ss_size < MINSIGSTKSZ)
+                goto out;
+	}
+
+        target_sigaltstack_used.ss_sp = ss.ss_sp;
+        target_sigaltstack_used.ss_size = ss.ss_size;
+    }
+
+    if (uoss) {
+        ret = -EFAULT;
+        if (!access_ok(VERIFY_WRITE, uoss, sizeof(oss)))
+            goto out;
+        memcpy(uoss, &oss, sizeof(oss));
+    }
+
+    ret = 0;
+out:
+    return ret;
+}
+
 int do_sigaction(int sig, const struct target_sigaction *act,
                  struct target_sigaction *oact)
 {
@@ -422,27 +506,27 @@
     struct sigaction act1;
     int host_sig;
 
-    if (sig < 1 || sig > TARGET_NSIG)
+    if (sig < 1 || sig > TARGET_NSIG || sig == SIGKILL || sig == SIGSTOP)
         return -EINVAL;
     k = &sigact_table[sig - 1];
 #if defined(DEBUG_SIGNAL)
-    fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n", 
+    fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
             sig, (int)act, (int)oact);
 #endif
     if (oact) {
         oact->_sa_handler = tswapl(k->sa._sa_handler);
         oact->sa_flags = tswapl(k->sa.sa_flags);
-	#if !defined(TARGET_MIPS)
-        	oact->sa_restorer = tswapl(k->sa.sa_restorer);
-	#endif
+#if !defined(TARGET_MIPS)
+        oact->sa_restorer = tswapl(k->sa.sa_restorer);
+#endif
         oact->sa_mask = k->sa.sa_mask;
     }
     if (act) {
         k->sa._sa_handler = tswapl(act->_sa_handler);
         k->sa.sa_flags = tswapl(act->sa_flags);
-	#if !defined(TARGET_MIPS)
-        	k->sa.sa_restorer = tswapl(act->sa_restorer);
-	#endif
+#if !defined(TARGET_MIPS)
+        k->sa.sa_restorer = tswapl(act->sa_restorer);
+#endif
         k->sa.sa_mask = act->sa_mask;
 
         /* we update the host linux signal state */
@@ -472,7 +556,7 @@
 #define offsetof(type, field) ((size_t) &((type *)0)->field)
 #endif
 
-static inline int copy_siginfo_to_user(target_siginfo_t *tinfo, 
+static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
                                        const target_siginfo_t *info)
 {
     tswap_siginfo(tinfo, info);
@@ -547,12 +631,6 @@
 	target_ulong cr2;
 };
 
-typedef struct target_sigaltstack {
-	target_ulong ss_sp;
-	int ss_flags;
-	target_ulong ss_size;
-} target_stack_t;
-
 struct target_ucontext {
         target_ulong	  tuc_flags;
 	target_ulong      tuc_link;
@@ -636,16 +714,14 @@
 
 	/* Default to using normal stack */
 	esp = env->regs[R_ESP];
-#if 0
 	/* This is the X/Open sanctioned signal stack switching.  */
-	if (ka->sa.sa_flags & SA_ONSTACK) {
-		if (sas_ss_flags(esp) == 0)
-			esp = current->sas_ss_sp + current->sas_ss_size;
-	}
+        if (ka->sa.sa_flags & TARGET_SA_ONSTACK) {
+            if (sas_ss_flags(esp) == 0)
+                esp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+        }
 
 	/* This is the legacy signal stack switching. */
-	else 
-#endif
+	else
         if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
             !(ka->sa.sa_flags & TARGET_SA_RESTORER) &&
             ka->sa.sa_restorer) {
@@ -690,7 +766,11 @@
 		err |= __put_user(frame->retcode, &frame->pretcode);
 		/* This is popl %eax ; movl $,%eax ; int $0x80 */
 		err |= __put_user(0xb858, (short *)(frame->retcode+0));
+#if defined(TARGET_X86_64)
+#warning "Fix this !"
+#else
 		err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
+#endif
 		err |= __put_user(0x80cd, (short *)(frame->retcode+6));
 	}
 
@@ -715,7 +795,7 @@
 	force_sig(TARGET_SIGSEGV /* , current */);
 }
 
-static void setup_rt_frame(int sig, struct emulated_sigaction *ka, 
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
                            target_siginfo_t *info,
 			   target_sigset_t *set, CPUX86State *env)
 {
@@ -742,11 +822,11 @@
 	/* Create the ucontext.  */
 	err |= __put_user(0, &frame->uc.tuc_flags);
 	err |= __put_user(0, &frame->uc.tuc_link);
-	err |= __put_user(/*current->sas_ss_sp*/ 0,
+	err |= __put_user(target_sigaltstack_used.ss_sp,
 			  &frame->uc.tuc_stack.ss_sp);
-	err |= __put_user(/* sas_ss_flags(regs->esp) */ 0,
+	err |= __put_user(sas_ss_flags(get_sp_from_cpustate(env)),
 			  &frame->uc.tuc_stack.ss_flags);
-	err |= __put_user(/* current->sas_ss_size */ 0,
+	err |= __put_user(target_sigaltstack_used.ss_size,
 			  &frame->uc.tuc_stack.ss_size);
 	err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
 			        env, set->sig[0]);
@@ -809,7 +889,7 @@
 
         cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
         cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
-	
+
 	{
 		unsigned int tmpflags;
                 tmpflags = ldl(&sc->eflags);
@@ -857,7 +937,7 @@
 
     target_to_host_sigset_internal(&set, &target_set);
     sigprocmask(SIG_SETMASK, &set, NULL);
-    
+
     /* restore registers */
     if (restore_sigcontext(env, &frame->sc, &eax))
         goto badframe;
@@ -872,7 +952,6 @@
 {
 	struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env->regs[R_ESP] - 4);
         sigset_t set;
-        //	stack_t st;
 	int eax;
 
 #if 0
@@ -881,17 +960,13 @@
 #endif
         target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
         sigprocmask(SIG_SETMASK, &set, NULL);
-	
+
 	if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
 		goto badframe;
 
-#if 0
-	if (__copy_from_user(&st, &frame->uc.tuc_stack, sizeof(st)))
+	if (do_sigaltstack(&frame->uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT)
 		goto badframe;
-	/* It is more difficult to avoid calling this function than to
-	   call it and ignore errors.  */
-	do_sigaltstack(&st, NULL, regs->esp);
-#endif
+
 	return eax;
 
 badframe:
@@ -925,12 +1000,6 @@
 	target_ulong fault_address;
 };
 
-typedef struct target_sigaltstack {
-	target_ulong ss_sp;
-	int ss_flags;
-	target_ulong ss_size;
-} target_stack_t;
-
 struct target_ucontext {
     target_ulong tuc_flags;
     target_ulong tuc_link;
@@ -1023,13 +1092,11 @@
 {
 	unsigned long sp = regs->regs[13];
 
-#if 0
 	/*
 	 * This is the X/Open sanctioned signal stack switching.
 	 */
-	if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
-		sp = current->sas_ss_sp + current->sas_ss_size;
-#endif
+	if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
+            sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
 	/*
 	 * ATPCS B01 mandates 8-byte alignment
 	 */
@@ -1066,8 +1133,8 @@
 		else
 			cpsr &= ~T_BIT;
 	}
-#endif
-#endif
+#endif /* CONFIG_ARM_THUMB */
+#endif /* 0 */
 #endif /* TARGET_CONFIG_CPU_32 */
 
 	if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
@@ -1119,11 +1186,12 @@
         //	return err;
 }
 
-static void setup_rt_frame(int usig, struct emulated_sigaction *ka, 
+static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
                            target_siginfo_t *info,
 			   target_sigset_t *set, CPUState *env)
 {
 	struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
+	struct target_sigaltstack stack;
 	int i, err = 0;
 
 	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
@@ -1136,6 +1204,15 @@
 	/* Clear all the bits of the ucontext we don't use.  */
 	memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext));
 
+        memset(&stack, 0, sizeof(stack));
+        __put_user(target_sigaltstack_used.ss_sp, &stack.ss_sp);
+        __put_user(target_sigaltstack_used.ss_size, &stack.ss_size);
+        __put_user(sas_ss_flags(get_sp_from_cpustate(env)), &stack.ss_flags);
+        if (!access_ok(VERIFY_WRITE, &frame->uc.tuc_stack, sizeof(stack)))
+            err = 1;
+        else
+            memcpy(&frame->uc.tuc_stack, &stack, sizeof(stack));
+
 	err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/
 				env, set->sig[0]);
         for(i = 0; i < TARGET_NSIG_WORDS; i++) {
@@ -1262,6 +1339,9 @@
 	if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
 		goto badframe;
 
+	if (do_sigaltstack(&frame->uc.tuc_stack, NULL, get_sp_from_cpustate(env)) == -EFAULT)
+		goto badframe;
+
 #if 0
 	/* Send SIGTRAP if we're single-stepping */
 	if (ptrace_cancel_bpt(current))
@@ -1374,14 +1454,13 @@
 	unsigned long sp;
 
 	sp = env->regwptr[UREG_FP];
-#if 0
 
 	/* This is the X/Open sanctioned signal stack switching.  */
-	if (sa->sa_flags & TARGET_SA_ONSTACK) {
-		if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7))
-			sp = current->sas_ss_sp + current->sas_ss_size;
+	if (sa->sa.sa_flags & TARGET_SA_ONSTACK) {
+            if (!on_sig_stack(sp)
+                && !((target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size) & 7))
+                sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
 	}
-#endif
 	return g2h(sp - framesize);
 }
 
@@ -1539,7 +1618,7 @@
 }
 
 
-static void setup_rt_frame(int sig, struct emulated_sigaction *ka, 
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
                            target_siginfo_t *info,
 			   target_sigset_t *set, CPUState *env)
 {
@@ -1625,6 +1704,64 @@
     return -ENOSYS;
 }
 
+#elif defined(TARGET_MIPS64)
+
+# warning signal handling not implemented
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_sigreturn: not implemented\n");
+    return -ENOSYS;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_rt_sigreturn: not implemented\n");
+    return -ENOSYS;
+}
+
+#elif defined(TARGET_MIPSN32)
+
+# warning signal handling not implemented
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+			target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
+                           target_siginfo_t *info,
+			   target_sigset_t *set, CPUState *env)
+{
+    fprintf(stderr, "setup_rt_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_sigreturn: not implemented\n");
+    return -ENOSYS;
+}
+
+long do_rt_sigreturn(CPUState *env)
+{
+    fprintf(stderr, "do_rt_sigreturn: not implemented\n");
+    return -ENOSYS;
+}
+
 #elif defined(TARGET_MIPS)
 
 struct target_sigcontext {
@@ -1678,10 +1815,10 @@
 {
     int err = 0;
 
-    err |= __put_user(regs->PC, &sc->sc_pc);
+    err |= __put_user(regs->PC[regs->current_tc], &sc->sc_pc);
 
-    #define save_gp_reg(i) do {   					\
-        err |= __put_user(regs->gpr[i], &sc->sc_regs[i]);		\
+#define save_gp_reg(i) do {   							\
+        err |= __put_user(regs->gpr[i][regs->current_tc], &sc->sc_regs[i]);	\
     } while(0)
     __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
     save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
@@ -1692,10 +1829,10 @@
     save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
     save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
     save_gp_reg(31);
-    #undef save_gp_reg
+#undef save_gp_reg
 
-    err |= __put_user(regs->HI, &sc->sc_mdhi);
-    err |= __put_user(regs->LO, &sc->sc_mdlo);
+    err |= __put_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi);
+    err |= __put_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo);
 
     /* Not used yet, but might be useful if we ever have DSP suppport */
 #if 0
@@ -1709,7 +1846,7 @@
 	err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
     }
     /* same with 64 bit */
-    #ifdef CONFIG_64BIT
+#ifdef CONFIG_64BIT
     err |= __put_user(regs->hi, &sc->sc_hi[0]);
     err |= __put_user(regs->lo, &sc->sc_lo[0]);
     if (cpu_has_dsp) {
@@ -1721,13 +1858,10 @@
 	err |= __put_user(mflo3(), &sc->sc_lo[3]);
 	err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
     }
-    #endif
+#endif
+#endif
 
-
-    #endif
-
-
-    #if 0
+#if 0
     err |= __put_user(!!used_math(), &sc->sc_used_math);
 
     if (!used_math())
@@ -1758,11 +1892,11 @@
 
     err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
 
-    err |= __get_user(regs->HI, &sc->sc_mdhi);
-    err |= __get_user(regs->LO, &sc->sc_mdlo);
+    err |= __get_user(regs->HI[0][regs->current_tc], &sc->sc_mdhi);
+    err |= __get_user(regs->LO[0][regs->current_tc], &sc->sc_mdlo);
 
-    #define restore_gp_reg(i) do {   					\
-        err |= __get_user(regs->gpr[i], &sc->sc_regs[i]);		\
+#define restore_gp_reg(i) do {   							\
+        err |= __get_user(regs->gpr[i][regs->current_tc], &sc->sc_regs[i]);		\
     } while(0)
     restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
     restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
@@ -1775,7 +1909,7 @@
     restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
     restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
     restore_gp_reg(31);
-    #undef restore_gp_reg
+#undef restore_gp_reg
 
 #if 0
     if (cpu_has_dsp) {
@@ -1787,7 +1921,7 @@
 	err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
 	err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
     }
-    #ifdef CONFIG_64BIT
+#ifdef CONFIG_64BIT
     err |= __get_user(regs->hi, &sc->sc_hi[0]);
     err |= __get_user(regs->lo, &sc->sc_lo[0]);
     if (cpu_has_dsp) {
@@ -1799,7 +1933,7 @@
 	err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
 	err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
     }
-    #endif
+#endif
 
     err |= __get_user(used_math, &sc->sc_used_math);
     conditional_used_math(used_math);
@@ -1828,7 +1962,7 @@
     unsigned long sp;
 
     /* Default to using normal stack */
-    sp = regs->gpr[29];
+    sp = regs->gpr[29][regs->current_tc];
 
     /*
      * FPU emulator may have it's own trampoline active just
@@ -1837,16 +1971,15 @@
      */
     sp -= 32;
 
-#if 0
     /* This is the X/Open sanctioned signal stack switching.  */
-    if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
-	sp = current->sas_ss_sp + current->sas_ss_size;
-#endif
+    if ((ka->sa.sa_flags & TARGET_SA_ONSTACK) && (sas_ss_flags (sp) == 0)) {
+        sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
+    }
 
     return g2h((sp - frame_size) & ~7);
 }
 
-static void setup_frame(int sig, struct emulated_sigaction * ka, 
+static void setup_frame(int sig, struct emulated_sigaction * ka,
    		target_sigset_t *set, CPUState *regs)
 {
     struct sigframe *frame;
@@ -1876,72 +2009,71 @@
     * $25 and PC point to the signal handler, $29 points to the
     * struct sigframe.
     */
-    regs->gpr[ 4] = sig;
-    regs->gpr[ 5] = 0;
-    regs->gpr[ 6] = h2g(&frame->sf_sc);
-    regs->gpr[29] = h2g(frame);
-    regs->gpr[31] = h2g(frame->sf_code);
+    regs->gpr[ 4][regs->current_tc] = sig;
+    regs->gpr[ 5][regs->current_tc] = 0;
+    regs->gpr[ 6][regs->current_tc] = h2g(&frame->sf_sc);
+    regs->gpr[29][regs->current_tc] = h2g(frame);
+    regs->gpr[31][regs->current_tc] = h2g(frame->sf_code);
     /* The original kernel code sets CP0_EPC to the handler
     * since it returns to userland using eret
     * we cannot do this here, and we must set PC directly */
-    regs->PC = regs->gpr[25] = ka->sa._sa_handler;
+    regs->PC[regs->current_tc] = regs->gpr[25][regs->current_tc] = ka->sa._sa_handler;
     return;
 
 give_sigsegv:
     force_sig(TARGET_SIGSEGV/*, current*/);
-    return;	
+    return;
 }
 
 long do_sigreturn(CPUState *regs)
 {
-   struct sigframe *frame;
-   sigset_t blocked;
-   target_sigset_t target_set;
-   int i;
+    struct sigframe *frame;
+    sigset_t blocked;
+    target_sigset_t target_set;
+    int i;
 
 #if defined(DEBUG_SIGNAL)
-   fprintf(stderr, "do_sigreturn\n");
+    fprintf(stderr, "do_sigreturn\n");
 #endif
-   frame = (struct sigframe *) regs->gpr[29];
-   if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+    frame = (struct sigframe *) regs->gpr[29][regs->current_tc];
+    if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
    	goto badframe;
 
-   for(i = 0; i < TARGET_NSIG_WORDS; i++) {
+    for(i = 0; i < TARGET_NSIG_WORDS; i++) {
    	if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
 	    goto badframe;
-   }		
+    }
 
-   target_to_host_sigset_internal(&blocked, &target_set);
-   sigprocmask(SIG_SETMASK, &blocked, NULL);
+    target_to_host_sigset_internal(&blocked, &target_set);
+    sigprocmask(SIG_SETMASK, &blocked, NULL);
 
-   if (restore_sigcontext(regs, &frame->sf_sc))
+    if (restore_sigcontext(regs, &frame->sf_sc))
    	goto badframe;
 
 #if 0
-   /*
-    * Don't let your children do this ...
-    */
-   __asm__ __volatile__(
+    /*
+     * Don't let your children do this ...
+     */
+    __asm__ __volatile__(
    	"move\t$29, %0\n\t"
    	"j\tsyscall_exit"
    	:/* no outputs */
    	:"r" (&regs));
-   /* Unreached */
+    /* Unreached */
 #endif
-    
-    regs->PC = regs->CP0_EPC;
-   /* I am not sure this is right, but it seems to work
+
+    regs->PC[regs->current_tc] = regs->CP0_EPC;
+    /* I am not sure this is right, but it seems to work
     * maybe a problem with nested signals ? */
     regs->CP0_EPC = 0;
     return 0;
 
 badframe:
-   force_sig(TARGET_SIGSEGV/*, current*/);
-   return 0;	
-
+    force_sig(TARGET_SIGSEGV/*, current*/);
+    return 0;
 }
 
-static void setup_rt_frame(int sig, struct emulated_sigaction *ka, 
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
                            target_siginfo_t *info,
 			   target_sigset_t *set, CPUState *env)
 {
@@ -1962,7 +2094,7 @@
     fprintf(stderr, "setup_frame: not implemented\n");
 }
 
-static void setup_rt_frame(int sig, struct emulated_sigaction *ka, 
+static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
                            target_siginfo_t *info,
 			   target_sigset_t *set, CPUState *env)
 {
@@ -1991,7 +2123,7 @@
     target_sigset_t target_old_set;
     struct emulated_sigaction *k;
     struct sigqueue *q;
-    
+
     if (!signal_pending)
         return;
 
@@ -2014,7 +2146,7 @@
     k->first = q->next;
     if (!k->first)
         k->pending = 0;
-      
+
     sig = gdb_handlesig (cpu_env, sig);
     if (!sig) {
         fprintf (stderr, "Lost signal\n");
@@ -2024,8 +2156,8 @@
     handler = k->sa._sa_handler;
     if (handler == TARGET_SIG_DFL) {
         /* default handler : ignore some signal. The other are fatal */
-        if (sig != TARGET_SIGCHLD && 
-            sig != TARGET_SIGURG && 
+        if (sig != TARGET_SIGCHLD &&
+            sig != TARGET_SIGURG &&
             sig != TARGET_SIGWINCH) {
             force_sig(sig);
         }
@@ -2040,7 +2172,7 @@
            blocked during the handler */
         if (!(k->sa.sa_flags & TARGET_SA_NODEFER))
             sigaddset(&set, target_to_host_signal(sig));
-        
+
         /* block signals in the handler using Linux */
         sigprocmask(SIG_BLOCK, &set, &old_set);
         /* save the previous blocked signal state to restore it at the
@@ -2048,7 +2180,7 @@
         host_to_target_sigset_internal(&target_old_set, &old_set);
 
         /* if the CPU is in VM86 mode, we restore the 32 bit values */
-#ifdef TARGET_I386
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
         {
             CPUX86State *env = cpu_env;
             if (env->eflags & VM_MASK)
@@ -2066,5 +2198,3 @@
     if (q != &k->info)
         free_sigqueue(q);
 }
-
-
diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h
index afb364f..6419570 100644
--- a/linux-user/sparc/syscall_nr.h
+++ b/linux-user/sparc/syscall_nr.h
@@ -217,4 +217,62 @@
 #define TARGET_NR_fdatasync          253
 #define TARGET_NR_nfsservctl         254
 #define TARGET_NR_aplib              255
-#define TARGET_NR__exit TARGET_NR_exit
+#define TARGET_NR_clock_settime	256
+#define TARGET_NR_clock_gettime	257
+#define TARGET_NR_clock_getres	258
+#define TARGET_NR_clock_nanosleep	259
+#define TARGET_NR_sched_getaffinity	260
+#define TARGET_NR_sched_setaffinity	261
+#define TARGET_NR_timer_settime	262
+#define TARGET_NR_timer_gettime	263
+#define TARGET_NR_timer_getoverrun	264
+#define TARGET_NR_timer_delete	265
+#define TARGET_NR_timer_create	266
+/* #define TARGET_NR_vserver		267 Reserved for VSERVER */
+#define TARGET_NR_io_setup		268
+#define TARGET_NR_io_destroy		269
+#define TARGET_NR_io_submit		270
+#define TARGET_NR_io_cancel		271
+#define TARGET_NR_io_getevents	272
+#define TARGET_NR_mq_open		273
+#define TARGET_NR_mq_unlink		274
+#define TARGET_NR_mq_timedsend	275
+#define TARGET_NR_mq_timedreceive	276
+#define TARGET_NR_mq_notify		277
+#define TARGET_NR_mq_getsetattr	278
+#define TARGET_NR_waitid		279
+#define TARGET_NR_tee		280
+#define TARGET_NR_add_key		281
+#define TARGET_NR_request_key	282
+#define TARGET_NR_keyctl		283
+#define TARGET_NR_openat		284
+#define TARGET_NR_mkdirat		285
+#define TARGET_NR_mknodat		286
+#define TARGET_NR_fchownat		287
+#define TARGET_NR_futimesat		288
+#define TARGET_NR_fstatat64		289
+#define TARGET_NR_unlinkat		290
+#define TARGET_NR_renameat		291
+#define TARGET_NR_linkat		292
+#define TARGET_NR_symlinkat		293
+#define TARGET_NR_readlinkat		294
+#define TARGET_NR_fchmodat		295
+#define TARGET_NR_faccessat		296
+#define TARGET_NR_pselect6		297
+#define TARGET_NR_ppoll		298
+#define TARGET_NR_unshare		299
+#define TARGET_NR_set_robust_list	300
+#define TARGET_NR_get_robust_list	301
+#define TARGET_NR_migrate_pages	302
+#define TARGET_NR_mbind		303
+#define TARGET_NR_get_mempolicy	304
+#define TARGET_NR_set_mempolicy	305
+#define TARGET_NR_kexec_load		306
+#define TARGET_NR_move_pages		307
+#define TARGET_NR_getcpu		308
+#define TARGET_NR_epoll_pwait	309
+#define TARGET_NR_utimensat		310
+#define TARGET_NR_signalfd		311
+#define TARGET_NR_timerfd		312
+#define TARGET_NR_eventfd		313
+#define TARGET_NR_fallocate		314
diff --git a/linux-user/sparc/target_signal.h b/linux-user/sparc/target_signal.h
new file mode 100644
index 0000000..dfca129
--- /dev/null
+++ b/linux-user/sparc/target_signal.h
@@ -0,0 +1,36 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	4096
+#define TARGET_SIGSTKSZ		16384
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline target_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/sparc/termbits.h b/linux-user/sparc/termbits.h
index cad45b2..ed9ab24 100644
--- a/linux-user/sparc/termbits.h
+++ b/linux-user/sparc/termbits.h
@@ -51,6 +51,7 @@
 #define TARGET_IXANY	0x00000800
 #define TARGET_IXOFF	0x00001000
 #define TARGET_IMAXBEL	0x00002000
+#define TARGET_IUTF8	0x00004000
 
 /* c_oflag bits */
 #define TARGET_OPOST	0x00000001
@@ -182,7 +183,7 @@
 #define TARGET_TCSETSW		TARGET_IOW('T', 10, struct target_termios)
 #define TARGET_TCSETSF		TARGET_IOW('T', 11, struct target_termios)
 
-/* Note that all the ioctls that are not available in Linux have a 
+/* Note that all the ioctls that are not available in Linux have a
  * double underscore on the front to: a) avoid some programs to
  * thing we support some ioctls under Linux (autoconfiguration stuff)
  */
diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h
index 9274c85..5310294 100644
--- a/linux-user/sparc64/syscall_nr.h
+++ b/linux-user/sparc64/syscall_nr.h
@@ -284,3 +284,34 @@
 #define TARGET_NR_add_key		281
 #define TARGET_NR_request_key	282
 #define TARGET_NR_keyctl		283
+#define TARGET_NR_openat		284
+#define TARGET_NR_mkdirat		285
+#define TARGET_NR_mknodat		286
+#define TARGET_NR_fchownat		287
+#define TARGET_NR_futimesat		288
+#define TARGET_NR_fstatat64		289
+#define TARGET_NR_unlinkat		290
+#define TARGET_NR_renameat		291
+#define TARGET_NR_linkat		292
+#define TARGET_NR_symlinkat		293
+#define TARGET_NR_readlinkat		294
+#define TARGET_NR_fchmodat		295
+#define TARGET_NR_faccessat		296
+#define TARGET_NR_pselect6		297
+#define TARGET_NR_ppoll		298
+#define TARGET_NR_unshare		299
+#define TARGET_NR_set_robust_list	300
+#define TARGET_NR_get_robust_list	301
+#define TARGET_NR_migrate_pages	302
+#define TARGET_NR_mbind		303
+#define TARGET_NR_get_mempolicy	304
+#define TARGET_NR_set_mempolicy	305
+#define TARGET_NR_kexec_load		306
+#define TARGET_NR_move_pages		307
+#define TARGET_NR_getcpu		308
+#define TARGET_NR_epoll_pwait	309
+#define TARGET_NR_utimensat		310
+#define TARGET_NR_signalfd		311
+#define TARGET_NR_timerfd		312
+#define TARGET_NR_eventfd		313
+#define TARGET_NR_fallocate		314
diff --git a/linux-user/sparc64/target_signal.h b/linux-user/sparc64/target_signal.h
new file mode 100644
index 0000000..dfca129
--- /dev/null
+++ b/linux-user/sparc64/target_signal.h
@@ -0,0 +1,36 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	4096
+#define TARGET_SIGSTKSZ		16384
+
+#ifndef UREG_I6
+#define UREG_I6        6
+#endif
+#ifndef UREG_FP
+#define UREG_FP        UREG_I6
+#endif
+
+static inline target_ulong get_sp_from_cpustate(CPUSPARCState *state)
+{
+    return state->regwptr[UREG_FP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h
index cad45b2..ed9ab24 100644
--- a/linux-user/sparc64/termbits.h
+++ b/linux-user/sparc64/termbits.h
@@ -51,6 +51,7 @@
 #define TARGET_IXANY	0x00000800
 #define TARGET_IXOFF	0x00001000
 #define TARGET_IMAXBEL	0x00002000
+#define TARGET_IUTF8	0x00004000
 
 /* c_oflag bits */
 #define TARGET_OPOST	0x00000001
@@ -182,7 +183,7 @@
 #define TARGET_TCSETSW		TARGET_IOW('T', 10, struct target_termios)
 #define TARGET_TCSETSF		TARGET_IOW('T', 11, struct target_termios)
 
-/* Note that all the ioctls that are not available in Linux have a 
+/* Note that all the ioctls that are not available in Linux have a
  * double underscore on the front to: a) avoid some programs to
  * thing we support some ioctls under Linux (autoconfiguration stuff)
  */
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 45c8f29..af5b9d9 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -1,6 +1,6 @@
 /*
  *  Linux syscalls
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -28,10 +28,13 @@
 #include <fcntl.h>
 #include <time.h>
 #include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
 #include <sys/wait.h>
 #include <sys/time.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
+#include <sys/prctl.h>
 #include <sys/resource.h>
 #include <sys/mman.h>
 #include <sys/swap.h>
@@ -71,7 +74,7 @@
 //#define DEBUG
 
 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
-    || defined(TARGET_M68K)
+    || defined(TARGET_M68K) || defined(TARGET_SH4)
 /* 16 bit uid wrappers emulation */
 #define USE_UID16
 #endif
@@ -136,10 +139,25 @@
 
 
 #define __NR_sys_uname __NR_uname
+#define __NR_sys_faccessat __NR_faccessat
+#define __NR_sys_fchmodat __NR_fchmodat
+#define __NR_sys_fchownat __NR_fchownat
 #define __NR_sys_getcwd1 __NR_getcwd
 #define __NR_sys_getdents __NR_getdents
 #define __NR_sys_getdents64 __NR_getdents64
+#define __NR_sys_linkat __NR_linkat
+#define __NR_sys_mkdirat __NR_mkdirat
+#define __NR_sys_mknodat __NR_mknodat
+#define __NR_sys_openat __NR_openat
+#define __NR_sys_readlinkat __NR_readlinkat
+#define __NR_sys_renameat __NR_renameat
 #define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
+#define __NR_sys_symlinkat __NR_symlinkat
+#define __NR_sys_syslog __NR_syslog
+#define __NR_sys_tgkill __NR_tgkill
+#define __NR_sys_tkill __NR_tkill
+#define __NR_sys_unlinkat __NR_unlinkat
+#define __NR_sys_utimensat __NR_utimensat
 
 #if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
 #define __NR__llseek __NR_lseek
@@ -153,15 +171,71 @@
 }
 #endif
 _syscall1(int,sys_uname,struct new_utsname *,buf)
+#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
+_syscall4(int,sys_faccessat,int,dirfd,const char *,pathname,int,mode,int,flags)
+#endif
+#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
+_syscall4(int,sys_fchmodat,int,dirfd,const char *,pathname,
+          mode_t,mode,int,flags)
+#endif
+#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
+_syscall5(int,sys_fchownat,int,dirfd,const char *,pathname,
+          uid_t,owner,gid_t,group,int,flags)
+#endif
 _syscall2(int,sys_getcwd1,char *,buf,size_t,size)
 _syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count);
+#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
 _syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count);
+#endif
 _syscall5(int, _llseek,  uint,  fd, ulong, hi, ulong, lo,
           loff_t *, res, uint, wh);
+#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
+_syscall5(int,sys_linkat,int,olddirfd,const char *,oldpath,
+	  int,newdirfd,const char *,newpath,int,flags)
+#endif
+#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
+_syscall3(int,sys_mkdirat,int,dirfd,const char *,pathname,mode_t,mode)
+#endif
+#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
+_syscall4(int,sys_mknodat,int,dirfd,const char *,pathname,
+          mode_t,mode,dev_t,dev)
+#endif
+#if defined(TARGET_NR_openat) && defined(__NR_openat)
+_syscall4(int,sys_openat,int,dirfd,const char *,pathname,int,flags,mode_t,mode)
+#endif
+#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
+_syscall4(int,sys_readlinkat,int,dirfd,const char *,pathname,
+          char *,buf,size_t,bufsize)
+#endif
+#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
+_syscall4(int,sys_renameat,int,olddirfd,const char *,oldpath,
+          int,newdirfd,const char *,newpath)
+#endif
 _syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
+#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
+_syscall3(int,sys_symlinkat,const char *,oldpath,
+          int,newdirfd,const char *,newpath)
+#endif
+_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
+#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
+_syscall3(int,sys_tgkill,int,tgid,int,pid,int,sig)
+#endif
+#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
+_syscall2(int,sys_tkill,int,tid,int,sig)
+#endif
 #ifdef __NR_exit_group
 _syscall1(int,exit_group,int,error_code)
 #endif
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+_syscall1(int,set_tid_address,int *,tidptr)
+#endif
+#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
+_syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
+#endif
+#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
+_syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
+          const struct timespec *,tsp,int,flags)
+#endif
 
 extern int personality(int);
 extern int flock(int, int);
@@ -173,17 +247,136 @@
 extern int getresgid(gid_t *, gid_t *, gid_t *);
 extern int setgroups(int, gid_t *);
 
-static inline long get_errno(long ret)
+/*
+ * This list is the union of errno values overridden in asm-<arch>/errno.h
+ * minus the errnos that are not actually generic to all archs.
+ */
+static uint16_t host_to_target_errno_table[1200] = {
+    [EIDRM]		= TARGET_EIDRM,
+    [ECHRNG]		= TARGET_ECHRNG,
+    [EL2NSYNC]		= TARGET_EL2NSYNC,
+    [EL3HLT]		= TARGET_EL3HLT,
+    [EL3RST]		= TARGET_EL3RST,
+    [ELNRNG]		= TARGET_ELNRNG,
+    [EUNATCH]		= TARGET_EUNATCH,
+    [ENOCSI]		= TARGET_ENOCSI,
+    [EL2HLT]		= TARGET_EL2HLT,
+    [EDEADLK]		= TARGET_EDEADLK,
+    [ENOLCK]		= TARGET_ENOLCK,
+    [EBADE]		= TARGET_EBADE,
+    [EBADR]		= TARGET_EBADR,
+    [EXFULL]		= TARGET_EXFULL,
+    [ENOANO]		= TARGET_ENOANO,
+    [EBADRQC]		= TARGET_EBADRQC,
+    [EBADSLT]		= TARGET_EBADSLT,
+    [EBFONT]		= TARGET_EBFONT,
+    [ENOSTR]		= TARGET_ENOSTR,
+    [ENODATA]		= TARGET_ENODATA,
+    [ETIME]		= TARGET_ETIME,
+    [ENOSR]		= TARGET_ENOSR,
+    [ENONET]		= TARGET_ENONET,
+    [ENOPKG]		= TARGET_ENOPKG,
+    [EREMOTE]		= TARGET_EREMOTE,
+    [ENOLINK]		= TARGET_ENOLINK,
+    [EADV]		= TARGET_EADV,
+    [ESRMNT]		= TARGET_ESRMNT,
+    [ECOMM]		= TARGET_ECOMM,
+    [EPROTO]		= TARGET_EPROTO,
+    [EDOTDOT]		= TARGET_EDOTDOT,
+    [EMULTIHOP]		= TARGET_EMULTIHOP,
+    [EBADMSG]		= TARGET_EBADMSG,
+    [ENAMETOOLONG]	= TARGET_ENAMETOOLONG,
+    [EOVERFLOW]		= TARGET_EOVERFLOW,
+    [ENOTUNIQ]		= TARGET_ENOTUNIQ,
+    [EBADFD]		= TARGET_EBADFD,
+    [EREMCHG]		= TARGET_EREMCHG,
+    [ELIBACC]		= TARGET_ELIBACC,
+    [ELIBBAD]		= TARGET_ELIBBAD,
+    [ELIBSCN]		= TARGET_ELIBSCN,
+    [ELIBMAX]		= TARGET_ELIBMAX,
+    [ELIBEXEC]		= TARGET_ELIBEXEC,
+    [EILSEQ]		= TARGET_EILSEQ,
+    [ENOSYS]		= TARGET_ENOSYS,
+    [ELOOP]		= TARGET_ELOOP,
+    [ERESTART]		= TARGET_ERESTART,
+    [ESTRPIPE]		= TARGET_ESTRPIPE,
+    [ENOTEMPTY]		= TARGET_ENOTEMPTY,
+    [EUSERS]		= TARGET_EUSERS,
+    [ENOTSOCK]		= TARGET_ENOTSOCK,
+    [EDESTADDRREQ]	= TARGET_EDESTADDRREQ,
+    [EMSGSIZE]		= TARGET_EMSGSIZE,
+    [EPROTOTYPE]	= TARGET_EPROTOTYPE,
+    [ENOPROTOOPT]	= TARGET_ENOPROTOOPT,
+    [EPROTONOSUPPORT]	= TARGET_EPROTONOSUPPORT,
+    [ESOCKTNOSUPPORT]	= TARGET_ESOCKTNOSUPPORT,
+    [EOPNOTSUPP]	= TARGET_EOPNOTSUPP,
+    [EPFNOSUPPORT]	= TARGET_EPFNOSUPPORT,
+    [EAFNOSUPPORT]	= TARGET_EAFNOSUPPORT,
+    [EADDRINUSE]	= TARGET_EADDRINUSE,
+    [EADDRNOTAVAIL]	= TARGET_EADDRNOTAVAIL,
+    [ENETDOWN]		= TARGET_ENETDOWN,
+    [ENETUNREACH]	= TARGET_ENETUNREACH,
+    [ENETRESET]		= TARGET_ENETRESET,
+    [ECONNABORTED]	= TARGET_ECONNABORTED,
+    [ECONNRESET]	= TARGET_ECONNRESET,
+    [ENOBUFS]		= TARGET_ENOBUFS,
+    [EISCONN]		= TARGET_EISCONN,
+    [ENOTCONN]		= TARGET_ENOTCONN,
+    [EUCLEAN]		= TARGET_EUCLEAN,
+    [ENOTNAM]		= TARGET_ENOTNAM,
+    [ENAVAIL]		= TARGET_ENAVAIL,
+    [EISNAM]		= TARGET_EISNAM,
+    [EREMOTEIO]		= TARGET_EREMOTEIO,
+    [ESHUTDOWN]		= TARGET_ESHUTDOWN,
+    [ETOOMANYREFS]	= TARGET_ETOOMANYREFS,
+    [ETIMEDOUT]		= TARGET_ETIMEDOUT,
+    [ECONNREFUSED]	= TARGET_ECONNREFUSED,
+    [EHOSTDOWN]		= TARGET_EHOSTDOWN,
+    [EHOSTUNREACH]	= TARGET_EHOSTUNREACH,
+    [EALREADY]		= TARGET_EALREADY,
+    [EINPROGRESS]	= TARGET_EINPROGRESS,
+    [ESTALE]		= TARGET_ESTALE,
+    [ECANCELED]		= TARGET_ECANCELED,
+    [ENOMEDIUM]		= TARGET_ENOMEDIUM,
+    [EMEDIUMTYPE]	= TARGET_EMEDIUMTYPE,
+#ifdef ENOKEY
+    [ENOKEY]		= TARGET_ENOKEY,
+#endif
+#ifdef EKEYEXPIRED
+    [EKEYEXPIRED]	= TARGET_EKEYEXPIRED,
+#endif
+#ifdef EKEYREVOKED
+    [EKEYREVOKED]	= TARGET_EKEYREVOKED,
+#endif
+#ifdef EKEYREJECTED
+    [EKEYREJECTED]	= TARGET_EKEYREJECTED,
+#endif
+#ifdef EOWNERDEAD
+    [EOWNERDEAD]	= TARGET_EOWNERDEAD,
+#endif
+#ifdef ENOTRECOVERABLE
+    [ENOTRECOVERABLE]	= TARGET_ENOTRECOVERABLE,
+#endif
+	};
+
+static inline int host_to_target_errno(int err)
+{
+    if(host_to_target_errno_table[err])
+        return host_to_target_errno_table[err];
+    return err;
+}
+
+static inline target_long get_errno(target_long ret)
 {
     if (ret == -1)
-        return -errno;
+        return -host_to_target_errno(errno);
     else
         return ret;
 }
 
-static inline int is_error(long ret)
+static inline int is_error(target_long ret)
 {
-    return (unsigned long)ret >= (unsigned long)(-4096);
+    return (target_ulong)ret >= (target_ulong)(-4096);
 }
 
 static target_ulong target_brk;
@@ -191,20 +384,20 @@
 
 void target_set_brk(target_ulong new_brk)
 {
-    target_original_brk = target_brk = new_brk;
+    target_original_brk = target_brk = HOST_PAGE_ALIGN(new_brk);
 }
 
-long do_brk(target_ulong new_brk)
+target_long do_brk(target_ulong new_brk)
 {
     target_ulong brk_page;
-    long mapped_addr;
+    target_long mapped_addr;
     int	new_alloc_size;
 
     if (!new_brk)
         return target_brk;
     if (new_brk < target_original_brk)
         return -ENOMEM;
-    
+
     brk_page = HOST_PAGE_ALIGN(target_brk);
 
     /* If the new brk is less than this, set it and we're done... */
@@ -215,7 +408,7 @@
 
     /* We need to allocate more memory after the brk... */
     new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
-    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size, 
+    mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
                                         PROT_READ|PROT_WRITE,
                                         MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
     if (is_error(mapped_addr)) {
@@ -226,7 +419,7 @@
     }
 }
 
-static inline fd_set *target_to_host_fds(fd_set *fds, 
+static inline fd_set *target_to_host_fds(fd_set *fds,
                                          target_long *target_fds, int n)
 {
 #if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
@@ -248,7 +441,7 @@
 #endif
 }
 
-static inline void host_to_target_fds(target_long *target_fds, 
+static inline void host_to_target_fds(target_long *target_fds,
                                       fd_set *fds, int n)
 {
 #if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
@@ -278,7 +471,7 @@
 #define HOST_HZ 100
 #endif
 
-static inline long host_to_target_clock_t(long ticks)
+static inline target_long host_to_target_clock_t(long ticks)
 {
 #if HOST_HZ == TARGET_HZ
     return ticks;
@@ -337,15 +530,15 @@
 }
 
 
-static long do_select(long n, 
-                      target_ulong rfd_p, target_ulong wfd_p, 
-                      target_ulong efd_p, target_ulong target_tv)
+static target_long do_select(int n,
+                             target_ulong rfd_p, target_ulong wfd_p,
+                             target_ulong efd_p, target_ulong target_tv)
 {
     fd_set rfds, wfds, efds;
     fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
     target_long *target_rfds, *target_wfds, *target_efds;
     struct timeval tv, *tv_ptr;
-    long ret;
+    target_long ret;
     int ok;
 
     if (rfd_p) {
@@ -369,7 +562,7 @@
         target_efds = NULL;
         efds_ptr = NULL;
     }
-            
+
     if (target_tv) {
         target_to_host_timeval(&tv, target_tv);
         tv_ptr = &tv;
@@ -434,7 +627,7 @@
         void *data = CMSG_DATA(cmsg);
         void *target_data = TARGET_CMSG_DATA(target_cmsg);
 
-        int len = tswapl(target_cmsg->cmsg_len) 
+        int len = tswapl(target_cmsg->cmsg_len)
                   - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
 
         space += CMSG_SPACE(len);
@@ -511,17 +704,18 @@
     msgh->msg_controllen = tswapl(space);
 }
 
-static long do_setsockopt(int sockfd, int level, int optname, 
-                          target_ulong optval, socklen_t optlen)
+static target_long do_setsockopt(int sockfd, int level, int optname,
+                                 target_ulong optval, socklen_t optlen)
 {
-    int val, ret;
-            
+    target_long ret;
+    int val;
+
     switch(level) {
     case SOL_TCP:
         /* TCP options all take an 'int' value.  */
         if (optlen < sizeof(uint32_t))
             return -EINVAL;
-        
+
         val = tget32(optval);
         ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
         break;
@@ -631,10 +825,11 @@
     return ret;
 }
 
-static long do_getsockopt(int sockfd, int level, int optname, 
-                          target_ulong optval, target_ulong optlen)
+static target_long do_getsockopt(int sockfd, int level, int optname,
+                                 target_ulong optval, target_ulong optlen)
 {
-    int len, lv, val, ret;
+    target_long ret;
+    int len, lv, val;
 
     switch(level) {
     case TARGET_SOL_SOCKET:
@@ -750,7 +945,7 @@
     unlock_user (target_vec, target_addr, 0);
 }
 
-static long do_socket(int domain, int type, int protocol)
+static target_long do_socket(int domain, int type, int protocol)
 {
 #if defined(TARGET_MIPS)
     switch(type) {
@@ -777,28 +972,28 @@
     return get_errno(socket(domain, type, protocol));
 }
 
-static long do_bind(int sockfd, target_ulong target_addr,
-                    socklen_t addrlen)
+static target_long do_bind(int sockfd, target_ulong target_addr,
+                           socklen_t addrlen)
 {
     void *addr = alloca(addrlen);
-    
+
     target_to_host_sockaddr(addr, target_addr, addrlen);
     return get_errno(bind(sockfd, addr, addrlen));
 }
 
-static long do_connect(int sockfd, target_ulong target_addr,
-                    socklen_t addrlen)
+static target_long do_connect(int sockfd, target_ulong target_addr,
+                              socklen_t addrlen)
 {
     void *addr = alloca(addrlen);
-    
+
     target_to_host_sockaddr(addr, target_addr, addrlen);
     return get_errno(connect(sockfd, addr, addrlen));
 }
 
-static long do_sendrecvmsg(int fd, target_ulong target_msg,
-                           int flags, int send)
+static target_long do_sendrecvmsg(int fd, target_ulong target_msg,
+                                  int flags, int send)
 {
-    long ret;
+    target_long ret;
     struct target_msghdr *msgp;
     struct msghdr msg;
     int count;
@@ -818,14 +1013,14 @@
     msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
     msg.msg_control = alloca(msg.msg_controllen);
     msg.msg_flags = tswap32(msgp->msg_flags);
-    
+
     count = tswapl(msgp->msg_iovlen);
     vec = alloca(count * sizeof(struct iovec));
     target_vec = tswapl(msgp->msg_iov);
     lock_iovec(vec, target_vec, count, send);
     msg.msg_iovlen = count;
     msg.msg_iov = vec;
-    
+
     if (send) {
         target_to_host_cmsg(&msg, msgp);
         ret = get_errno(sendmsg(fd, &msg, flags));
@@ -838,12 +1033,12 @@
     return ret;
 }
 
-static long do_accept(int fd, target_ulong target_addr,
-                      target_ulong target_addrlen)
+static target_long do_accept(int fd, target_ulong target_addr,
+                             target_ulong target_addrlen)
 {
     socklen_t addrlen = tget32(target_addrlen);
     void *addr = alloca(addrlen);
-    long ret;
+    target_long ret;
 
     ret = get_errno(accept(fd, addr, &addrlen));
     if (!is_error(ret)) {
@@ -853,12 +1048,12 @@
     return ret;
 }
 
-static long do_getpeername(int fd, target_ulong target_addr,
-                           target_ulong target_addrlen)
+static target_long do_getpeername(int fd, target_ulong target_addr,
+                                  target_ulong target_addrlen)
 {
     socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(target_addrlen);
-    long ret;
+    void *addr = alloca(addrlen);
+    target_long ret;
 
     ret = get_errno(getpeername(fd, addr, &addrlen));
     if (!is_error(ret)) {
@@ -868,12 +1063,12 @@
     return ret;
 }
 
-static long do_getsockname(int fd, target_ulong target_addr,
-                           target_ulong target_addrlen)
+static target_long do_getsockname(int fd, target_ulong target_addr,
+                                  target_ulong target_addrlen)
 {
     socklen_t addrlen = tget32(target_addrlen);
-    void *addr = alloca(target_addrlen);
-    long ret;
+    void *addr = alloca(addrlen);
+    target_long ret;
 
     ret = get_errno(getsockname(fd, addr, &addrlen));
     if (!is_error(ret)) {
@@ -883,11 +1078,11 @@
     return ret;
 }
 
-static long do_socketpair(int domain, int type, int protocol,
-                          target_ulong target_tab)
+static target_long do_socketpair(int domain, int type, int protocol,
+                                 target_ulong target_tab)
 {
     int tab[2];
-    long ret;
+    target_long ret;
 
     ret = get_errno(socketpair(domain, type, protocol, tab));
     if (!is_error(ret)) {
@@ -897,12 +1092,12 @@
     return ret;
 }
 
-static long do_sendto(int fd, target_ulong msg, size_t len, int flags,
-                      target_ulong target_addr, socklen_t addrlen)
+static target_long do_sendto(int fd, target_ulong msg, size_t len, int flags,
+                             target_ulong target_addr, socklen_t addrlen)
 {
     void *addr;
     void *host_msg;
-    long ret;
+    target_long ret;
 
     host_msg = lock_user(msg, len, 1);
     if (target_addr) {
@@ -916,13 +1111,14 @@
     return ret;
 }
 
-static long do_recvfrom(int fd, target_ulong msg, size_t len, int flags,
-                        target_ulong target_addr, target_ulong target_addrlen)
+static target_long do_recvfrom(int fd, target_ulong msg, size_t len, int flags,
+                               target_ulong target_addr,
+                               target_ulong target_addrlen)
 {
     socklen_t addrlen;
     void *addr;
     void *host_msg;
-    long ret;
+    target_long ret;
 
     host_msg = lock_user(msg, len, 0);
     if (target_addr) {
@@ -945,9 +1141,10 @@
     return ret;
 }
 
-static long do_socketcall(int num, target_ulong vptr)
+#ifdef TARGET_NR_socketcall
+static target_long do_socketcall(int num, target_ulong vptr)
 {
-    long ret;
+    target_long ret;
     const int n = sizeof(target_ulong);
 
     switch(num) {
@@ -1074,7 +1271,7 @@
             target_msg = tgetl(vptr + n);
             flags = tgetl(vptr + 2 * n);
 
-            ret = do_sendrecvmsg(fd, target_msg, flags, 
+            ret = do_sendrecvmsg(fd, target_msg, flags,
                                  (num == SOCKOP_sendmsg));
         }
         break;
@@ -1107,7 +1304,9 @@
     }
     return ret;
 }
+#endif
 
+#ifdef TARGET_NR_ipc
 #define N_SHM_REGIONS	32
 
 static struct shm_region {
@@ -1115,18 +1314,335 @@
     uint32_t	size;
 } shm_regions[N_SHM_REGIONS];
 
+struct target_ipc_perm
+{
+    target_long __key;
+    target_ulong uid;
+    target_ulong gid;
+    target_ulong cuid;
+    target_ulong cgid;
+    unsigned short int mode;
+    unsigned short int __pad1;
+    unsigned short int __seq;
+    unsigned short int __pad2;
+    target_ulong __unused1;
+    target_ulong __unused2;
+};
+
+struct target_semid_ds
+{
+  struct target_ipc_perm sem_perm;
+  target_ulong sem_otime;
+  target_ulong __unused1;
+  target_ulong sem_ctime;
+  target_ulong __unused2;
+  target_ulong sem_nsems;
+  target_ulong __unused3;
+  target_ulong __unused4;
+};
+
+static inline void target_to_host_ipc_perm(struct ipc_perm *host_ip,
+                                           target_ulong target_addr)
+{
+    struct target_ipc_perm *target_ip;
+    struct target_semid_ds *target_sd;
+
+    lock_user_struct(target_sd, target_addr, 1);
+    target_ip=&(target_sd->sem_perm);
+    host_ip->__key = tswapl(target_ip->__key);
+    host_ip->uid = tswapl(target_ip->uid);
+    host_ip->gid = tswapl(target_ip->gid);
+    host_ip->cuid = tswapl(target_ip->cuid);
+    host_ip->cgid = tswapl(target_ip->cgid);
+    host_ip->mode = tswapl(target_ip->mode);
+    unlock_user_struct(target_sd, target_addr, 0);
+}
+
+static inline void host_to_target_ipc_perm(target_ulong target_addr,
+                                           struct ipc_perm *host_ip)
+{
+    struct target_ipc_perm *target_ip;
+    struct target_semid_ds *target_sd;
+
+    lock_user_struct(target_sd, target_addr, 0);
+    target_ip = &(target_sd->sem_perm);
+    target_ip->__key = tswapl(host_ip->__key);
+    target_ip->uid = tswapl(host_ip->uid);
+    target_ip->gid = tswapl(host_ip->gid);
+    target_ip->cuid = tswapl(host_ip->cuid);
+    target_ip->cgid = tswapl(host_ip->cgid);
+    target_ip->mode = tswapl(host_ip->mode);
+    unlock_user_struct(target_sd, target_addr, 1);
+}
+
+static inline void target_to_host_semid_ds(struct semid_ds *host_sd,
+                                          target_ulong target_addr)
+{
+    struct target_semid_ds *target_sd;
+
+    lock_user_struct(target_sd, target_addr, 1);
+    target_to_host_ipc_perm(&(host_sd->sem_perm),target_addr);
+    host_sd->sem_nsems = tswapl(target_sd->sem_nsems);
+    host_sd->sem_otime = tswapl(target_sd->sem_otime);
+    host_sd->sem_ctime = tswapl(target_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 0);
+}
+
+static inline void host_to_target_semid_ds(target_ulong target_addr,
+                                           struct semid_ds *host_sd)
+{
+    struct target_semid_ds *target_sd;
+
+    lock_user_struct(target_sd, target_addr, 0);
+    host_to_target_ipc_perm(target_addr,&(host_sd->sem_perm));
+    target_sd->sem_nsems = tswapl(host_sd->sem_nsems);
+    target_sd->sem_otime = tswapl(host_sd->sem_otime);
+    target_sd->sem_ctime = tswapl(host_sd->sem_ctime);
+    unlock_user_struct(target_sd, target_addr, 1);
+}
+
 union semun {
 	int val;
-	struct senid_ds *buf;
+	struct semid_ds *buf;
 	unsigned short *array;
 };
 
+union target_semun {
+	int val;
+	target_long buf;
+	unsigned short int *array;
+};
+
+static inline void target_to_host_semun(int cmd,
+                                        union semun *host_su,
+                                        target_ulong target_addr,
+                                        struct semid_ds *ds)
+{
+    union target_semun *target_su;
+
+    switch( cmd ) {
+	case IPC_STAT:
+	case IPC_SET:
+           lock_user_struct(target_su, target_addr, 1);
+	   target_to_host_semid_ds(ds,target_su->buf);
+	   host_su->buf = ds;
+           unlock_user_struct(target_su, target_addr, 0);
+	   break;
+	case GETVAL:
+	case SETVAL:
+           lock_user_struct(target_su, target_addr, 1);
+	   host_su->val = tswapl(target_su->val);
+           unlock_user_struct(target_su, target_addr, 0);
+	   break;
+	case GETALL:
+	case SETALL:
+           lock_user_struct(target_su, target_addr, 1);
+	   *host_su->array = tswap16(*target_su->array);
+           unlock_user_struct(target_su, target_addr, 0);
+	   break;
+	default:
+           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+    }
+}
+
+static inline void host_to_target_semun(int cmd,
+                                        target_ulong target_addr,
+                                        union semun *host_su,
+                                        struct semid_ds *ds)
+{
+    union target_semun *target_su;
+
+    switch( cmd ) {
+	case IPC_STAT:
+	case IPC_SET:
+           lock_user_struct(target_su, target_addr, 0);
+	   host_to_target_semid_ds(target_su->buf,ds);
+           unlock_user_struct(target_su, target_addr, 1);
+	   break;
+	case GETVAL:
+	case SETVAL:
+           lock_user_struct(target_su, target_addr, 0);
+	   target_su->val = tswapl(host_su->val);
+           unlock_user_struct(target_su, target_addr, 1);
+	   break;
+	case GETALL:
+	case SETALL:
+           lock_user_struct(target_su, target_addr, 0);
+	   *target_su->array = tswap16(*host_su->array);
+           unlock_user_struct(target_su, target_addr, 1);
+	   break;
+        default:
+           gemu_log("semun operation not fully supported: %d\n", (int)cmd);
+    }
+}
+
+static inline target_long do_semctl(int first, int second, int third,
+                                    target_long ptr)
+{
+    union semun arg;
+    struct semid_ds dsarg;
+    int cmd = third&0xff;
+    target_long ret = 0;
+
+    switch( cmd ) {
+	case GETVAL:
+            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            ret = get_errno(semctl(first, second, cmd, arg));
+            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            break;
+	case SETVAL:
+            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            ret = get_errno(semctl(first, second, cmd, arg));
+            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            break;
+	case GETALL:
+            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            ret = get_errno(semctl(first, second, cmd, arg));
+            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            break;
+	case SETALL:
+            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            ret = get_errno(semctl(first, second, cmd, arg));
+            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            break;
+	case IPC_STAT:
+            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            ret = get_errno(semctl(first, second, cmd, arg));
+            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            break;
+	case IPC_SET:
+            target_to_host_semun(cmd,&arg,ptr,&dsarg);
+            ret = get_errno(semctl(first, second, cmd, arg));
+            host_to_target_semun(cmd,ptr,&arg,&dsarg);
+            break;
+    default:
+            ret = get_errno(semctl(first, second, cmd, arg));
+    }
+
+    return ret;
+}
+
+struct target_msqid_ds
+{
+  struct target_ipc_perm msg_perm;
+  target_ulong msg_stime;
+  target_ulong __unused1;
+  target_ulong msg_rtime;
+  target_ulong __unused2;
+  target_ulong msg_ctime;
+  target_ulong __unused3;
+  target_ulong __msg_cbytes;
+  target_ulong msg_qnum;
+  target_ulong msg_qbytes;
+  target_ulong msg_lspid;
+  target_ulong msg_lrpid;
+  target_ulong __unused4;
+  target_ulong __unused5;
+};
+
+static inline void target_to_host_msqid_ds(struct msqid_ds *host_md,
+                                           target_ulong target_addr)
+{
+    struct target_msqid_ds *target_md;
+
+    lock_user_struct(target_md, target_addr, 1);
+    target_to_host_ipc_perm(&(host_md->msg_perm),target_addr);
+    host_md->msg_stime = tswapl(target_md->msg_stime);
+    host_md->msg_rtime = tswapl(target_md->msg_rtime);
+    host_md->msg_ctime = tswapl(target_md->msg_ctime);
+    host_md->__msg_cbytes = tswapl(target_md->__msg_cbytes);
+    host_md->msg_qnum = tswapl(target_md->msg_qnum);
+    host_md->msg_qbytes = tswapl(target_md->msg_qbytes);
+    host_md->msg_lspid = tswapl(target_md->msg_lspid);
+    host_md->msg_lrpid = tswapl(target_md->msg_lrpid);
+    unlock_user_struct(target_md, target_addr, 0);
+}
+
+static inline void host_to_target_msqid_ds(target_ulong target_addr,
+                                           struct msqid_ds *host_md)
+{
+    struct target_msqid_ds *target_md;
+
+    lock_user_struct(target_md, target_addr, 0);
+    host_to_target_ipc_perm(target_addr,&(host_md->msg_perm));
+    target_md->msg_stime = tswapl(host_md->msg_stime);
+    target_md->msg_rtime = tswapl(host_md->msg_rtime);
+    target_md->msg_ctime = tswapl(host_md->msg_ctime);
+    target_md->__msg_cbytes = tswapl(host_md->__msg_cbytes);
+    target_md->msg_qnum = tswapl(host_md->msg_qnum);
+    target_md->msg_qbytes = tswapl(host_md->msg_qbytes);
+    target_md->msg_lspid = tswapl(host_md->msg_lspid);
+    target_md->msg_lrpid = tswapl(host_md->msg_lrpid);
+    unlock_user_struct(target_md, target_addr, 1);
+}
+
+static inline target_long do_msgctl(int first, int second, target_long ptr)
+{
+    struct msqid_ds dsarg;
+    int cmd = second&0xff;
+    target_long ret = 0;
+    switch( cmd ) {
+    case IPC_STAT:
+    case IPC_SET:
+        target_to_host_msqid_ds(&dsarg,ptr);
+        ret = get_errno(msgctl(first, cmd, &dsarg));
+        host_to_target_msqid_ds(ptr,&dsarg);
+    default:
+        ret = get_errno(msgctl(first, cmd, &dsarg));
+    }
+    return ret;
+}
+
+struct target_msgbuf {
+	target_ulong mtype;
+	char	mtext[1];
+};
+
+static inline target_long do_msgsnd(int msqid, target_long msgp,
+                                    unsigned int msgsz, int msgflg)
+{
+    struct target_msgbuf *target_mb;
+    struct msgbuf *host_mb;
+    target_long ret = 0;
+
+    lock_user_struct(target_mb,msgp,0);
+    host_mb = malloc(msgsz+sizeof(long));
+    host_mb->mtype = tswapl(target_mb->mtype);
+    memcpy(host_mb->mtext,target_mb->mtext,msgsz);
+    ret = get_errno(msgsnd(msqid, host_mb, msgsz, msgflg));
+    free(host_mb);
+    unlock_user_struct(target_mb, msgp, 0);
+
+    return ret;
+}
+
+static inline target_long do_msgrcv(int msqid, target_long msgp,
+                                    unsigned int msgsz, int msgtype,
+                                    int msgflg)
+{
+    struct target_msgbuf *target_mb;
+    struct msgbuf *host_mb;
+    target_long ret = 0;
+
+    lock_user_struct(target_mb, msgp, 0);
+    host_mb = malloc(msgsz+sizeof(long));
+    ret = get_errno(msgrcv(msqid, host_mb, msgsz, 1, msgflg));
+    if (ret > 0)
+    	memcpy(target_mb->mtext, host_mb->mtext, ret);
+    target_mb->mtype = tswapl(host_mb->mtype);
+    free(host_mb);
+    unlock_user_struct(target_mb, msgp, 0);
+
+    return ret;
+}
+
 /* ??? This only works with linear mappings.  */
-static long do_ipc(long call, long first, long second, long third,
-		   long ptr, long fifth)
+static target_long do_ipc(unsigned int call, int first,
+                          int second, int third,
+                          target_long ptr, target_long fifth)
 {
     int version;
-    long ret = 0;
+    target_long ret = 0;
     unsigned long raddr;
     struct shmid_ds shm_info;
     int i;
@@ -1144,12 +1660,11 @@
         break;
 
     case IPCOP_semctl:
-        ret = get_errno(semctl(first, second, third, ((union semun*)ptr)->val));
-
+        ret = do_semctl(first, second, third, ptr);
         break;
 
     case IPCOP_semtimedop:
-        gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version);
+        gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
         ret = -ENOSYS;
         break;
 
@@ -1158,27 +1673,27 @@
 		break;
 
 	case IPCOP_msgsnd:
-		ret = get_errno(msgsnd(first, (struct msgbuf *) ptr, second, third));
+		ret = do_msgsnd(first, ptr, second, third);
 		break;
 
 	case IPCOP_msgctl:
-		ret = get_errno(msgctl(first, second, (struct msqid_ds *) ptr));
+        	ret = do_msgctl(first, second, ptr);
 		break;
 
 	case IPCOP_msgrcv:
-		{
-			struct ipc_kludge
-			{
-				void *__unbounded msgp;
-				long int msgtyp;
-			};
+                {
+                      struct ipc_kludge
+                      {
+                              void *__unbounded msgp;
+                              long int msgtyp;
+                      };
 
-			struct ipc_kludge *foo = (struct ipc_kludge *) ptr;
-			struct msgbuf *msgp = (struct msgbuf *) foo->msgp;
+                      struct ipc_kludge *foo = (struct ipc_kludge *) ptr;
+                      struct msgbuf *msgp = (struct msgbuf *) foo->msgp;
 
-			ret = get_errno(msgrcv(first, msgp, second, 0, third));
+                      ret = do_msgrcv(first, (long)msgp, second, 0, third);
 
-		}
+                }
 		break;
 
     case IPCOP_shmat:
@@ -1188,7 +1703,7 @@
             break;
         raddr = ret;
 	/* find out the length of the shared memory segment */
-        
+
         ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
         if (is_error(ret)) {
             /* can't get length, bail out */
@@ -1205,7 +1720,7 @@
                 break;
 	    }
 	}
-	if (put_user(raddr, (uint32_t *)third))
+	if (put_user(raddr, (target_ulong *)third))
             return -EFAULT;
         ret = 0;
 	break;
@@ -1239,12 +1754,13 @@
         break;
     default:
     unimplemented:
-	gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version);
+	gemu_log("Unsupported ipc call: %d (version %d)\n", call, version);
 	ret = -ENOSYS;
 	break;
     }
     return ret;
 }
+#endif
 
 /* kernel structure types definitions */
 #define IFNAMSIZ        16
@@ -1285,11 +1801,11 @@
 };
 
 /* ??? Implement proper locking for ioctls.  */
-static long do_ioctl(long fd, long cmd, long arg)
+static target_long do_ioctl(int fd, target_long cmd, target_long arg)
 {
     const IOCTLEntry *ie;
     const argtype *arg_type;
-    long ret;
+    target_long ret;
     uint8_t buf_temp[MAX_STRUCT_SIZE];
     int target_size;
     void *argptr;
@@ -1297,7 +1813,7 @@
     ie = ioctl_entries;
     for(;;) {
         if (ie->target_cmd == 0) {
-            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd);
+            gemu_log("Unsupported ioctl: cmd=0x%04lx\n", (long)cmd);
             return -ENOSYS;
         }
         if (ie->target_cmd == cmd)
@@ -1306,7 +1822,7 @@
     }
     arg_type = ie->arg_type;
 #if defined(DEBUG)
-    gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name);
+    gemu_log("ioctl: cmd=0x%04lx (%s)\n", (long)cmd, ie->name);
 #endif
     switch(arg_type[0]) {
     case TYPE_NULL:
@@ -1351,7 +1867,8 @@
         }
         break;
     default:
-        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]);
+        gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n",
+                 (long)cmd, arg_type[0]);
         ret = -ENOSYS;
         break;
     }
@@ -1462,51 +1979,51 @@
 {
     struct host_termios *host = dst;
     const struct target_termios *target = src;
-    
-    host->c_iflag = 
+
+    host->c_iflag =
         target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
-    host->c_oflag = 
+    host->c_oflag =
         target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
-    host->c_cflag = 
+    host->c_cflag =
         target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
-    host->c_lflag = 
+    host->c_lflag =
         target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
     host->c_line = target->c_line;
-    
-    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR]; 
-    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT]; 
-    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];       
-    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL]; 
-    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];   
-    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME]; 
-    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];   
-    host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC]; 
-    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];       
-    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP]; 
-    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP]; 
-    host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];   
-    host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];   
-    host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];   
-    host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];     
-    host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];       
-    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2]; 
+
+    host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
+    host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
+    host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
+    host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
+    host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
+    host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
+    host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
+    host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
+    host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
+    host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
+    host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
+    host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
+    host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
+    host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
+    host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
+    host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
+    host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
 }
-  
+
 static void host_to_target_termios (void *dst, const void *src)
 {
     struct target_termios *target = dst;
     const struct host_termios *host = src;
 
-    target->c_iflag = 
+    target->c_iflag =
         tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
-    target->c_oflag = 
+    target->c_oflag =
         tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
-    target->c_cflag = 
+    target->c_cflag =
         tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
-    target->c_lflag = 
+    target->c_lflag =
         tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
     target->c_line = host->c_line;
-  
+
     target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
     target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
     target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
@@ -1587,7 +2104,7 @@
 }
 
 /* XXX: add locking support */
-static int write_ldt(CPUX86State *env, 
+static int write_ldt(CPUX86State *env,
                      target_ulong ptr, unsigned long bytecount, int oldmode)
 {
     struct target_modify_ldt_ldt_s ldt_info;
@@ -1604,7 +2121,7 @@
     ldt_info.limit = tswap32(target_ldt_info->limit);
     ldt_info.flags = tswap32(target_ldt_info->flags);
     unlock_user_struct(target_ldt_info, ptr, 0);
-    
+
     if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
         return -EINVAL;
     seg_32bit = ldt_info.flags & 1;
@@ -1645,7 +2162,7 @@
             goto install;
         }
     }
-    
+
     entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
         (ldt_info.limit & 0x0ffff);
     entry_2 = (ldt_info.base_addr & 0xff000000) |
@@ -1672,7 +2189,7 @@
 int do_modify_ldt(CPUX86State *env, int func, target_ulong ptr, unsigned long bytecount)
 {
     int ret = -ENOSYS;
-    
+
     switch (func) {
     case 0:
         ret = read_ldt(ptr, bytecount);
@@ -1701,13 +2218,13 @@
     return 0;
 }
 
-int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
+int do_fork(CPUState *env, unsigned int flags, target_ulong newsp)
 {
     int ret;
     TaskState *ts;
     uint8_t *new_stack;
     CPUState *new_env;
-    
+
     if (flags & CLONE_VM) {
         ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
         memset(ts, 0, sizeof(TaskState));
@@ -1717,8 +2234,7 @@
         ts->next = first_task_state;
         first_task_state = ts;
         /* we create a new CPU instance. */
-        new_env = cpu_init();
-        memcpy(new_env, env, sizeof(CPUState));
+        new_env = cpu_copy(env);
 #if defined(TARGET_I386)
         if (!newsp)
             newsp = env->regs[R_ESP];
@@ -1743,12 +2259,14 @@
         new_env->dregs[0] = 0;
         /* ??? is this sufficient?  */
 #elif defined(TARGET_MIPS)
-        printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
+        if (!newsp)
+            newsp = env->gpr[29][env->current_tc];
+        new_env->gpr[29][env->current_tc] = newsp;
 #elif defined(TARGET_PPC)
         if (!newsp)
             newsp = env->gpr[1];
         new_env->gpr[1] = newsp;
-        { 
+        {
             int i;
             for (i = 7; i < 32; i++)
                 new_env->gpr[i] = 0;
@@ -1758,6 +2276,16 @@
 	  newsp = env->gregs[15];
 	new_env->gregs[15] = newsp;
 	/* XXXXX */
+#elif defined(TARGET_ALPHA)
+       if (!newsp)
+         newsp = env->ir[30];
+       new_env->ir[30] = newsp;
+        /* ? */
+        {
+            int i;
+            for (i = 7; i < 30; i++)
+                new_env->ir[i] = 0;
+        }
 #else
 #error unsupported target CPU
 #endif
@@ -1776,16 +2304,23 @@
     return ret;
 }
 
-static long do_fcntl(int fd, int cmd, target_ulong arg)
+static target_long do_fcntl(int fd, int cmd, target_ulong arg)
 {
     struct flock fl;
     struct target_flock *target_fl;
     struct flock64 fl64;
     struct target_flock64 *target_fl64;
-    long ret;
+    target_long ret;
 
     switch(cmd) {
     case TARGET_F_GETLK:
+        lock_user_struct(target_fl, arg, 1);
+        fl.l_type = tswap16(target_fl->l_type);
+        fl.l_whence = tswap16(target_fl->l_whence);
+        fl.l_start = tswapl(target_fl->l_start);
+        fl.l_len = tswapl(target_fl->l_len);
+        fl.l_pid = tswapl(target_fl->l_pid);
+        unlock_user_struct(target_fl, arg, 0);
         ret = fcntl(fd, cmd, &fl);
         if (ret == 0) {
             lock_user_struct(target_fl, arg, 0);
@@ -1797,7 +2332,7 @@
             unlock_user_struct(target_fl, arg, 1);
         }
         break;
-        
+
     case TARGET_F_SETLK:
     case TARGET_F_SETLKW:
         lock_user_struct(target_fl, arg, 1);
@@ -1809,8 +2344,15 @@
         unlock_user_struct(target_fl, arg, 0);
         ret = fcntl(fd, cmd, &fl);
         break;
-        
+
     case TARGET_F_GETLK64:
+        lock_user_struct(target_fl64, arg, 1);
+        fl64.l_type = tswap16(target_fl64->l_type) >> 1;
+        fl64.l_whence = tswap16(target_fl64->l_whence);
+        fl64.l_start = tswapl(target_fl64->l_start);
+        fl64.l_len = tswapl(target_fl64->l_len);
+        fl64.l_pid = tswap16(target_fl64->l_pid);
+        unlock_user_struct(target_fl64, arg, 0);
         ret = fcntl(fd, cmd >> 1, &fl64);
         if (ret == 0) {
             lock_user_struct(target_fl64, arg, 0);
@@ -1892,8 +2434,8 @@
     const argtype *arg_type;
     int size;
 
-#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def); 
-#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def); 
+#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
+#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
 #include "syscall_types.h"
 #undef STRUCT
 #undef STRUCT_SPECIAL
@@ -1906,20 +2448,20 @@
             TARGET_IOC_SIZEMASK) {
             arg_type = ie->arg_type;
             if (arg_type[0] != TYPE_PTR) {
-                fprintf(stderr, "cannot patch size for ioctl 0x%x\n", 
+                fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
                         ie->target_cmd);
                 exit(1);
             }
             arg_type++;
             size = thunk_type_size(arg_type, 0);
-            ie->target_cmd = (ie->target_cmd & 
+            ie->target_cmd = (ie->target_cmd &
                               ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
                 (size << TARGET_IOC_SIZESHIFT);
         }
         /* automatic consistency check if same arch */
 #if defined(__i386__) && defined(TARGET_I386)
         if (ie->target_cmd != ie->host_cmd) {
-            fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n", 
+            fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n",
                     ie->target_cmd, ie->host_cmd);
         }
 #endif
@@ -1927,6 +2469,7 @@
     }
 }
 
+#if TARGET_LONG_BITS == 32
 static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
 {
 #ifdef TARGET_WORDS_BIG_ENDIAN
@@ -1935,10 +2478,18 @@
     return ((uint64_t)word1 << 32) | word0;
 #endif
 }
+#else /* TARGET_LONG_BITS == 32 */
+static inline uint64_t target_offset64(uint64_t word0, uint64_t word1)
+{
+    return word0;
+}
+#endif /* TARGET_LONG_BITS != 32 */
 
 #ifdef TARGET_NR_truncate64
-static inline long target_truncate64(void *cpu_env, const char *arg1,
-                                     long arg2, long arg3, long arg4)
+static inline target_long target_truncate64(void *cpu_env, const char *arg1,
+                                            target_long arg2,
+                                            target_long arg3,
+                                            target_long arg4)
 {
 #ifdef TARGET_ARM
     if (((CPUARMState *)cpu_env)->eabi)
@@ -1952,8 +2503,10 @@
 #endif
 
 #ifdef TARGET_NR_ftruncate64
-static inline long target_ftruncate64(void *cpu_env, long arg1, long arg2,
-                                      long arg3, long arg4)
+static inline target_long target_ftruncate64(void *cpu_env, target_long arg1,
+                                             target_long arg2,
+                                             target_long arg3,
+                                             target_long arg4)
 {
 #ifdef TARGET_ARM
     if (((CPUARMState *)cpu_env)->eabi)
@@ -1988,14 +2541,15 @@
     unlock_user_struct(target_ts, target_addr, 1);
 }
 
-long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3, 
-                long arg4, long arg5, long arg6)
+target_long do_syscall(void *cpu_env, int num, target_long arg1,
+                       target_long arg2, target_long arg3, target_long arg4,
+                       target_long arg5, target_long arg6)
 {
-    long ret;
+    target_long ret;
     struct stat st;
     struct statfs stfs;
     void *p;
-    
+
 #ifdef DEBUG
     gemu_log("syscall %d", num);
 #endif
@@ -2027,6 +2581,24 @@
                              arg3));
         unlock_user(p, arg1, 0);
         break;
+#if defined(TARGET_NR_openat) && defined(__NR_openat)
+    case TARGET_NR_openat:
+        if (!arg2) {
+            ret = -EFAULT;
+            goto fail;
+        }
+        p = lock_user_string(arg2);
+        if (!access_ok(VERIFY_READ, p, 1))
+            ret = -EFAULT;
+        else
+            ret = get_errno(sys_openat(arg1,
+                                       path(p),
+                                       target_to_host_bitmask(arg3, fcntl_flags_tbl),
+                                       arg4));
+        if (p)
+            unlock_user(p, arg2, 0);
+        break;
+#endif
     case TARGET_NR_close:
         ret = get_errno(close(arg1));
         break;
@@ -2036,6 +2608,7 @@
     case TARGET_NR_fork:
         ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
         break;
+#ifdef TARGET_NR_waitpid
     case TARGET_NR_waitpid:
         {
             int status;
@@ -2044,11 +2617,14 @@
                 tput32(arg2, status);
         }
         break;
+#endif
+#ifdef TARGET_NR_creat /* not on alpha */
     case TARGET_NR_creat:
         p = lock_user_string(arg1);
         ret = get_errno(creat(p, arg2));
         unlock_user(p, arg1, 0);
         break;
+#endif
     case TARGET_NR_link:
         {
             void * p2;
@@ -2059,11 +2635,48 @@
             unlock_user(p, arg1, 0);
         }
         break;
+#if defined(TARGET_NR_linkat) && defined(__NR_linkat)
+    case TARGET_NR_linkat:
+        if (!arg2 || !arg4) {
+            ret = -EFAULT;
+            goto fail;
+	}
+        {
+            void * p2 = NULL;
+            p  = lock_user_string(arg2);
+            p2 = lock_user_string(arg4);
+            if (!access_ok(VERIFY_READ, p, 1)
+                || !access_ok(VERIFY_READ, p2, 1))
+                ret = -EFAULT;
+            else
+                ret = get_errno(sys_linkat(arg1, p, arg3, p2, arg5));
+            if (p2)
+                unlock_user(p, arg2, 0);
+            if (p)
+                unlock_user(p2, arg4, 0);
+        }
+        break;
+#endif
     case TARGET_NR_unlink:
         p = lock_user_string(arg1);
         ret = get_errno(unlink(p));
         unlock_user(p, arg1, 0);
         break;
+#if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
+    case TARGET_NR_unlinkat:
+        if (!arg2) {
+            ret = -EFAULT;
+            goto fail;
+        }
+        p = lock_user_string(arg2);
+        if (!access_ok(VERIFY_READ, p, 1))
+            ret = -EFAULT;
+        else
+            ret = get_errno(sys_unlinkat(arg1, p, arg3));
+        if (p)
+            unlock_user(p, arg2, 0);
+        break;
+#endif
     case TARGET_NR_execve:
         {
             char **argp, **envp;
@@ -2140,6 +2753,21 @@
         ret = get_errno(mknod(p, arg2, arg3));
         unlock_user(p, arg1, 0);
         break;
+#if defined(TARGET_NR_mknodat) && defined(__NR_mknodat)
+    case TARGET_NR_mknodat:
+        if (!arg2) {
+            ret = -EFAULT;
+            goto fail;
+        }
+        p = lock_user_string(arg2);
+        if (!access_ok(VERIFY_READ, p, 1))
+            ret = -EFAULT;
+        else
+            ret = get_errno(sys_mknodat(arg1, p, arg3, arg4));
+        if (p)
+            unlock_user(p, arg2, 0);
+        break;
+#endif
     case TARGET_NR_chmod:
         p = lock_user_string(arg1);
         ret = get_errno(chmod(p, arg2));
@@ -2156,17 +2784,34 @@
     case TARGET_NR_lseek:
         ret = get_errno(lseek(arg1, arg2, arg3));
         break;
+#ifdef TARGET_NR_getxpid
+    case TARGET_NR_getxpid:
+#else
     case TARGET_NR_getpid:
+#endif
         ret = get_errno(getpid());
         break;
     case TARGET_NR_mount:
-        /* need to look at the data field */
-        goto unimplemented;
+		{
+			/* need to look at the data field */
+			void *p2, *p3;
+			p = lock_user_string(arg1);
+			p2 = lock_user_string(arg2);
+			p3 = lock_user_string(arg3);
+			ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, (const void *)arg5));
+			unlock_user(p, arg1, 0);
+			unlock_user(p2, arg2, 0);
+			unlock_user(p3, arg3, 0);
+			break;
+		}
+#ifdef TARGET_NR_umount
     case TARGET_NR_umount:
         p = lock_user_string(arg1);
         ret = get_errno(umount(p));
         unlock_user(p, arg1, 0);
         break;
+#endif
+#ifdef TARGET_NR_stime /* not on alpha */
     case TARGET_NR_stime:
         {
             time_t host_time;
@@ -2174,18 +2819,24 @@
             ret = get_errno(stime(&host_time));
         }
         break;
+#endif
     case TARGET_NR_ptrace:
         goto unimplemented;
+#ifdef TARGET_NR_alarm /* not on alpha */
     case TARGET_NR_alarm:
         ret = alarm(arg1);
         break;
+#endif
 #ifdef TARGET_NR_oldfstat
     case TARGET_NR_oldfstat:
         goto unimplemented;
 #endif
+#ifdef TARGET_NR_pause /* not on alpha */
     case TARGET_NR_pause:
         ret = get_errno(pause());
         break;
+#endif
+#ifdef TARGET_NR_utime
     case TARGET_NR_utime:
         {
             struct utimbuf tbuf, *host_tbuf;
@@ -2204,6 +2855,7 @@
             unlock_user(p, arg1, 0);
         }
         break;
+#endif
     case TARGET_NR_utimes:
         {
             struct timeval *tvp, tv[2];
@@ -2233,9 +2885,26 @@
         ret = get_errno(access(p, arg2));
         unlock_user(p, arg1, 0);
         break;
+#if defined(TARGET_NR_faccessat) && defined(__NR_faccessat)
+    case TARGET_NR_faccessat:
+        if (!arg2) {
+            ret = -EFAULT;
+            goto fail;
+        }
+        p = lock_user_string(arg2);
+        if (!access_ok(VERIFY_READ, p, 1))
+    	    ret = -EFAULT;
+        else
+            ret = get_errno(sys_faccessat(arg1, p, arg3, arg4));
+        if (p)
+            unlock_user(p, arg2, 0);
+        break;
+#endif
+#ifdef TARGET_NR_nice /* not on alpha */
     case TARGET_NR_nice:
         ret = get_errno(nice(arg1));
         break;
+#endif
 #ifdef TARGET_NR_ftime
     case TARGET_NR_ftime:
         goto unimplemented;
@@ -2257,11 +2926,48 @@
             unlock_user(p, arg1, 0);
         }
         break;
+#if defined(TARGET_NR_renameat) && defined(__NR_renameat)
+    case TARGET_NR_renameat:
+        if (!arg2 || !arg4) {
+            ret = -EFAULT;
+	    goto fail;
+        }
+        {
+            void *p2 = NULL;
+            p  = lock_user_string(arg2);
+            p2 = lock_user_string(arg4);
+            if (!access_ok(VERIFY_READ, p, 1)
+                || !access_ok(VERIFY_READ, p2, 1))
+                ret = -EFAULT;
+            else
+                ret = get_errno(sys_renameat(arg1, p, arg3, p2));
+            if (p2)
+                unlock_user(p2, arg4, 0);
+            if (p)
+                unlock_user(p, arg2, 0);
+        }
+        break;
+#endif
     case TARGET_NR_mkdir:
         p = lock_user_string(arg1);
         ret = get_errno(mkdir(p, arg2));
         unlock_user(p, arg1, 0);
         break;
+#if defined(TARGET_NR_mkdirat) && defined(__NR_mkdirat)
+    case TARGET_NR_mkdirat:
+        if (!arg2) {
+            ret = -EFAULT;
+            goto fail;
+        }
+        p = lock_user_string(arg2);
+        if (!access_ok(VERIFY_READ, p, 1))
+            ret = -EFAULT;
+        else
+            ret = get_errno(sys_mkdirat(arg1, p, arg3));
+        if (p)
+            unlock_user(p, arg2, 0);
+        break;
+#endif
     case TARGET_NR_rmdir:
         p = lock_user_string(arg1);
         ret = get_errno(rmdir(p));
@@ -2275,8 +2981,14 @@
             int host_pipe[2];
             ret = get_errno(pipe(host_pipe));
             if (!is_error(ret)) {
+#if defined(TARGET_MIPS)
+                CPUMIPSState *env = (CPUMIPSState*)cpu_env;
+		env->gpr[3][env->current_tc] = host_pipe[1];
+		ret = host_pipe[0];
+#else
                 tput32(arg1, host_pipe[0]);
                 tput32(arg1 + 4, host_pipe[1]);
+#endif
             }
         }
         break;
@@ -2300,19 +3012,22 @@
     case TARGET_NR_prof:
         goto unimplemented;
 #endif
+#ifdef TARGET_NR_signal
     case TARGET_NR_signal:
         goto unimplemented;
-
+#endif
     case TARGET_NR_acct:
         p = lock_user_string(arg1);
         ret = get_errno(acct(path(p)));
         unlock_user(p, arg1, 0);
         break;
+#ifdef TARGET_NR_umount2 /* not on alpha */
     case TARGET_NR_umount2:
         p = lock_user_string(arg1);
         ret = get_errno(umount2(p, arg2));
         unlock_user(p, arg1, 0);
         break;
+#endif
 #ifdef TARGET_NR_lock
     case TARGET_NR_lock:
         goto unimplemented;
@@ -2351,18 +3066,21 @@
     case TARGET_NR_dup2:
         ret = get_errno(dup2(arg1, arg2));
         break;
+#ifdef TARGET_NR_getppid /* not on alpha */
     case TARGET_NR_getppid:
         ret = get_errno(getppid());
         break;
+#endif
     case TARGET_NR_getpgrp:
         ret = get_errno(getpgrp());
         break;
     case TARGET_NR_setsid:
         ret = get_errno(setsid());
         break;
+#ifdef TARGET_NR_sigaction
     case TARGET_NR_sigaction:
         {
-	#if !defined(TARGET_MIPS)
+#if !defined(TARGET_MIPS)
             struct target_old_sigaction *old_act;
             struct target_sigaction act, oact, *pact;
             if (arg2) {
@@ -2385,7 +3103,7 @@
                 old_act->sa_restorer = oact.sa_restorer;
                 unlock_user_struct(old_act, arg3, 1);
             }
-	#else
+#else
 	    struct target_sigaction act, oact, *pact, *old_act;
 
 	    if (arg2) {
@@ -2411,9 +3129,10 @@
 		old_act->sa_mask.sig[3] = 0;
 		unlock_user_struct(old_act, arg3, 1);
 	    }
-	#endif
+#endif
         }
         break;
+#endif
     case TARGET_NR_rt_sigaction:
         {
             struct target_sigaction *act;
@@ -2434,6 +3153,7 @@
                 unlock_user_struct(oact, arg3, 1);
         }
         break;
+#ifdef TARGET_NR_sgetmask /* not on alpha */
     case TARGET_NR_sgetmask:
         {
             sigset_t cur_set;
@@ -2443,6 +3163,8 @@
             ret = target_set;
         }
         break;
+#endif
+#ifdef TARGET_NR_ssetmask /* not on alpha */
     case TARGET_NR_ssetmask:
         {
             sigset_t set, oset, cur_set;
@@ -2455,11 +3177,13 @@
             ret = target_set;
         }
         break;
+#endif
+#ifdef TARGET_NR_sigprocmask
     case TARGET_NR_sigprocmask:
         {
             int how = arg1;
             sigset_t set, oldset, *set_ptr;
-            
+
             if (arg2) {
                 switch(how) {
                 case TARGET_SIG_BLOCK:
@@ -2491,11 +3215,12 @@
             }
         }
         break;
+#endif
     case TARGET_NR_rt_sigprocmask:
         {
             int how = arg1;
             sigset_t set, oldset, *set_ptr;
-            
+
             if (arg2) {
                 switch(how) {
                 case TARGET_SIG_BLOCK:
@@ -2527,6 +3252,7 @@
             }
         }
         break;
+#ifdef TARGET_NR_sigpending
     case TARGET_NR_sigpending:
         {
             sigset_t set;
@@ -2538,6 +3264,7 @@
             }
         }
         break;
+#endif
     case TARGET_NR_rt_sigpending:
         {
             sigset_t set;
@@ -2549,6 +3276,7 @@
             }
         }
         break;
+#ifdef TARGET_NR_sigsuspend
     case TARGET_NR_sigsuspend:
         {
             sigset_t set;
@@ -2558,6 +3286,7 @@
             ret = get_errno(sigsuspend(&set));
         }
         break;
+#endif
     case TARGET_NR_rt_sigsuspend:
         {
             sigset_t set;
@@ -2572,7 +3301,7 @@
             sigset_t set;
             struct timespec uts, *puts;
             siginfo_t uinfo;
-            
+
             p = lock_user(arg1, sizeof(target_sigset_t), 1);
             target_to_host_sigset(&set, p);
             unlock_user(p, arg1, 0);
@@ -2599,10 +3328,12 @@
             ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
         }
         break;
+#ifdef TARGET_NR_sigreturn
     case TARGET_NR_sigreturn:
         /* NOTE: ret is eax, so not transcoding must be done */
         ret = do_sigreturn(cpu_env);
         break;
+#endif
     case TARGET_NR_rt_sigreturn:
         /* NOTE: ret is eax, so not transcoding must be done */
         ret = do_rt_sigreturn(cpu_env);
@@ -2631,7 +3362,7 @@
             int resource = arg1;
             struct target_rlimit *target_rlim;
             struct rlimit rlim;
-            
+
             ret = get_errno(getrlimit(resource, &rlim));
             if (!is_error(ret)) {
                 lock_user_struct(target_rlim, arg2, 0);
@@ -2694,6 +3425,28 @@
             unlock_user(p, arg1, 0);
         }
         break;
+#if defined(TARGET_NR_symlinkat) && defined(__NR_symlinkat)
+    case TARGET_NR_symlinkat:
+        if (!arg1 || !arg3) {
+            ret = -EFAULT;
+	    goto fail;
+	}
+        {
+            void *p2 = NULL;
+            p  = lock_user_string(arg1);
+            p2 = lock_user_string(arg3);
+            if (!access_ok(VERIFY_READ, p, 1)
+                || !access_ok(VERIFY_READ, p2, 1))
+                ret = -EFAULT;
+            else
+                ret = get_errno(sys_symlinkat(p, arg2, p2));
+            if (p2)
+                unlock_user(p2, arg3, 0);
+            if (p)
+                unlock_user(p, arg1, 0);
+        }
+        break;
+#endif
 #ifdef TARGET_NR_oldlstat
     case TARGET_NR_oldlstat:
         goto unimplemented;
@@ -2708,17 +3461,46 @@
             unlock_user(p, arg1, 0);
         }
         break;
+#if defined(TARGET_NR_readlinkat) && defined(__NR_readlinkat)
+    case TARGET_NR_readlinkat:
+        if (!arg2 || !arg3) {
+            ret = -EFAULT;
+            goto fail;
+	}
+        {
+            void *p2 = NULL;
+            p  = lock_user_string(arg2);
+            p2 = lock_user(arg3, arg4, 0);
+            if (!access_ok(VERIFY_READ, p, 1)
+                || !access_ok(VERIFY_READ, p2, 1))
+        	ret = -EFAULT;
+            else
+                ret = get_errno(sys_readlinkat(arg1, path(p), p2, arg4));
+            if (p2)
+                unlock_user(p2, arg3, ret);
+            if (p)
+                unlock_user(p, arg2, 0);
+        }
+        break;
+#endif
+#ifdef TARGET_NR_uselib
     case TARGET_NR_uselib:
         goto unimplemented;
+#endif
+#ifdef TARGET_NR_swapon
     case TARGET_NR_swapon:
         p = lock_user_string(arg1);
         ret = get_errno(swapon(p, arg2));
         unlock_user(p, arg1, 0);
         break;
+#endif
     case TARGET_NR_reboot:
         goto unimplemented;
+#ifdef TARGET_NR_readdir
     case TARGET_NR_readdir:
         goto unimplemented;
+#endif
+#ifdef TARGET_NR_mmap
     case TARGET_NR_mmap:
 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K)
         {
@@ -2732,17 +3514,18 @@
             v5 = tswapl(v[4]);
             v6 = tswapl(v[5]);
             unlock_user(v, arg1, 0);
-            ret = get_errno(target_mmap(v1, v2, v3, 
+            ret = get_errno(target_mmap(v1, v2, v3,
                                         target_to_host_bitmask(v4, mmap_flags_tbl),
                                         v5, v6));
         }
 #else
-        ret = get_errno(target_mmap(arg1, arg2, arg3, 
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl), 
+        ret = get_errno(target_mmap(arg1, arg2, arg3,
+                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
                                     arg5,
                                     arg6));
 #endif
         break;
+#endif
 #ifdef TARGET_NR_mmap2
     case TARGET_NR_mmap2:
 #if defined(TARGET_SPARC) || defined(TARGET_MIPS)
@@ -2750,8 +3533,8 @@
 #else
 #define MMAP_SHIFT TARGET_PAGE_BITS
 #endif
-        ret = get_errno(target_mmap(arg1, arg2, arg3, 
-                                    target_to_host_bitmask(arg4, mmap_flags_tbl), 
+        ret = get_errno(target_mmap(arg1, arg2, arg3,
+                                    target_to_host_bitmask(arg4, mmap_flags_tbl),
                                     arg5,
                                     arg6 << MMAP_SHIFT));
         break;
@@ -2762,25 +3545,37 @@
     case TARGET_NR_mprotect:
         ret = get_errno(target_mprotect(arg1, arg2, arg3));
         break;
+#ifdef TARGET_NR_mremap
     case TARGET_NR_mremap:
         ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
         break;
+#endif
         /* ??? msync/mlock/munlock are broken for softmmu.  */
+#ifdef TARGET_NR_msync
     case TARGET_NR_msync:
         ret = get_errno(msync(g2h(arg1), arg2, arg3));
         break;
+#endif
+#ifdef TARGET_NR_mlock
     case TARGET_NR_mlock:
         ret = get_errno(mlock(g2h(arg1), arg2));
         break;
+#endif
+#ifdef TARGET_NR_munlock
     case TARGET_NR_munlock:
         ret = get_errno(munlock(g2h(arg1), arg2));
         break;
+#endif
+#ifdef TARGET_NR_mlockall
     case TARGET_NR_mlockall:
         ret = get_errno(mlockall(arg1));
         break;
+#endif
+#ifdef TARGET_NR_munlockall
     case TARGET_NR_munlockall:
         ret = get_errno(munlockall());
         break;
+#endif
     case TARGET_NR_truncate:
         p = lock_user_string(arg1);
         ret = get_errno(truncate(p, arg2));
@@ -2792,6 +3587,21 @@
     case TARGET_NR_fchmod:
         ret = get_errno(fchmod(arg1, arg2));
         break;
+#if defined(TARGET_NR_fchmodat) && defined(__NR_fchmodat)
+    case TARGET_NR_fchmodat:
+        if (!arg2) {
+            ret = -EFAULT;
+            goto fail;
+        }
+        p = lock_user_string(arg2);
+        if (!access_ok(VERIFY_READ, p, 1))
+            ret = -EFAULT;
+        else
+            ret = get_errno(sys_fchmodat(arg1, p, arg3, arg4));
+        if (p)
+            unlock_user(p, arg2, 0);
+        break;
+#endif
     case TARGET_NR_getpriority:
         ret = get_errno(getpriority(arg1, arg2));
         break;
@@ -2809,7 +3619,7 @@
     convert_statfs:
         if (!is_error(ret)) {
             struct target_statfs *target_stfs;
-            
+
             lock_user_struct(target_stfs, arg2, 0);
             /* ??? put_user is probably wrong.  */
             put_user(stfs.f_type, &target_stfs->f_type);
@@ -2819,7 +3629,8 @@
             put_user(stfs.f_bavail, &target_stfs->f_bavail);
             put_user(stfs.f_files, &target_stfs->f_files);
             put_user(stfs.f_ffree, &target_stfs->f_ffree);
-            put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid);
+            put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
+            put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
             put_user(stfs.f_namelen, &target_stfs->f_namelen);
             unlock_user_struct(target_stfs, arg2, 1);
         }
@@ -2835,7 +3646,7 @@
     convert_statfs64:
         if (!is_error(ret)) {
             struct target_statfs64 *target_stfs;
-            
+
             lock_user_struct(target_stfs, arg3, 0);
             /* ??? put_user is probably wrong.  */
             put_user(stfs.f_type, &target_stfs->f_type);
@@ -2845,7 +3656,8 @@
             put_user(stfs.f_bavail, &target_stfs->f_bavail);
             put_user(stfs.f_files, &target_stfs->f_files);
             put_user(stfs.f_ffree, &target_stfs->f_ffree);
-            put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid);
+            put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid.val[0]);
+            put_user(stfs.f_fsid.__val[1], &target_stfs->f_fsid.val[1]);
             put_user(stfs.f_namelen, &target_stfs->f_namelen);
             unlock_user_struct(target_stfs, arg3, 0);
         }
@@ -2858,10 +3670,11 @@
     case TARGET_NR_ioperm:
         goto unimplemented;
 #endif
+#ifdef TARGET_NR_socketcall
     case TARGET_NR_socketcall:
         ret = do_socketcall(arg1, arg2);
         break;
-
+#endif
 #ifdef TARGET_NR_accept
     case TARGET_NR_accept:
         ret = do_accept(arg1, arg2, arg3);
@@ -2899,12 +3712,12 @@
 #endif
 #ifdef TARGET_NR_recv
     case TARGET_NR_recv:
-        ret = do_recvfrom(arg1, arg1, arg3, arg4, 0, 0);
+        ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
         break;
 #endif
 #ifdef TARGET_NR_recvfrom
     case TARGET_NR_recvfrom:
-        ret = do_recvfrom(arg1, arg1, arg3, arg4, arg5, arg6);
+        ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
         break;
 #endif
 #ifdef TARGET_NR_recvmsg
@@ -2947,18 +3760,22 @@
         ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
         break;
 #endif
-        
+
     case TARGET_NR_syslog:
-        goto unimplemented;
+        p = lock_user_string(arg2);
+        ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
+        unlock_user(p, arg2, 0);
+        break;
+
     case TARGET_NR_setitimer:
         {
             struct itimerval value, ovalue, *pvalue;
 
             if (arg2) {
                 pvalue = &value;
-                target_to_host_timeval(&pvalue->it_interval, 
+                target_to_host_timeval(&pvalue->it_interval,
                                        arg2);
-                target_to_host_timeval(&pvalue->it_value, 
+                target_to_host_timeval(&pvalue->it_value,
                                        arg2 + sizeof(struct target_timeval));
             } else {
                 pvalue = NULL;
@@ -2975,7 +3792,7 @@
     case TARGET_NR_getitimer:
         {
             struct itimerval value;
-            
+
             ret = get_errno(getitimer(arg1, &value));
             if (!is_error(ret) && arg2) {
                 host_to_target_timeval(arg2,
@@ -3001,21 +3818,38 @@
         do_stat:
             if (!is_error(ret)) {
                 struct target_stat *target_st;
-                
+
                 lock_user_struct(target_st, arg2, 0);
+#if defined(TARGET_MIPS) || defined(TARGET_SPARC64)
+                target_st->st_dev = tswap32(st.st_dev);
+#else
                 target_st->st_dev = tswap16(st.st_dev);
+#endif
                 target_st->st_ino = tswapl(st.st_ino);
 #if defined(TARGET_PPC) || defined(TARGET_MIPS)
                 target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
                 target_st->st_uid = tswap32(st.st_uid);
                 target_st->st_gid = tswap32(st.st_gid);
+#elif defined(TARGET_SPARC64)
+                target_st->st_mode = tswap32(st.st_mode);
+                target_st->st_uid = tswap32(st.st_uid);
+                target_st->st_gid = tswap32(st.st_gid);
 #else
                 target_st->st_mode = tswap16(st.st_mode);
                 target_st->st_uid = tswap16(st.st_uid);
                 target_st->st_gid = tswap16(st.st_gid);
 #endif
+#if defined(TARGET_MIPS)
+		/* If this is the same on PPC, then just merge w/ the above ifdef */
+                target_st->st_nlink = tswapl(st.st_nlink);
+                target_st->st_rdev = tswapl(st.st_rdev);
+#elif defined(TARGET_SPARC64)
+                target_st->st_nlink = tswap32(st.st_nlink);
+                target_st->st_rdev = tswap32(st.st_rdev);
+#else
                 target_st->st_nlink = tswap16(st.st_nlink);
                 target_st->st_rdev = tswap16(st.st_rdev);
+#endif
                 target_st->st_size = tswapl(st.st_size);
                 target_st->st_blksize = tswapl(st.st_blksize);
                 target_st->st_blocks = tswapl(st.st_blocks);
@@ -3066,11 +3900,13 @@
             }
         }
         break;
+#ifdef TARGET_NR_swapoff
     case TARGET_NR_swapoff:
         p = lock_user_string(arg1);
         ret = get_errno(swapoff(p));
         unlock_user(p, arg1, 0);
         break;
+#endif
     case TARGET_NR_sysinfo:
         {
             struct target_sysinfo *target_value;
@@ -3098,9 +3934,11 @@
             }
         }
         break;
+#ifdef TARGET_NR_ipc
     case TARGET_NR_ipc:
 	ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
 	break;
+#endif
     case TARGET_NR_fsync:
         ret = get_errno(fsync(arg1));
         break;
@@ -3123,7 +3961,7 @@
         /* no need to transcode because we use the linux syscall */
         {
             struct new_utsname * buf;
-    
+
             lock_user_struct(buf, arg1, 0);
             ret = get_errno(sys_uname(buf));
             if (!is_error(ret)) {
@@ -3141,18 +3979,24 @@
     case TARGET_NR_modify_ldt:
         ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3));
         break;
+#if !defined(TARGET_X86_64)
     case TARGET_NR_vm86old:
         goto unimplemented;
     case TARGET_NR_vm86:
         ret = do_vm86(cpu_env, arg1, arg2);
         break;
 #endif
+#endif
     case TARGET_NR_adjtimex:
         goto unimplemented;
+#ifdef TARGET_NR_create_module
     case TARGET_NR_create_module:
+#endif
     case TARGET_NR_init_module:
     case TARGET_NR_delete_module:
+#ifdef TARGET_NR_get_kernel_syms
     case TARGET_NR_get_kernel_syms:
+#endif
         goto unimplemented;
     case TARGET_NR_quotactl:
         goto unimplemented;
@@ -3162,15 +4006,22 @@
     case TARGET_NR_fchdir:
         ret = get_errno(fchdir(arg1));
         break;
+#ifdef TARGET_NR_bdflush /* not on x86_64 */
     case TARGET_NR_bdflush:
         goto unimplemented;
+#endif
+#ifdef TARGET_NR_sysfs
     case TARGET_NR_sysfs:
         goto unimplemented;
+#endif
     case TARGET_NR_personality:
         ret = get_errno(personality(arg1));
         break;
+#ifdef TARGET_NR_afs_syscall
     case TARGET_NR_afs_syscall:
         goto unimplemented;
+#endif
+#ifdef TARGET_NR__llseek /* Not on alpha */
     case TARGET_NR__llseek:
         {
 #if defined (__x86_64__)
@@ -3183,6 +4034,7 @@
 #endif
         }
         break;
+#endif
     case TARGET_NR_getdents:
 #if TARGET_LONG_SIZE != 4
         goto unimplemented;
@@ -3191,12 +4043,12 @@
         {
             struct target_dirent *target_dirp;
             struct dirent *dirp;
-            long count = arg3;
+            target_long count = arg3;
 
 	    dirp = malloc(count);
 	    if (!dirp)
                 return -ENOMEM;
-            
+
             ret = get_errno(sys_getdents(arg1, dirp, count));
             if (!is_error(ret)) {
                 struct dirent *de;
@@ -3222,7 +4074,7 @@
 		    strncpy(tde->d_name, de->d_name, tnamelen);
                     de = (struct dirent *)((char *)de + reclen);
                     len -= reclen;
-                    tde = (struct dirent *)((char *)tde + treclen);
+                    tde = (struct target_dirent *)((char *)tde + treclen);
 		    count1 += treclen;
                 }
 		ret = count1;
@@ -3233,7 +4085,7 @@
 #else
         {
             struct dirent *dirp;
-            long count = arg3;
+            target_long count = arg3;
 
             dirp = lock_user(arg2, count, 0);
             ret = get_errno(sys_getdents(arg1, dirp, count));
@@ -3257,11 +4109,11 @@
         }
 #endif
         break;
-#ifdef TARGET_NR_getdents64
+#if defined(TARGET_NR_getdents64) && defined(__NR_getdents64)
     case TARGET_NR_getdents64:
         {
             struct dirent64 *dirp;
-            long count = arg3;
+            target_long count = arg3;
             dirp = lock_user(arg2, count, 0);
             ret = get_errno(sys_getdents64(arg1, dirp, count));
             if (!is_error(ret)) {
@@ -3284,9 +4136,12 @@
         }
         break;
 #endif /* TARGET_NR_getdents64 */
+#ifdef TARGET_NR__newselect
     case TARGET_NR__newselect:
         ret = do_select(arg1, arg2, arg3, arg4, arg5);
         break;
+#endif
+#ifdef TARGET_NR_poll
     case TARGET_NR_poll:
         {
             struct target_pollfd *target_pfd;
@@ -3312,6 +4167,7 @@
             unlock_user(target_pfd, arg1, ret);
         }
         break;
+#endif
     case TARGET_NR_flock:
         /* NOTE: the flock constant seems to be the same for every
            Linux platform */
@@ -3342,9 +4198,11 @@
     case TARGET_NR_getsid:
         ret = get_errno(getsid(arg1));
         break;
+#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
     case TARGET_NR_fdatasync:
         ret = get_errno(fdatasync(arg1));
         break;
+#endif
     case TARGET_NR__sysctl:
         /* We don't implement this, but ENODIR is always a safe
            return value. */
@@ -3413,12 +4271,30 @@
             }
         }
         break;
+#ifdef TARGET_NR_query_module
     case TARGET_NR_query_module:
         goto unimplemented;
+#endif
+#ifdef TARGET_NR_nfsservctl
     case TARGET_NR_nfsservctl:
         goto unimplemented;
+#endif
     case TARGET_NR_prctl:
-        goto unimplemented;
+        switch (arg1)
+            {
+            case PR_GET_PDEATHSIG:
+                {
+                    int deathsig;
+                    ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
+                    if (!is_error(ret) && arg2)
+                        tput32(arg2, deathsig);
+                }
+                break;
+            default:
+                ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
+                break;
+            }
+        break;
 #ifdef TARGET_NR_pread
     case TARGET_NR_pread:
         page_unprotect_range(arg2, arg3);
@@ -3442,7 +4318,15 @@
     case TARGET_NR_capset:
         goto unimplemented;
     case TARGET_NR_sigaltstack:
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_MIPS) || \
+    defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_ALPHA)
+        ret = do_sigaltstack((struct target_sigaltstack *)arg1,
+                             (struct target_sigaltstack *)arg2,
+                             get_sp_from_cpustate((CPUState *)cpu_env));
+        break;
+#else
         goto unimplemented;
+#endif
     case TARGET_NR_sendfile:
         goto unimplemented;
 #ifdef TARGET_NR_getpmsg
@@ -3618,10 +4502,25 @@
     case TARGET_NR_fchown:
         ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
         break;
+#if defined(TARGET_NR_fchownat) && defined(__NR_fchownat)
+    case TARGET_NR_fchownat:
+        if (!arg2) {
+            ret = -EFAULT;
+            goto fail;
+        }
+        p = lock_user_string(arg2);
+        if (!access_ok(VERIFY_READ, p, 1))
+            ret = -EFAULT;
+	else
+            ret = get_errno(sys_fchownat(arg1, p, low2highuid(arg3), low2highgid(arg4), arg5));
+        if (p)
+            unlock_user(p, arg2, 0);
+        break;
+#endif
 #ifdef TARGET_NR_setresuid
     case TARGET_NR_setresuid:
-        ret = get_errno(setresuid(low2highuid(arg1), 
-                                  low2highuid(arg2), 
+        ret = get_errno(setresuid(low2highuid(arg1),
+                                  low2highuid(arg2),
                                   low2highuid(arg3)));
         break;
 #endif
@@ -3640,8 +4539,8 @@
 #endif
 #ifdef TARGET_NR_getresgid
     case TARGET_NR_setresgid:
-        ret = get_errno(setresgid(low2highgid(arg1), 
-                                  low2highgid(arg2), 
+        ret = get_errno(setresgid(low2highgid(arg1),
+                                  low2highgid(arg2),
                                   low2highgid(arg3)));
         break;
 #endif
@@ -3740,7 +4639,7 @@
             uint32_t *target_grouplist;
             gid_t *grouplist;
             int i;
-            
+
             grouplist = alloca(gidsetsize * sizeof(gid_t));
             target_grouplist = lock_user(arg2, gidsetsize * 4, 1);
             for(i = 0;i < gidsetsize; i++)
@@ -3837,15 +4736,51 @@
 #if TARGET_LONG_BITS == 32
     case TARGET_NR_fcntl64:
     {
+	int cmd;
 	struct flock64 fl;
 	struct target_flock64 *target_fl;
 #ifdef TARGET_ARM
 	struct target_eabi_flock64 *target_efl;
 #endif
 
+        switch(arg2){
+        case TARGET_F_GETLK64:
+            cmd = F_GETLK64;
+            break;
+        case TARGET_F_SETLK64:
+            cmd = F_SETLK64;
+            break;
+        case TARGET_F_SETLKW64:
+            cmd = F_SETLK64;
+            break;
+        default:
+            cmd = arg2;
+            break;
+        }
+
         switch(arg2) {
-        case F_GETLK64:
-            ret = get_errno(fcntl(arg1, arg2, &fl));
+        case TARGET_F_GETLK64:
+#ifdef TARGET_ARM
+            if (((CPUARMState *)cpu_env)->eabi) {
+                lock_user_struct(target_efl, arg3, 1);
+                fl.l_type = tswap16(target_efl->l_type);
+                fl.l_whence = tswap16(target_efl->l_whence);
+                fl.l_start = tswap64(target_efl->l_start);
+                fl.l_len = tswap64(target_efl->l_len);
+                fl.l_pid = tswapl(target_efl->l_pid);
+                unlock_user_struct(target_efl, arg3, 0);
+            } else
+#endif
+            {
+                lock_user_struct(target_fl, arg3, 1);
+                fl.l_type = tswap16(target_fl->l_type);
+                fl.l_whence = tswap16(target_fl->l_whence);
+                fl.l_start = tswap64(target_fl->l_start);
+                fl.l_len = tswap64(target_fl->l_len);
+                fl.l_pid = tswapl(target_fl->l_pid);
+                unlock_user_struct(target_fl, arg3, 0);
+            }
+            ret = get_errno(fcntl(arg1, cmd, &fl));
 	    if (ret == 0) {
 #ifdef TARGET_ARM
                 if (((CPUARMState *)cpu_env)->eabi) {
@@ -3870,8 +4805,8 @@
 	    }
 	    break;
 
-        case F_SETLK64:
-        case F_SETLKW64:
+        case TARGET_F_SETLK64:
+        case TARGET_F_SETLKW64:
 #ifdef TARGET_ARM
             if (((CPUARMState *)cpu_env)->eabi) {
                 lock_user_struct(target_efl, arg3, 1);
@@ -3892,10 +4827,10 @@
                 fl.l_pid = tswapl(target_fl->l_pid);
                 unlock_user_struct(target_fl, arg3, 0);
             }
-            ret = get_errno(fcntl(arg1, arg2, &fl));
+            ret = get_errno(fcntl(arg1, cmd, &fl));
 	    break;
         default:
-            ret = get_errno(do_fcntl(arg1, arg2, arg3));
+            ret = get_errno(do_fcntl(arg1, cmd, arg3));
             break;
         }
 	break;
@@ -3919,8 +4854,10 @@
     case TARGET_NR_gettid:
         ret = get_errno(gettid());
         break;
+#ifdef TARGET_NR_readahead
     case TARGET_NR_readahead:
         goto unimplemented;
+#endif
 #ifdef TARGET_NR_setxattr
     case TARGET_NR_setxattr:
     case TARGET_NR_lsetxattr:
@@ -3938,6 +4875,15 @@
 #endif
 #ifdef TARGET_NR_set_thread_area
     case TARGET_NR_set_thread_area:
+#ifdef TARGET_MIPS
+      ((CPUMIPSState *) cpu_env)->tls_value = arg1;
+      ret = 0;
+      break;
+#else
+      goto unimplemented_nowarn;
+#endif
+#endif
+#ifdef TARGET_NR_get_thread_area
     case TARGET_NR_get_thread_area:
         goto unimplemented_nowarn;
 #endif
@@ -3945,10 +4891,78 @@
     case TARGET_NR_getdomainname:
         goto unimplemented_nowarn;
 #endif
+
+#ifdef TARGET_NR_clock_gettime
+    case TARGET_NR_clock_gettime:
+    {
+        struct timespec ts;
+        ret = get_errno(clock_gettime(arg1, &ts));
+        if (!is_error(ret)) {
+            host_to_target_timespec(arg2, &ts);
+        }
+        break;
+    }
+#endif
+#ifdef TARGET_NR_clock_getres
+    case TARGET_NR_clock_getres:
+    {
+        struct timespec ts;
+        ret = get_errno(clock_getres(arg1, &ts));
+        if (!is_error(ret)) {
+            host_to_target_timespec(arg2, &ts);
+        }
+        break;
+    }
+#endif
+
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+    case TARGET_NR_set_tid_address:
+      ret = get_errno(set_tid_address((int *) arg1));
+      break;
+#endif
+
+#if defined(TARGET_NR_tkill) && defined(__NR_tkill)
+    case TARGET_NR_tkill:
+        ret = get_errno(sys_tkill((int)arg1, (int)arg2));
+        break;
+#endif
+
+#if defined(TARGET_NR_tgkill) && defined(__NR_tgkill)
+    case TARGET_NR_tgkill:
+	ret = get_errno(sys_tgkill((int)arg1, (int)arg2, (int)arg3));
+	break;
+#endif
+
+#ifdef TARGET_NR_set_robust_list
+    case TARGET_NR_set_robust_list:
+	goto unimplemented_nowarn;
+#endif
+
+#if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
+    case TARGET_NR_utimensat:
+        {
+            struct timespec ts[2];
+            target_to_host_timespec(ts, arg3);
+            target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
+            if (!arg2)
+                ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4));
+            else {
+                p = lock_user_string(arg2);
+                if (!access_ok(VERIFY_READ, p, 1))
+                    ret = -EFAULT;
+                else
+                    ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4));
+                if (p)
+                    unlock_user(p, arg2, 0);
+            }
+        }
+	break;
+#endif
+
     default:
     unimplemented:
         gemu_log("qemu: Unsupported syscall: %d\n", num);
-#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) || defined(TARGET_NR_getdomainname)
+#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname) || defined(TARGET_NR_set_robust_list)
     unimplemented_nowarn:
 #endif
         ret = -ENOSYS;
@@ -3960,4 +4974,3 @@
 #endif
     return ret;
 }
-
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index e33c12b..90bea9b 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -49,7 +49,7 @@
 #define TARGET_IOC_TYPEBITS	8
 
 #if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \
-    || defined(TARGET_M68K)
+    || defined(TARGET_M68K) || defined(TARGET_ALPHA)
 
 #define TARGET_IOC_SIZEBITS	14
 #define TARGET_IOC_DIRBITS	2
@@ -176,19 +176,14 @@
 static __inline__ struct target_cmsghdr *
 __target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
 {
-  if (tswapl(__cmsg->cmsg_len) < sizeof (struct target_cmsghdr))
-    /* The kernel header does this so there may be a reason.  */
-    return 0;
+  struct target_cmsghdr *__ptr;
 
-  __cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg
-                               + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
-  if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) tswapl(__mhdr->msg_control)
-                                        + tswapl(__mhdr->msg_controllen))
-      || ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))
-          > ((unsigned char *) tswapl(__mhdr->msg_control) 
-             + tswapl(__mhdr->msg_controllen))))
+  __ptr = (struct target_cmsghdr *)((unsigned char *) __cmsg
+                                    + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
+  if ((unsigned long)((char *)(__ptr+1) - (char *)(size_t)tswapl(__mhdr->msg_control))
+      > tswapl(__mhdr->msg_controllen))
     /* No more entries.  */
-    return 0;
+    return (struct target_cmsghdr *)0;
   return __cmsg;
 }
 
@@ -286,15 +281,15 @@
 
 void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
 void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
-void host_to_target_old_sigset(target_ulong *old_sigset, 
+void host_to_target_old_sigset(target_ulong *old_sigset,
                                const sigset_t *sigset);
-void target_to_host_old_sigset(sigset_t *sigset, 
+void target_to_host_old_sigset(sigset_t *sigset,
                                const target_ulong *old_sigset);
 struct target_sigaction;
 int do_sigaction(int sig, const struct target_sigaction *act,
                  struct target_sigaction *oact);
 
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K)
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA)
 
 #if defined(TARGET_SPARC)
 #define TARGET_SA_NOCLDSTOP    8u
@@ -312,7 +307,9 @@
 #define TARGET_SA_NODEFER	0x40000000
 #define TARGET_SA_RESTART	0x10000000
 #define TARGET_SA_RESETHAND	0x80000000
+#if !defined(TARGET_MIPSN32) && !defined(TARGET_MIPS64)
 #define TARGET_SA_RESTORER	0x04000000	/* Only for o32 */
+#endif
 #else
 #define TARGET_SA_NOCLDSTOP	0x00000001
 #define TARGET_SA_NOCLDWAIT	0x00000002 /* not supported yet */
@@ -452,8 +449,12 @@
 #if defined(TARGET_MIPS)
 
 struct target_sigaction {
-	target_ulong	sa_flags;
+	uint32_t	sa_flags;
+#if defined(TARGET_MIPSN32)
+	uint32_t	_sa_handler;
+#else
 	target_ulong	_sa_handler;
+#endif
 	target_sigset_t	sa_mask;
 };
 
@@ -714,59 +715,59 @@
 #define TARGET_FIGETBSZ   TARGET_IO(0x00,2)  /* get the block size used for bmap */
 
 /* cdrom commands */
-#define TARGET_CDROMPAUSE		0x5301 /* Pause Audio Operation */ 
+#define TARGET_CDROMPAUSE		0x5301 /* Pause Audio Operation */
 #define TARGET_CDROMRESUME		0x5302 /* Resume paused Audio Operation */
 #define TARGET_CDROMPLAYMSF		0x5303 /* Play Audio MSF (struct cdrom_msf) */
-#define TARGET_CDROMPLAYTRKIND		0x5304 /* Play Audio Track/index 
+#define TARGET_CDROMPLAYTRKIND		0x5304 /* Play Audio Track/index
                                            (struct cdrom_ti) */
-#define TARGET_CDROMREADTOCHDR		0x5305 /* Read TOC header 
+#define TARGET_CDROMREADTOCHDR		0x5305 /* Read TOC header
                                            (struct cdrom_tochdr) */
-#define TARGET_CDROMREADTOCENTRY	0x5306 /* Read TOC entry 
+#define TARGET_CDROMREADTOCENTRY	0x5306 /* Read TOC entry
                                            (struct cdrom_tocentry) */
 #define TARGET_CDROMSTOP		0x5307 /* Stop the cdrom drive */
 #define TARGET_CDROMSTART		0x5308 /* Start the cdrom drive */
 #define TARGET_CDROMEJECT		0x5309 /* Ejects the cdrom media */
-#define TARGET_CDROMVOLCTRL		0x530a /* Control output volume 
+#define TARGET_CDROMVOLCTRL		0x530a /* Control output volume
                                            (struct cdrom_volctrl) */
-#define TARGET_CDROMSUBCHNL		0x530b /* Read subchannel data 
+#define TARGET_CDROMSUBCHNL		0x530b /* Read subchannel data
                                            (struct cdrom_subchnl) */
-#define TARGET_CDROMREADMODE2		0x530c /* Read TARGET_CDROM mode 2 data (2336 Bytes) 
+#define TARGET_CDROMREADMODE2		0x530c /* Read TARGET_CDROM mode 2 data (2336 Bytes)
                                            (struct cdrom_read) */
 #define TARGET_CDROMREADMODE1		0x530d /* Read TARGET_CDROM mode 1 data (2048 Bytes)
                                            (struct cdrom_read) */
 #define TARGET_CDROMREADAUDIO		0x530e /* (struct cdrom_read_audio) */
 #define TARGET_CDROMEJECT_SW		0x530f /* enable(1)/disable(0) auto-ejecting */
-#define TARGET_CDROMMULTISESSION	0x5310 /* Obtain the start-of-last-session 
-                                           address of multi session disks 
+#define TARGET_CDROMMULTISESSION	0x5310 /* Obtain the start-of-last-session
+                                           address of multi session disks
                                            (struct cdrom_multisession) */
-#define TARGET_CDROM_GET_MCN		0x5311 /* Obtain the "Universal Product Code" 
+#define TARGET_CDROM_GET_MCN		0x5311 /* Obtain the "Universal Product Code"
                                            if available (struct cdrom_mcn) */
-#define TARGET_CDROM_GET_UPC		TARGET_CDROM_GET_MCN  /* This one is depricated, 
+#define TARGET_CDROM_GET_UPC		TARGET_CDROM_GET_MCN  /* This one is depricated,
                                           but here anyway for compatability */
 #define TARGET_CDROMRESET		0x5312 /* hard-reset the drive */
-#define TARGET_CDROMVOLREAD		0x5313 /* Get the drive's volume setting 
+#define TARGET_CDROMVOLREAD		0x5313 /* Get the drive's volume setting
                                           (struct cdrom_volctrl) */
 #define TARGET_CDROMREADRAW		0x5314	/* read data in raw mode (2352 Bytes)
                                            (struct cdrom_read) */
-/* 
+/*
  * These ioctls are used only used in aztcd.c and optcd.c
  */
 #define TARGET_CDROMREADCOOKED		0x5315	/* read data in cooked mode */
 #define TARGET_CDROMSEEK		0x5316  /* seek msf address */
-  
+
 /*
- * This ioctl is only used by the scsi-cd driver.  
+ * This ioctl is only used by the scsi-cd driver.
    It is for playing audio in logical block addressing mode.
  */
 #define TARGET_CDROMPLAYBLK		0x5317	/* (struct cdrom_blk) */
 
-/* 
+/*
  * These ioctls are only used in optcd.c
  */
 #define TARGET_CDROMREADALL		0x5318	/* read all 2646 bytes */
 
-/* 
- * These ioctls are (now) only in ide-cd.c for controlling 
+/*
+ * These ioctls are (now) only in ide-cd.c for controlling
  * drive spindown time.  They should be implemented in the
  * Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10,
  * GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE...
@@ -775,7 +776,7 @@
 #define TARGET_CDROMGETSPINDOWN        0x531d
 #define TARGET_CDROMSETSPINDOWN        0x531e
 
-/* 
+/*
  * These ioctls are implemented through the uniform CD-ROM driver
  * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM
  * drivers are eventually ported to the uniform CD-ROM driver interface.
@@ -865,16 +866,25 @@
 #define TARGET_MAP_EXECUTABLE	0x4000		/* mark it as an executable */
 #define TARGET_MAP_LOCKED	0x8000		/* pages are locked */
 #define TARGET_MAP_NORESERVE	0x0400		/* don't check for reservations */
+#define TARGET_MAP_POPULATE	0x10000		/* populate (prefault) pagetables */
+#define TARGET_MAP_NONBLOCK	0x20000		/* do not block on IO */
 #else
 #define TARGET_MAP_ANONYMOUS	0x20		/* don't use a file */
 #define TARGET_MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define TARGET_MAP_DENYWRITE	0x0800		/* ETXTBSY */
 #define TARGET_MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+#if defined(TARGET_PPC)
+#define TARGET_MAP_LOCKED	0x0080		/* pages are locked */
+#define TARGET_MAP_NORESERVE	0x0040		/* don't check for reservations */
+#else
 #define TARGET_MAP_LOCKED	0x2000		/* pages are locked */
 #define TARGET_MAP_NORESERVE	0x4000		/* don't check for reservations */
 #endif
+#define TARGET_MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
+#define TARGET_MAP_NONBLOCK	0x10000		/* do not block on IO */
+#endif
 
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4)
+#if defined(TARGET_I386) || defined(TARGET_ARM)
 struct target_stat {
 	unsigned short st_dev;
 	unsigned short __pad1;
@@ -967,6 +977,57 @@
 } __attribute__ ((packed));
 #endif
 
+#elif defined(TARGET_SPARC64)
+struct target_stat {
+	unsigned int	st_dev;
+	target_ulong	st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+	unsigned int	st_rdev;
+	target_long	st_size;
+	target_long	target_st_atime;
+	target_long	target_st_mtime;
+	target_long	target_st_ctime;
+	target_long	st_blksize;
+	target_long	st_blocks;
+	target_ulong	__unused4[2];
+};
+
+struct target_stat64 {
+	unsigned char	__pad0[6];
+	unsigned short	st_dev;
+
+	uint64_t	st_ino;
+	uint64_t	st_nlink;
+
+	unsigned int	st_mode;
+
+	unsigned int	st_uid;
+	unsigned int	st_gid;
+
+	unsigned char	__pad2[6];
+	unsigned short	st_rdev;
+
+        int64_t		st_size;
+	int64_t		st_blksize;
+
+	unsigned char	__pad4[4];
+	unsigned int	st_blocks;
+
+	target_ulong	target_st_atime;
+	target_ulong	__unused1;
+
+	target_ulong	target_st_mtime;
+	target_ulong	__unused2;
+
+	target_ulong	target_st_ctime;
+	target_ulong	__unused3;
+
+	target_ulong	__unused4[3];
+};
+
 #elif defined(TARGET_SPARC)
 
 struct target_stat {
@@ -1133,6 +1194,116 @@
 	unsigned long long	st_ino;
 } __attribute__((packed));
 
+#elif defined(TARGET_MIPS64)
+
+/* The memory layout is the same as of struct stat64 of the 32-bit kernel.  */
+struct target_stat {
+	unsigned int		st_dev;
+	unsigned int		st_pad0[3]; /* Reserved for st_dev expansion */
+
+	target_ulong		st_ino;
+
+	unsigned int		st_mode;
+	unsigned int		st_nlink;
+
+	int			st_uid;
+	int			st_gid;
+
+	unsigned int		st_rdev;
+	unsigned int		st_pad1[3]; /* Reserved for st_rdev expansion */
+
+	target_ulong		st_size;
+
+	/*
+	 * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+	 * but we don't have it under Linux.
+	 */
+	unsigned int		target_st_atime;
+	unsigned int		target_st_atime_nsec;
+
+	unsigned int		target_st_mtime;
+	unsigned int		target_st_mtime_nsec;
+
+	unsigned int		target_st_ctime;
+	unsigned int		target_st_ctime_nsec;
+
+	unsigned int		st_blksize;
+	unsigned int		st_pad2;
+
+	target_ulong		st_blocks;
+};
+
+#elif defined(TARGET_MIPSN32)
+
+struct target_stat {
+	unsigned	st_dev;
+	int		st_pad1[3];		/* Reserved for network id */
+	unsigned int	st_ino;
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+	int		st_uid;
+	int		st_gid;
+	unsigned 	st_rdev;
+	unsigned int	st_pad2[2];
+	unsigned int	st_size;
+	unsigned int	st_pad3;
+	/*
+	 * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+	 * but we don't have it under Linux.
+	 */
+	unsigned int		target_st_atime;
+	unsigned int		target_st_atime_nsec;
+	unsigned int		target_st_mtime;
+	unsigned int		target_st_mtime_nsec;
+	unsigned int		target_st_ctime;
+	unsigned int		target_st_ctime_nsec;
+	unsigned int		st_blksize;
+	unsigned int		st_blocks;
+	unsigned int		st_pad4[14];
+};
+
+/*
+ * This matches struct stat64 in glibc2.1, hence the absolutely insane
+ * amounts of padding around dev_t's.  The memory layout is the same as of
+ * struct stat of the 64-bit kernel.
+ */
+
+struct target_stat64 {
+	unsigned int	st_dev;
+	unsigned int	st_pad0[3];	/* Reserved for st_dev expansion  */
+
+	target_ulong	st_ino;
+
+        unsigned int	st_mode;
+        unsigned int	st_nlink;
+
+	int		st_uid;
+	int		st_gid;
+
+	unsigned int	st_rdev;
+	unsigned int	st_pad1[3];	/* Reserved for st_rdev expansion  */
+
+	int		st_size;
+
+	/*
+	 * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
+	 * but we don't have it under Linux.
+	 */
+	int		target_st_atime;
+	unsigned int	target_st_atime_nsec;	/* Reserved for st_atime expansion  */
+
+	int		target_st_mtime;
+	unsigned int	target_st_mtime_nsec;	/* Reserved for st_mtime expansion  */
+
+	int		target_st_ctime;
+	unsigned int	target_st_ctime_nsec;	/* Reserved for st_ctime expansion  */
+
+	unsigned int	st_blksize;
+	unsigned int	st_pad2;
+
+	int		st_blocks;
+};
+
 #elif defined(TARGET_MIPS)
 
 struct target_stat {
@@ -1203,11 +1374,135 @@
 
 	int64_t  	st_blocks;
 };
+
+#elif defined(TARGET_ALPHA)
+
+struct target_stat {
+       unsigned int    st_dev;
+       unsigned int    st_ino;
+       unsigned int    st_mode;
+       unsigned int    st_nlink;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    st_rdev;
+       target_long     st_size;
+       target_ulong    target_st_atime;
+       target_ulong    target_st_mtime;
+       target_ulong    target_st_ctime;
+       unsigned int    st_blksize;
+       unsigned int    st_blocks;
+       unsigned int    st_flags;
+       unsigned int    st_gen;
+};
+
+struct target_stat64 {
+       target_ulong    st_dev;
+       target_ulong    st_ino;
+       target_ulong    st_rdev;
+       target_long     st_size;
+       target_ulong    st_blocks;
+
+       unsigned int    st_mode;
+       unsigned int    st_uid;
+       unsigned int    st_gid;
+       unsigned int    st_blksize;
+       unsigned int    st_nlink;
+       unsigned int    __pad0;
+
+       target_ulong    target_st_atime;
+       target_ulong    target_st_atime_nsec;
+       target_ulong    target_st_mtime;
+       target_ulong    target_st_mtime_nsec;
+       target_ulong    target_st_ctime;
+       target_ulong    target_st_ctime_nsec;
+       target_long     __unused[3];
+};
+
+#elif defined(TARGET_SH4)
+
+struct target_stat {
+	target_ulong  st_dev;
+	target_ulong  st_ino;
+	unsigned short st_mode;
+	unsigned short st_nlink;
+	unsigned short st_uid;
+	unsigned short st_gid;
+	target_ulong  st_rdev;
+	target_ulong  st_size;
+	target_ulong  st_blksize;
+	target_ulong  st_blocks;
+	target_ulong  target_st_atime;
+	target_ulong  target_st_atime_nsec;
+	target_ulong  target_st_mtime;
+	target_ulong  target_st_mtime_nsec;
+	target_ulong  target_st_ctime;
+	target_ulong  target_st_ctime_nsec;
+	target_ulong  __unused4;
+	target_ulong  __unused5;
+};
+
+/* This matches struct stat64 in glibc2.1, hence the absolutely
+ * insane amounts of padding around dev_t's.
+ */
+struct target_stat64 {
+	unsigned long long	st_dev;
+	unsigned char	__pad0[4];
+
+#define TARGET_STAT64_HAS_BROKEN_ST_INO	1
+	target_ulong	__st_ino;
+
+	unsigned int	st_mode;
+	unsigned int	st_nlink;
+
+	target_ulong	st_uid;
+	target_ulong	st_gid;
+
+	unsigned long long	st_rdev;
+	unsigned char	__pad3[4];
+
+	long long	st_size;
+	target_ulong	st_blksize;
+
+	unsigned long long	st_blocks;	/* Number 512-byte blocks allocated. */
+
+	target_ulong	target_st_atime;
+	target_ulong	target_st_atime_nsec;
+
+	target_ulong	target_st_mtime;
+	target_ulong	target_st_mtime_nsec;
+
+	target_ulong	target_st_ctime;
+	target_ulong	target_st_ctime_nsec;
+
+	unsigned long long	st_ino;
+};
+
 #else
 #error unsupported CPU
 #endif
 
+typedef struct {
+        int     val[2];
+} target_fsid_t;
+
 #ifdef TARGET_MIPS
+#ifdef TARGET_MIPSN32
+struct target_statfs {
+	int32_t			f_type;
+	int32_t			f_bsize;
+	int32_t			f_frsize;	/* Fragment size - unsupported */
+	int32_t			f_blocks;
+	int32_t			f_bfree;
+	int32_t			f_files;
+	int32_t			f_ffree;
+	int32_t			f_bavail;
+
+	/* Linux specials */
+	target_fsid_t		f_fsid;
+	int32_t			f_namelen;
+	int32_t			f_spare[6];
+};
+#else
 struct target_statfs {
 	target_long		f_type;
 	target_long		f_bsize;
@@ -1219,10 +1514,11 @@
 	target_long		f_bavail;
 
 	/* Linux specials */
-	int	f_fsid;
+	target_fsid_t		f_fsid;
 	target_long		f_namelen;
 	target_long		f_spare[6];
 };
+#endif
 
 struct target_statfs64 {
 	uint32_t	f_type;
@@ -1234,7 +1530,7 @@
 	uint64_t	f_files;
 	uint64_t	f_ffree;
 	uint64_t	f_bavail;
-	int f_fsid;
+	target_fsid_t	f_fsid;
 	uint32_t	f_namelen;
 	uint32_t	f_spare[6];
 };
@@ -1247,7 +1543,7 @@
 	uint32_t f_bavail;
 	uint32_t f_files;
 	uint32_t f_ffree;
-	int f_fsid;
+	target_fsid_t f_fsid;
 	uint32_t f_namelen;
 	uint32_t f_frsize;
 	uint32_t f_spare[5];
@@ -1261,7 +1557,7 @@
 	uint64_t f_bavail;
 	uint64_t f_files;
 	uint64_t f_ffree;
-	int f_fsid;
+	target_fsid_t f_fsid;
         uint32_t f_namelen;
 	uint32_t f_frsize;
 	uint32_t f_spare[5];
@@ -1577,3 +1873,5 @@
 };
 
 #include "socket.h"
+
+#include "errno_defs.h"
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
index 308da48..f73aabc 100644
--- a/linux-user/syscall_types.h
+++ b/linux-user/syscall_types.h
@@ -5,7 +5,7 @@
 
 STRUCT(serial_multiport_struct,
        TYPE_INT, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR,
-       TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, 
+       TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT,
        MK_ARRAY(TYPE_INT, 32))
 
 STRUCT(serial_icounter_struct,
@@ -15,12 +15,12 @@
        TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14))
 
 STRUCT(rtentry,
-       TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), 
-       TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID, 
+       TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr),
+       TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID,
        TYPE_ULONG, TYPE_ULONG, TYPE_SHORT)
 
 STRUCT(ifmap,
-       TYPE_ULONG, TYPE_ULONG, TYPE_SHORT, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, 
+       TYPE_ULONG, TYPE_ULONG, TYPE_SHORT, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR,
        /* Spare 3 bytes */
        TYPE_CHAR, TYPE_CHAR, TYPE_CHAR)
 
@@ -28,7 +28,7 @@
 
 STRUCT(sockaddr_ifreq,
        MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_sockaddr))
-     
+
 STRUCT(short_ifreq,
        MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_SHORT)
 
@@ -49,7 +49,7 @@
        TYPE_INT, TYPE_PTRVOID)
 
 STRUCT(arpreq,
-       MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr), 
+       MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr),
        MK_ARRAY(TYPE_CHAR, 16))
 
 STRUCT(arpreq_old,
diff --git a/linux-user/vm86.c b/linux-user/vm86.c
index b28eea6..9639114 100644
--- a/linux-user/vm86.c
+++ b/linux-user/vm86.c
@@ -1,6 +1,6 @@
 /*
  *  vm86 linux syscall support
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -85,7 +85,7 @@
     target_v86->regs.eflags = tswap32(env->eflags);
     unlock_user_struct(target_v86, ts->target_v86, 1);
 #ifdef DEBUG_VM86
-    fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n", 
+    fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
             env->eflags, env->segs[R_CS].selector, env->eip);
 #endif
 
@@ -123,7 +123,7 @@
 static inline int set_IF(CPUX86State *env)
 {
     TaskState *ts = env->opaque;
-    
+
     ts->v86flags |= VIF_MASK;
     if (ts->v86flags & VIP_MASK) {
         return_to_32bit(env, TARGET_VM86_STI);
@@ -202,7 +202,7 @@
         goto cannot_handle;
     if (is_revectored(intno, &ts->vm86plus.int_revectored))
         goto cannot_handle;
-    if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff, 
+    if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
                                        &ts->vm86plus.int21_revectored))
         goto cannot_handle;
     int_ptr = (uint32_t *)(intno << 2);
@@ -210,7 +210,7 @@
     if ((segoffs >> 16) == TARGET_BIOSSEG)
         goto cannot_handle;
 #if defined(DEBUG_VM86)
-    fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n", 
+    fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
             intno, segoffs >> 16, segoffs & 0xffff);
 #endif
     /* save old state */
@@ -264,7 +264,7 @@
     csp = (uint8_t *)(env->segs[R_CS].selector << 4);
     ip = env->eip & 0xffff;
     pc = csp + ip;
-    
+
     ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
     sp = env->regs[R_ESP] & 0xffff;
 
@@ -330,7 +330,7 @@
         ADD16(ip, 1);
         env->eip = ip;
         if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
-            if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >> 
+            if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
                   (intno &7)) & 1) {
                 return_to_32bit(env, TARGET_VM86_INTx + (intno << 8));
                 return;
@@ -362,12 +362,12 @@
                 return;
         }
         VM86_FAULT_RETURN;
-        
+
     case 0xfa: /* cli */
         env->eip = ip;
         clear_IF(env);
         VM86_FAULT_RETURN;
-        
+
     case 0xfb: /* sti */
         env->eip = ip;
         if (set_IF(env))
@@ -386,7 +386,7 @@
     TaskState *ts = env->opaque;
     struct target_vm86plus_struct * target_v86;
     int ret;
-    
+
     switch (subfunction) {
     case TARGET_VM86_REQUEST_IRQ:
     case TARGET_VM86_FREE_IRQ:
@@ -427,7 +427,7 @@
     lock_user_struct(target_v86, vm86_addr, 1);
     /* build vm86 CPU state */
     ts->v86flags = tswap32(target_v86->regs.eflags);
-    env->eflags = (env->eflags & ~SAFE_MASK) | 
+    env->eflags = (env->eflags & ~SAFE_MASK) |
         (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
 
     ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
@@ -462,17 +462,17 @@
     cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
     ret = tswap32(target_v86->regs.eax); /* eax will be restored at
                                             the end of the syscall */
-    memcpy(&ts->vm86plus.int_revectored, 
+    memcpy(&ts->vm86plus.int_revectored,
            &target_v86->int_revectored, 32);
-    memcpy(&ts->vm86plus.int21_revectored, 
+    memcpy(&ts->vm86plus.int21_revectored,
            &target_v86->int21_revectored, 32);
     ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
-    memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab, 
+    memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
            target_v86->vm86plus.vm86dbg_intxxtab, 32);
     unlock_user_struct(target_v86, vm86_addr, 0);
-    
+
 #ifdef DEBUG_VM86
-    fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n", 
+    fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n",
             env->segs[R_CS].selector, env->eip);
 #endif
     /* now the virtual CPU is ready for vm86 execution ! */
diff --git a/linux-user/x86_64/syscall.h b/linux-user/x86_64/syscall.h
new file mode 100644
index 0000000..2f87dc9
--- /dev/null
+++ b/linux-user/x86_64/syscall.h
@@ -0,0 +1,92 @@
+#define __USER_CS	(0x33)
+#define __USER_DS	(0x2B)
+
+struct target_pt_regs {
+	target_ulong r15;
+	target_ulong r14;
+	target_ulong r13;
+	target_ulong r12;
+	target_ulong rbp;
+	target_ulong rbx;
+/* arguments: non interrupts/non tracing syscalls only save upto here*/
+ 	target_ulong r11;
+	target_ulong r10;
+	target_ulong r9;
+	target_ulong r8;
+	target_ulong rax;
+	target_ulong rcx;
+	target_ulong rdx;
+	target_ulong rsi;
+	target_ulong rdi;
+	target_ulong orig_rax;
+/* end of arguments */
+/* cpu exception frame or undefined */
+	target_ulong rip;
+	target_ulong cs;
+	target_ulong eflags;
+	target_ulong rsp;
+	target_ulong ss;
+/* top of stack page */
+};
+
+/* Maximum number of LDT entries supported. */
+#define TARGET_LDT_ENTRIES	8192
+/* The size of each LDT entry. */
+#define TARGET_LDT_ENTRY_SIZE	8
+
+#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
+#define TARGET_GDT_ENTRY_TLS_MIN 12
+#define TARGET_GDT_ENTRY_TLS_MAX 14
+
+#if 0 // Redefine this
+struct target_modify_ldt_ldt_s {
+	unsigned int  entry_number;
+	target_ulong  base_addr;
+	unsigned int  limit;
+	unsigned int  seg_32bit:1;
+	unsigned int  contents:2;
+	unsigned int  read_exec_only:1;
+	unsigned int  limit_in_pages:1;
+	unsigned int  seg_not_present:1;
+	unsigned int  useable:1;
+	unsigned int  lm:1;
+};
+#else
+struct target_modify_ldt_ldt_s {
+	unsigned int  entry_number;
+	target_ulong  base_addr;
+	unsigned int  limit;
+        unsigned int flags;
+};
+#endif
+
+struct target_ipc64_perm
+{
+	int		key;
+	uint32_t	uid;
+	uint32_t	gid;
+	uint32_t	cuid;
+	uint32_t	cgid;
+	unsigned short		mode;
+	unsigned short		__pad1;
+	unsigned short		seq;
+	unsigned short		__pad2;
+	target_ulong		__unused1;
+	target_ulong		__unused2;
+};
+
+struct target_msqid64_ds {
+	struct target_ipc64_perm msg_perm;
+	unsigned int msg_stime;	/* last msgsnd time */
+	unsigned int msg_rtime;	/* last msgrcv time */
+	unsigned int msg_ctime;	/* last change time */
+	target_ulong  msg_cbytes;	/* current number of bytes on queue */
+	target_ulong  msg_qnum;	/* number of messages in queue */
+	target_ulong  msg_qbytes;	/* max number of bytes on queue */
+	unsigned int msg_lspid;	/* pid of last msgsnd */
+	unsigned int msg_lrpid;	/* last receive pid */
+	target_ulong  __unused4;
+	target_ulong  __unused5;
+};
+
+#define UNAME_MACHINE "x86_64"
diff --git a/linux-user/x86_64/syscall_nr.h b/linux-user/x86_64/syscall_nr.h
new file mode 100644
index 0000000..e6a4c27
--- /dev/null
+++ b/linux-user/x86_64/syscall_nr.h
@@ -0,0 +1,286 @@
+#define TARGET_NR_read                                0
+#define TARGET_NR_write                               1
+#define TARGET_NR_open                                2
+#define TARGET_NR_close                               3
+#define TARGET_NR_stat                                4
+#define TARGET_NR_fstat                               5
+#define TARGET_NR_lstat                               6
+#define TARGET_NR_poll                                7
+#define TARGET_NR_lseek                               8
+#define TARGET_NR_mmap                                9
+#define TARGET_NR_mprotect                           10
+#define TARGET_NR_munmap                             11
+#define TARGET_NR_brk                                12
+#define TARGET_NR_rt_sigaction                       13
+#define TARGET_NR_rt_sigprocmask                     14
+#define TARGET_NR_rt_sigreturn                       15
+#define TARGET_NR_ioctl                              16
+#define TARGET_NR_pread64                            17
+#define TARGET_NR_pwrite64                           18
+#define TARGET_NR_readv                              19
+#define TARGET_NR_writev                             20
+#define TARGET_NR_access                             21
+#define TARGET_NR_pipe                               22
+#define TARGET_NR_select                             23
+#define TARGET_NR_sched_yield                        24
+#define TARGET_NR_mremap                             25
+#define TARGET_NR_msync                              26
+#define TARGET_NR_mincore                            27
+#define TARGET_NR_madvise                            28
+#define TARGET_NR_shmget                             29
+#define TARGET_NR_shmat                              30
+#define TARGET_NR_shmctl                             31
+#define TARGET_NR_dup                                32
+#define TARGET_NR_dup2                               33
+#define TARGET_NR_pause                              34
+#define TARGET_NR_nanosleep                          35
+#define TARGET_NR_getitimer                          36
+#define TARGET_NR_alarm                              37
+#define TARGET_NR_setitimer                          38
+#define TARGET_NR_getpid                             39
+#define TARGET_NR_sendfile                           40
+#define TARGET_NR_socket                             41
+#define TARGET_NR_connect                            42
+#define TARGET_NR_accept                             43
+#define TARGET_NR_sendto                             44
+#define TARGET_NR_recvfrom                           45
+#define TARGET_NR_sendmsg                            46
+#define TARGET_NR_recvmsg                            47
+#define TARGET_NR_shutdown                           48
+#define TARGET_NR_bind                               49
+#define TARGET_NR_listen                             50
+#define TARGET_NR_getsockname                        51
+#define TARGET_NR_getpeername                        52
+#define TARGET_NR_socketpair                         53
+#define TARGET_NR_setsockopt                         54
+#define TARGET_NR_getsockopt                         55
+#define TARGET_NR_clone                              56
+#define TARGET_NR_fork                               57
+#define TARGET_NR_vfork                              58
+#define TARGET_NR_execve                             59
+#define TARGET_NR_exit                               60
+#define TARGET_NR_wait4                              61
+#define TARGET_NR_kill                               62
+#define TARGET_NR_uname                              63
+#define TARGET_NR_semget                             64
+#define TARGET_NR_semop                              65
+#define TARGET_NR_semctl                             66
+#define TARGET_NR_shmdt                              67
+#define TARGET_NR_msgget                             68
+#define TARGET_NR_msgsnd                             69
+#define TARGET_NR_msgrcv                             70
+#define TARGET_NR_msgctl                             71
+#define TARGET_NR_fcntl                              72
+#define TARGET_NR_flock                              73
+#define TARGET_NR_fsync                              74
+#define TARGET_NR_fdatasync                          75
+#define TARGET_NR_truncate                           76
+#define TARGET_NR_ftruncate                          77
+#define TARGET_NR_getdents                           78
+#define TARGET_NR_getcwd                             79
+#define TARGET_NR_chdir                              80
+#define TARGET_NR_fchdir                             81
+#define TARGET_NR_rename                             82
+#define TARGET_NR_mkdir                              83
+#define TARGET_NR_rmdir                              84
+#define TARGET_NR_creat                              85
+#define TARGET_NR_link                               86
+#define TARGET_NR_unlink                             87
+#define TARGET_NR_symlink                            88
+#define TARGET_NR_readlink                           89
+#define TARGET_NR_chmod                              90
+#define TARGET_NR_fchmod                             91
+#define TARGET_NR_chown                              92
+#define TARGET_NR_fchown                             93
+#define TARGET_NR_lchown                             94
+#define TARGET_NR_umask                              95
+#define TARGET_NR_gettimeofday                       96
+#define TARGET_NR_getrlimit                          97
+#define TARGET_NR_getrusage                          98
+#define TARGET_NR_sysinfo                            99
+#define TARGET_NR_times                             100
+#define TARGET_NR_ptrace                            101
+#define TARGET_NR_getuid                            102
+#define TARGET_NR_syslog                            103
+#define TARGET_NR_getgid                            104
+#define TARGET_NR_setuid                            105
+#define TARGET_NR_setgid                            106
+#define TARGET_NR_geteuid                           107
+#define TARGET_NR_getegid                           108
+#define TARGET_NR_setpgid                           109
+#define TARGET_NR_getppid                           110
+#define TARGET_NR_getpgrp                           111
+#define TARGET_NR_setsid                            112
+#define TARGET_NR_setreuid                          113
+#define TARGET_NR_setregid                          114
+#define TARGET_NR_getgroups                         115
+#define TARGET_NR_setgroups                         116
+#define TARGET_NR_setresuid                         117
+#define TARGET_NR_getresuid                         118
+#define TARGET_NR_setresgid                         119
+#define TARGET_NR_getresgid                         120
+#define TARGET_NR_getpgid                           121
+#define TARGET_NR_setfsuid                          122
+#define TARGET_NR_setfsgid                          123
+#define TARGET_NR_getsid                            124
+#define TARGET_NR_capget                            125
+#define TARGET_NR_capset                            126
+#define TARGET_NR_rt_sigpending                     127
+#define TARGET_NR_rt_sigtimedwait                   128
+#define TARGET_NR_rt_sigqueueinfo                   129
+#define TARGET_NR_rt_sigsuspend                     130
+#define TARGET_NR_sigaltstack                       131
+#define TARGET_NR_utime                             132
+#define TARGET_NR_mknod                             133
+#define TARGET_NR_uselib                            134
+#define TARGET_NR_personality                       135
+#define TARGET_NR_ustat                             136
+#define TARGET_NR_statfs                            137
+#define TARGET_NR_fstatfs                           138
+#define TARGET_NR_sysfs                             139
+#define TARGET_NR_getpriority                       140
+#define TARGET_NR_setpriority                       141
+#define TARGET_NR_sched_setparam                    142
+#define TARGET_NR_sched_getparam                    143
+#define TARGET_NR_sched_setscheduler                144
+#define TARGET_NR_sched_getscheduler                145
+#define TARGET_NR_sched_get_priority_max            146
+#define TARGET_NR_sched_get_priority_min            147
+#define TARGET_NR_sched_rr_get_interval             148
+#define TARGET_NR_mlock                             149
+#define TARGET_NR_munlock                           150
+#define TARGET_NR_mlockall                          151
+#define TARGET_NR_munlockall                        152
+#define TARGET_NR_vhangup                           153
+#define TARGET_NR_modify_ldt                        154
+#define TARGET_NR_pivot_root                        155
+#define TARGET_NR__sysctl                           156
+#define TARGET_NR_prctl                             157
+#define TARGET_NR_arch_prctl                        158
+#define TARGET_NR_adjtimex                          159
+#define TARGET_NR_setrlimit                         160
+#define TARGET_NR_chroot                            161
+#define TARGET_NR_sync                              162
+#define TARGET_NR_acct                              163
+#define TARGET_NR_settimeofday                      164
+#define TARGET_NR_mount                             165
+#define TARGET_NR_umount2                           166
+#define TARGET_NR_swapon                            167
+#define TARGET_NR_swapoff                           168
+#define TARGET_NR_reboot                            169
+#define TARGET_NR_sethostname                       170
+#define TARGET_NR_setdomainname                     171
+#define TARGET_NR_iopl                              172
+#define TARGET_NR_ioperm                            173
+#define TARGET_NR_create_module                     174
+#define TARGET_NR_init_module                       175
+#define TARGET_NR_delete_module                     176
+#define TARGET_NR_get_kernel_syms                   177
+#define TARGET_NR_query_module                      178
+#define TARGET_NR_quotactl                          179
+#define TARGET_NR_nfsservctl                        180
+#define TARGET_NR_getpmsg                           181	/* reserved for LiS/STREAMS */
+#define TARGET_NR_putpmsg                           182	/* reserved for LiS/STREAMS */
+#define TARGET_NR_afs_syscall                       183	/* reserved for AFS */
+#define TARGET_NR_tuxcall      		184 /* reserved for tux */
+#define TARGET_NR_security			185
+#define TARGET_NR_gettid		186
+#define TARGET_NR_readahead		187
+#define TARGET_NR_setxattr		188
+#define TARGET_NR_lsetxattr		189
+#define TARGET_NR_fsetxattr		190
+#define TARGET_NR_getxattr		191
+#define TARGET_NR_lgetxattr		192
+#define TARGET_NR_fgetxattr		193
+#define TARGET_NR_listxattr		194
+#define TARGET_NR_llistxattr		195
+#define TARGET_NR_flistxattr		196
+#define TARGET_NR_removexattr	197
+#define TARGET_NR_lremovexattr	198
+#define TARGET_NR_fremovexattr	199
+#define TARGET_NR_tkill	200
+#define TARGET_NR_time      201
+#define TARGET_NR_futex     202
+#define TARGET_NR_sched_setaffinity    203
+#define TARGET_NR_sched_getaffinity     204
+#define TARGET_NR_set_thread_area	205
+#define TARGET_NR_io_setup	206
+#define TARGET_NR_io_destroy	207
+#define TARGET_NR_io_getevents	208
+#define TARGET_NR_io_submit	209
+#define TARGET_NR_io_cancel	210
+#define TARGET_NR_get_thread_area	211
+#define TARGET_NR_lookup_dcookie	212
+#define TARGET_NR_epoll_create	213
+#define TARGET_NR_epoll_ctl_old	214
+#define TARGET_NR_epoll_wait_old	215
+#define TARGET_NR_remap_file_pages	216
+#define TARGET_NR_getdents64	217
+#define TARGET_NR_set_tid_address	218
+#define TARGET_NR_restart_syscall	219
+#define TARGET_NR_semtimedop		220
+#define TARGET_NR_fadvise64		221
+#define TARGET_NR_timer_create		222
+#define TARGET_NR_timer_settime		223
+#define TARGET_NR_timer_gettime		224
+#define TARGET_NR_timer_getoverrun		225
+#define TARGET_NR_timer_delete	226
+#define TARGET_NR_clock_settime	227
+#define TARGET_NR_clock_gettime	228
+#define TARGET_NR_clock_getres	229
+#define TARGET_NR_clock_nanosleep	230
+#define TARGET_NR_exit_group		231
+#define TARGET_NR_epoll_wait		232
+#define TARGET_NR_epoll_ctl		233
+#define TARGET_NR_tgkill		234
+#define TARGET_NR_utimes		235
+#define TARGET_NR_vserver		236
+#define TARGET_NR_mbind 		237
+#define TARGET_NR_set_mempolicy 	238
+#define TARGET_NR_get_mempolicy 	239
+#define TARGET_NR_mq_open 		240
+#define TARGET_NR_mq_unlink 		241
+#define TARGET_NR_mq_timedsend 	242
+#define TARGET_NR_mq_timedreceive	243
+#define TARGET_NR_mq_notify 		244
+#define TARGET_NR_mq_getsetattr 	245
+#define TARGET_NR_kexec_load 	246
+#define TARGET_NR_waitid		247
+#define TARGET_NR_add_key		248
+#define TARGET_NR_request_key	249
+#define TARGET_NR_keyctl		250
+#define TARGET_NR_ioprio_set		251
+#define TARGET_NR_ioprio_get		252
+#define TARGET_NR_inotify_init	253
+#define TARGET_NR_inotify_add_watch	254
+#define TARGET_NR_inotify_rm_watch	255
+#define TARGET_NR_migrate_pages	256
+#define TARGET_NR_openat		257
+#define TARGET_NR_mkdirat		258
+#define TARGET_NR_mknodat		259
+#define TARGET_NR_fchownat		260
+#define TARGET_NR_futimesat		261
+#define TARGET_NR_newfstatat		262
+#define TARGET_NR_unlinkat		263
+#define TARGET_NR_renameat		264
+#define TARGET_NR_linkat		265
+#define TARGET_NR_symlinkat		266
+#define TARGET_NR_readlinkat		267
+#define TARGET_NR_fchmodat		268
+#define TARGET_NR_faccessat		269
+#define TARGET_NR_pselect6		270
+#define TARGET_NR_ppoll		271
+#define TARGET_NR_unshare		272
+#define TARGET_NR_set_robust_list	273
+#define TARGET_NR_get_robust_list	274
+#define TARGET_NR_splice		275
+#define TARGET_NR_tee		276
+#define TARGET_NR_sync_file_range	277
+#define TARGET_NR_vmsplice		278
+#define TARGET_NR_move_pages		279
+#define TARGET_NR_utimensat		280
+#define TARGET_NR_epoll_pwait	281
+#define TARGET_NR_signalfd		282
+#define TARGET_NR_timerfd		283
+#define TARGET_NR_eventfd		284
+#define TARGET_NR_fallocate		285
diff --git a/linux-user/x86_64/target_signal.h b/linux-user/x86_64/target_signal.h
new file mode 100644
index 0000000..f93a8d6
--- /dev/null
+++ b/linux-user/x86_64/target_signal.h
@@ -0,0 +1,29 @@
+#ifndef TARGET_SIGNAL_H
+#define TARGET_SIGNAL_H
+
+#include "cpu.h"
+
+/* this struct defines a stack used during syscall handling */
+
+typedef struct target_sigaltstack {
+	target_ulong ss_sp;
+	target_long ss_flags;
+	target_ulong ss_size;
+} target_stack_t;
+
+
+/*
+ * sigaltstack controls
+ */
+#define TARGET_SS_ONSTACK	1
+#define TARGET_SS_DISABLE	2
+
+#define TARGET_MINSIGSTKSZ	2048
+#define TARGET_SIGSTKSZ		8192
+
+static inline target_ulong get_sp_from_cpustate(CPUX86State *state)
+{
+    return state->regs[R_ESP];
+}
+
+#endif /* TARGET_SIGNAL_H */
diff --git a/linux-user/x86_64/termbits.h b/linux-user/x86_64/termbits.h
new file mode 100644
index 0000000..1c3445c
--- /dev/null
+++ b/linux-user/x86_64/termbits.h
@@ -0,0 +1,247 @@
+#define TARGET_NCCS 19
+
+typedef unsigned char	target_cc_t;
+typedef unsigned int	target_speed_t;
+typedef unsigned int	target_tcflag_t;
+struct target_termios {
+	target_tcflag_t c_iflag;		/* input mode flags */
+	target_tcflag_t c_oflag;		/* output mode flags */
+	target_tcflag_t c_cflag;		/* control mode flags */
+	target_tcflag_t c_lflag;		/* local mode flags */
+	target_cc_t c_line;			/* line discipline */
+	target_cc_t c_cc[TARGET_NCCS];		/* control characters */
+};
+
+/* c_cc characters */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* c_iflag bits */
+#define TARGET_IGNBRK	0000001
+#define TARGET_BRKINT	0000002
+#define TARGET_IGNPAR	0000004
+#define TARGET_PARMRK	0000010
+#define TARGET_INPCK	0000020
+#define TARGET_ISTRIP	0000040
+#define TARGET_INLCR	0000100
+#define TARGET_IGNCR	0000200
+#define TARGET_ICRNL	0000400
+#define TARGET_IUCLC	0001000
+#define TARGET_IXON	0002000
+#define TARGET_IXANY	0004000
+#define TARGET_IXOFF	0010000
+#define TARGET_IMAXBEL	0020000
+#define TARGET_IUTF8	0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST	0000001
+#define TARGET_OLCUC	0000002
+#define TARGET_ONLCR	0000004
+#define TARGET_OCRNL	0000010
+#define TARGET_ONOCR	0000020
+#define TARGET_ONLRET	0000040
+#define TARGET_OFILL	0000100
+#define TARGET_OFDEL	0000200
+#define TARGET_NLDLY	0000400
+#define   TARGET_NL0	0000000
+#define   TARGET_NL1	0000400
+#define TARGET_CRDLY	0003000
+#define   TARGET_CR0	0000000
+#define   TARGET_CR1	0001000
+#define   TARGET_CR2	0002000
+#define   TARGET_CR3	0003000
+#define TARGET_TABDLY	0014000
+#define   TARGET_TAB0	0000000
+#define   TARGET_TAB1	0004000
+#define   TARGET_TAB2	0010000
+#define   TARGET_TAB3	0014000
+#define   TARGET_XTABS	0014000
+#define TARGET_BSDLY	0020000
+#define   TARGET_BS0	0000000
+#define   TARGET_BS1	0020000
+#define TARGET_VTDLY	0040000
+#define   TARGET_VT0	0000000
+#define   TARGET_VT1	0040000
+#define TARGET_FFDLY	0100000
+#define   TARGET_FF0	0000000
+#define   TARGET_FF1	0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD	0010017
+#define  TARGET_B0	0000000		/* hang up */
+#define  TARGET_B50	0000001
+#define  TARGET_B75	0000002
+#define  TARGET_B110	0000003
+#define  TARGET_B134	0000004
+#define  TARGET_B150	0000005
+#define  TARGET_B200	0000006
+#define  TARGET_B300	0000007
+#define  TARGET_B600	0000010
+#define  TARGET_B1200	0000011
+#define  TARGET_B1800	0000012
+#define  TARGET_B2400	0000013
+#define  TARGET_B4800	0000014
+#define  TARGET_B9600	0000015
+#define  TARGET_B19200	0000016
+#define  TARGET_B38400	0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE	0000060
+#define   TARGET_CS5	0000000
+#define   TARGET_CS6	0000020
+#define   TARGET_CS7	0000040
+#define   TARGET_CS8	0000060
+#define TARGET_CSTOPB	0000100
+#define TARGET_CREAD	0000200
+#define TARGET_PARENB	0000400
+#define TARGET_PARODD	0001000
+#define TARGET_HUPCL	0002000
+#define TARGET_CLOCAL	0004000
+#define TARGET_CBAUDEX 0010000
+#define	   TARGET_BOTHER 0010000		/* non standard rate */
+#define    TARGET_B57600 0010001
+#define   TARGET_B115200 0010002
+#define   TARGET_B230400 0010003
+#define   TARGET_B460800 0010004
+#define   TARGET_B500000 0010005
+#define   TARGET_B576000 0010006
+#define   TARGET_B921600 0010007
+#define  TARGET_B1000000 0010010
+#define  TARGET_B1152000 0010011
+#define  TARGET_B1500000 0010012
+#define  TARGET_B2000000 0010013
+#define  TARGET_B2500000 0010014
+#define  TARGET_B3000000 0010015
+#define  TARGET_B3500000 0010016
+#define  TARGET_B4000000 0010017
+#define TARGET_CIBAUD	  002003600000	/* input baud rate */
+#define TARGET_CMSPAR	  010000000000		/* mark or space (stick) parity */
+#define TARGET_CRTSCTS	  020000000000		/* flow control */
+
+#define TARGET_IBSHIFT	  8		/* Shift from CBAUD to CIBAUD */
+
+/* c_lflag bits */
+#define TARGET_ISIG	0000001
+#define TARGET_ICANON	0000002
+#define TARGET_XCASE	0000004
+#define TARGET_ECHO	0000010
+#define TARGET_ECHOE	0000020
+#define TARGET_ECHOK	0000040
+#define TARGET_ECHONL	0000100
+#define TARGET_NOFLSH	0000200
+#define TARGET_TOSTOP	0000400
+#define TARGET_ECHOCTL	0001000
+#define TARGET_ECHOPRT	0002000
+#define TARGET_ECHOKE	0004000
+#define TARGET_FLUSHO	0010000
+#define TARGET_PENDIN	0040000
+#define TARGET_IEXTEN	0100000
+
+/* tcflow() and TCXONC use these */
+#define	TARGET_TCOOFF		0
+#define	TARGET_TCOON		1
+#define	TARGET_TCIOFF		2
+#define	TARGET_TCION		3
+
+/* tcflush() and TCFLSH use these */
+#define	TARGET_TCIFLUSH	0
+#define	TARGET_TCOFLUSH	1
+#define	TARGET_TCIOFLUSH	2
+
+/* tcsetattr uses these */
+#define	TARGET_TCSANOW		0
+#define	TARGET_TCSADRAIN	1
+#define	TARGET_TCSAFLUSH	2
+
+#define TARGET_TCGETS		0x5401
+#define TARGET_TCSETS		0x5402
+#define TARGET_TCSETSW		0x5403
+#define TARGET_TCSETSF		0x5404
+#define TARGET_TCGETA		0x5405
+#define TARGET_TCSETA		0x5406
+#define TARGET_TCSETAW		0x5407
+#define TARGET_TCSETAF		0x5408
+#define TARGET_TCSBRK		0x5409
+#define TARGET_TCXONC		0x540A
+#define TARGET_TCFLSH		0x540B
+#define TARGET_TIOCEXCL	0x540C
+#define TARGET_TIOCNXCL	0x540D
+#define TARGET_TIOCSCTTY	0x540E
+#define TARGET_TIOCGPGRP	0x540F
+#define TARGET_TIOCSPGRP	0x5410
+#define TARGET_TIOCOUTQ	0x5411
+#define TARGET_TIOCSTI		0x5412
+#define TARGET_TIOCGWINSZ	0x5413
+#define TARGET_TIOCSWINSZ	0x5414
+#define TARGET_TIOCMGET	0x5415
+#define TARGET_TIOCMBIS	0x5416
+#define TARGET_TIOCMBIC	0x5417
+#define TARGET_TIOCMSET	0x5418
+#define TARGET_TIOCGSOFTCAR	0x5419
+#define TARGET_TIOCSSOFTCAR	0x541A
+#define TARGET_FIONREAD	0x541B
+#define TARGET_TIOCINQ		FIONREAD
+#define TARGET_TIOCLINUX	0x541C
+#define TARGET_TIOCCONS	0x541D
+#define TARGET_TIOCGSERIAL	0x541E
+#define TARGET_TIOCSSERIAL	0x541F
+#define TARGET_TIOCPKT		0x5420
+#define TARGET_FIONBIO		0x5421
+#define TARGET_TIOCNOTTY	0x5422
+#define TARGET_TIOCSETD	0x5423
+#define TARGET_TIOCGETD	0x5424
+#define TARGET_TCSBRKP		0x5425	/* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSBRK	0x5427  /* BSD compatibility */
+#define TARGET_TIOCCBRK	0x5428  /* BSD compatibility */
+#define TARGET_TIOCGSID	0x5429  /* Return the session ID of FD */
+#define TARGET_TCGETS2		_IOR('T',0x2A, struct termios2)
+#define TARGET_TCSETS2		_IOW('T',0x2B, struct termios2)
+#define TARGET_TCSETSW2	_IOW('T',0x2C, struct termios2)
+#define TARGET_TCSETSF2	_IOW('T',0x2D, struct termios2)
+#define TARGET_TIOCGPTN	_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK	_IOW('T',0x31, int)  /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX	0x5450  /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX		0x5451
+#define TARGET_FIOASYNC	0x5452
+#define TARGET_TIOCSERCONFIG	0x5453
+#define TARGET_TIOCSERGWILD	0x5454
+#define TARGET_TIOCSERSWILD	0x5455
+#define TARGET_TIOCGLCKTRMIOS	0x5456
+#define TARGET_TIOCSLCKTRMIOS	0x5457
+#define TARGET_TIOCSERGSTRUCT	0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR   0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config  */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
+#define TARGET_FIOQSIZE       0x5460
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA		 0
+#define TARGET_TIOCPKT_FLUSHREAD	 1
+#define TARGET_TIOCPKT_FLUSHWRITE	 2
+#define TARGET_TIOCPKT_STOP		 4
+#define TARGET_TIOCPKT_START		 8
+#define TARGET_TIOCPKT_NOSTOP		16
+#define TARGET_TIOCPKT_DOSTOP		32
+
+#define TARGET_TIOCSER_TEMT    0x01	/* Transmitter physically empty */
diff --git a/loader.c b/loader.c
index 7823add..40bcaf6 100644
--- a/loader.c
+++ b/loader.c
@@ -1,8 +1,8 @@
 /*
  * QEMU Executable loader
- * 
+ *
  * Copyright (c) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -23,6 +23,7 @@
  */
 #include "vl.h"
 #include "disas.h"
+#include "uboot_image.h"
 
 /* return the size or -1 if error */
 int get_image_size(const char *filename)
@@ -195,7 +196,7 @@
 
 /* return < 0 if error, otherwise the number of bytes loaded in memory */
 int load_elf(const char *filename, int64_t virt_to_phys_addend,
-             uint64_t *pentry)
+             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr)
 {
     int fd, data_order, host_data_order, must_swab, ret;
     uint8_t e_ident[EI_NIDENT];
@@ -229,9 +230,11 @@
 
     lseek(fd, 0, SEEK_SET);
     if (e_ident[EI_CLASS] == ELFCLASS64) {
-        ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry);
+        ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry,
+                         lowaddr, highaddr);
     } else {
-        ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry);
+        ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry,
+                         lowaddr, highaddr);
     }
 
     close(fd);
@@ -241,3 +244,80 @@
     close(fd);
     return -1;
 }
+
+static void bswap_uboot_header(uboot_image_header_t *hdr)
+{
+#ifndef WORDS_BIGENDIAN
+    bswap32s(&hdr->ih_magic);
+    bswap32s(&hdr->ih_hcrc);
+    bswap32s(&hdr->ih_time);
+    bswap32s(&hdr->ih_size);
+    bswap32s(&hdr->ih_load);
+    bswap32s(&hdr->ih_ep);
+    bswap32s(&hdr->ih_dcrc);
+#endif
+}
+
+/* Load a U-Boot image.  */
+int load_uboot(const char *filename, target_ulong *ep, int *is_linux)
+{
+
+    int fd;
+    int size;
+    uboot_image_header_t h;
+    uboot_image_header_t *hdr = &h;
+    uint8_t *data = NULL;
+
+    fd = open(filename, O_RDONLY | O_BINARY);
+    if (fd < 0)
+        return -1;
+
+    size = read(fd, hdr, sizeof(uboot_image_header_t));
+    if (size < 0)
+        goto fail;
+
+    bswap_uboot_header(hdr);
+
+    if (hdr->ih_magic != IH_MAGIC)
+        goto fail;
+
+    /* TODO: Implement Multi-File images.  */
+    if (hdr->ih_type == IH_TYPE_MULTI) {
+        fprintf(stderr, "Unable to load multi-file u-boot images\n");
+        goto fail;
+    }
+
+    /* TODO: Implement compressed images.  */
+    if (hdr->ih_comp != IH_COMP_NONE) {
+        fprintf(stderr, "Unable to load compressed u-boot images\n");
+        goto fail;
+    }
+
+    /* TODO: Check CPU type.  */
+    if (is_linux) {
+        if (hdr->ih_type == IH_TYPE_KERNEL && hdr->ih_os == IH_OS_LINUX)
+            *is_linux = 1;
+        else
+            *is_linux = 0;
+    }
+
+    *ep = hdr->ih_ep;
+    data = qemu_malloc(hdr->ih_size);
+    if (!data)
+        goto fail;
+
+    if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
+        fprintf(stderr, "Error reading file\n");
+        goto fail;
+    }
+
+    cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size);
+
+    return hdr->ih_size;
+
+fail:
+    if (data)
+        qemu_free(data);
+    close(fd);
+    return -1;
+}
diff --git a/m68k-dis.c b/m68k-dis.c
index dd19558..10b8d5b 100644
--- a/m68k-dis.c
+++ b/m68k-dis.c
@@ -560,7 +560,7 @@
 };
 
 /* Name of register halves for MAC/EMAC.
-   Seperate from reg_names since 'spu', 'fpl' look weird.  */
+   Separate from reg_names since 'spu', 'fpl' look weird.  */
 static char *const reg_half_names[] =
 {
   "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
@@ -2378,7 +2378,7 @@
 {"eor", 4,	one(0005174),	one(0177777), "#wSs", m68000up },
 {"eor", 4,	one(0005100),	one(0177700), "#w$s", m68000up },
 {"eor", 2,	one(0130500),	one(0170700), "Dd$s", m68000up },
-		
+
 {"exg", 2,	one(0140500),	one(0170770), "DdDs", m68000up },
 {"exg", 2,	one(0140510),	one(0170770), "AdAs", m68000up },
 {"exg", 2,	one(0140610),	one(0170770), "DdAs", m68000up },
@@ -4011,13 +4011,13 @@
 {"roxrl", 2,	one(0160260),		one(0170770), "DdDs", m68000up },
 
 {"rtd", 4,	one(0047164),		one(0177777), "#w", m68010up },
-		
+
 {"rte", 2,	one(0047163),		one(0177777), "",   m68000up | mcfisa_a },
-		
+
 {"rtm", 2,	one(0003300),		one(0177760), "Rs", m68020 },
-		
+
 {"rtr", 2,	one(0047167),		one(0177777), "",   m68000up },
-		
+
 {"rts", 2,	one(0047165),		one(0177777), "",   m68000up | mcfisa_a },
 
 {"satsl", 2,	one(0046200),		one(0177770), "Ds", mcfisa_b },
@@ -4561,12 +4561,12 @@
      zero can it be zero, and then it must be zero.  */
   unsigned long exponent, int_bit;
   const unsigned char *ufrom = (const unsigned char *) from;
-  
+
   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
 			fmt->exp_start, fmt->exp_len);
   int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
 		       fmt->man_start, 1);
-  
+
   if ((exponent == 0) != (int_bit == 0))
     return 0;
   else
@@ -4699,7 +4699,7 @@
     }
   return result;
 }
-  
+
 #ifndef min
 #define min(a, b) ((a) < (b) ? (a) : (b))
 #endif
diff --git a/m68k-semi.c b/m68k-semi.c
new file mode 100644
index 0000000..fc033a1
--- /dev/null
+++ b/m68k-semi.c
@@ -0,0 +1,359 @@
+/*
+ *  m68k/ColdFire Semihosting syscall interface
+ *
+ *  Copyright (c) 2005-2007 CodeSourcery.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "cpu.h"
+#if defined(CONFIG_USER_ONLY)
+#include "qemu.h"
+#define SEMIHOSTING_HEAP_SIZE (128 * 1024 * 1024)
+#else
+#include "vl.h"
+#include "softmmu-semi.h"
+#endif
+
+#define HOSTED_EXIT  0
+#define HOSTED_INIT_SIM 1
+#define HOSTED_OPEN 2
+#define HOSTED_CLOSE 3
+#define HOSTED_READ 4
+#define HOSTED_WRITE 5
+#define HOSTED_LSEEK 6
+#define HOSTED_RENAME 7
+#define HOSTED_UNLINK 8
+#define HOSTED_STAT 9
+#define HOSTED_FSTAT 10
+#define HOSTED_GETTIMEOFDAY 11
+#define HOSTED_ISATTY 12
+#define HOSTED_SYSTEM 13
+
+typedef uint32_t gdb_mode_t;
+typedef uint32_t gdb_time_t;
+
+struct m68k_gdb_stat {
+  uint32_t    gdb_st_dev;     /* device */
+  uint32_t    gdb_st_ino;     /* inode */
+  gdb_mode_t  gdb_st_mode;    /* protection */
+  uint32_t    gdb_st_nlink;   /* number of hard links */
+  uint32_t    gdb_st_uid;     /* user ID of owner */
+  uint32_t    gdb_st_gid;     /* group ID of owner */
+  uint32_t    gdb_st_rdev;    /* device type (if inode device) */
+  uint64_t    gdb_st_size;    /* total size, in bytes */
+  uint64_t    gdb_st_blksize; /* blocksize for filesystem I/O */
+  uint64_t    gdb_st_blocks;  /* number of blocks allocated */
+  gdb_time_t  gdb_st_atime;   /* time of last access */
+  gdb_time_t  gdb_st_mtime;   /* time of last modification */
+  gdb_time_t  gdb_st_ctime;   /* time of last change */
+} __attribute__((packed));
+
+struct gdb_timeval {
+  gdb_time_t tv_sec;  /* second */
+  uint64_t tv_usec;   /* microsecond */
+} __attribute__((packed));
+
+#define GDB_O_RDONLY   0x0
+#define GDB_O_WRONLY   0x1
+#define GDB_O_RDWR     0x2
+#define GDB_O_APPEND   0x8
+#define GDB_O_CREAT  0x200
+#define GDB_O_TRUNC  0x400
+#define GDB_O_EXCL   0x800
+
+static int translate_openflags(int flags)
+{
+    int hf;
+
+    if (flags & GDB_O_WRONLY)
+        hf = O_WRONLY;
+    else if (flags & GDB_O_RDWR)
+        hf = O_RDWR;
+    else
+        hf = O_RDONLY;
+
+    if (flags & GDB_O_APPEND) hf |= O_APPEND;
+    if (flags & GDB_O_CREAT) hf |= O_CREAT;
+    if (flags & GDB_O_TRUNC) hf |= O_TRUNC;
+    if (flags & GDB_O_EXCL) hf |= O_EXCL;
+
+    return hf;
+}
+
+static void translate_stat(CPUState *env, target_ulong addr, struct stat *s)
+{
+    struct m68k_gdb_stat *p;
+
+    p = lock_user(addr, sizeof(struct m68k_gdb_stat), 0);
+    p->gdb_st_dev = cpu_to_be32(s->st_dev);
+    p->gdb_st_ino = cpu_to_be32(s->st_ino);
+    p->gdb_st_mode = cpu_to_be32(s->st_mode);
+    p->gdb_st_nlink = cpu_to_be32(s->st_nlink);
+    p->gdb_st_uid = cpu_to_be32(s->st_uid);
+    p->gdb_st_gid = cpu_to_be32(s->st_gid);
+    p->gdb_st_rdev = cpu_to_be32(s->st_rdev);
+    p->gdb_st_size = cpu_to_be64(s->st_size);
+#ifdef _WIN32
+    /* Windows stat is missing some fields.  */
+    p->gdb_st_blksize = 0;
+    p->gdb_st_blocks = 0;
+#else
+    p->gdb_st_blksize = cpu_to_be64(s->st_blksize);
+    p->gdb_st_blocks = cpu_to_be64(s->st_blocks);
+#endif
+    p->gdb_st_atime = cpu_to_be32(s->st_atime);
+    p->gdb_st_mtime = cpu_to_be32(s->st_mtime);
+    p->gdb_st_ctime = cpu_to_be32(s->st_ctime);
+    unlock_user(p, addr, sizeof(struct m68k_gdb_stat));
+}
+
+static int m68k_semi_is_fseek;
+
+static void m68k_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
+{
+    target_ulong args;
+
+    args = env->dregs[1];
+    if (m68k_semi_is_fseek) {
+        /* FIXME: We've already lost the high bits of the fseek
+           return value.  */
+        tput32(args, 0);
+        args += 4;
+        m68k_semi_is_fseek = 0;
+    }
+    tput32(args, ret);
+    tput32(args + 4, errno);
+}
+
+#define ARG(x) tget32(args + (x) * 4)
+#define PARG(x) ((unsigned long)ARG(x))
+void do_m68k_semihosting(CPUM68KState *env, int nr)
+{
+    uint32_t args;
+    void *p;
+    void *q;
+    uint32_t len;
+    uint32_t result;
+
+    args = env->dregs[1];
+    switch (nr) {
+    case HOSTED_EXIT:
+        exit(env->dregs[0]);
+    case HOSTED_OPEN:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "open,%s,%x,%x", ARG(0), (int)ARG(1),
+                           ARG(2), ARG(3));
+            return;
+        } else {
+            p = lock_user_string(ARG(0));
+            result = open(p, translate_openflags(ARG(2)), ARG(3));
+            unlock_user(p, ARG(0), 0);
+        }
+        break;
+    case HOSTED_CLOSE:
+        {
+            /* Ignore attempts to close stdin/out/err.  */
+            int fd = ARG(0);
+            if (fd > 2) {
+                if (use_gdb_syscalls()) {
+                    gdb_do_syscall(m68k_semi_cb, "close,%x", ARG(0));
+                    return;
+                } else {
+                    result = close(fd);
+                }
+            } else {
+                result = 0;
+            }
+            break;
+        }
+    case HOSTED_READ:
+        len = ARG(2);
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "read,%x,%x,%x",
+                           ARG(0), ARG(1), len);
+            return;
+        } else {
+            p = lock_user(ARG(1), len, 0);
+            result = read(ARG(0), p, len);
+            unlock_user(p, ARG(1), len);
+        }
+        break;
+    case HOSTED_WRITE:
+        len = ARG(2);
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "write,%x,%x,%x",
+                           ARG(0), ARG(1), len);
+            return;
+        } else {
+            p = lock_user(ARG(1), len, 1);
+            result = write(ARG(0), p, len);
+            unlock_user(p, ARG(0), 0);
+        }
+        break;
+    case HOSTED_LSEEK:
+        {
+            uint64_t off;
+            off = (uint32_t)ARG(2) | ((uint64_t)ARG(1) << 32);
+            if (use_gdb_syscalls()) {
+                m68k_semi_is_fseek = 1;
+                gdb_do_syscall(m68k_semi_cb, "fseek,%x,%lx,%x",
+                               ARG(0), off, ARG(3));
+            } else {
+                off = lseek(ARG(0), off, ARG(3));
+                tput32(args, off >> 32);
+                tput32(args + 4, off);
+                tput32(args + 8, errno);
+            }
+            return;
+        }
+    case HOSTED_RENAME:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "rename,%s,%s",
+                           ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
+            return;
+        } else {
+            p = lock_user_string(ARG(0));
+            q = lock_user_string(ARG(2));
+            result = rename(p, q);
+            unlock_user(p, ARG(0), 0);
+            unlock_user(q, ARG(2), 0);
+        }
+        break;
+    case HOSTED_UNLINK:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "unlink,%s",
+                           ARG(0), (int)ARG(1));
+            return;
+        } else {
+            p = lock_user_string(ARG(0));
+            result = unlink(p);
+            unlock_user(p, ARG(0), 0);
+        }
+        break;
+    case HOSTED_STAT:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "stat,%s,%x",
+                           ARG(0), (int)ARG(1), ARG(2));
+            return;
+        } else {
+            struct stat s;
+            p = lock_user_string(ARG(0));
+            result = stat(p, &s);
+            unlock_user(p, ARG(0), 0);
+            if (result == 0) {
+                translate_stat(env, ARG(2), &s);
+            }
+        }
+        break;
+    case HOSTED_FSTAT:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "fstat,%x,%x",
+                           ARG(0), ARG(1));
+            return;
+        } else {
+            struct stat s;
+            result = fstat(ARG(0), &s);
+            if (result == 0) {
+                translate_stat(env, ARG(1), &s);
+            }
+        }
+        break;
+    case HOSTED_GETTIMEOFDAY:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "gettimeofday,%x,%x",
+                           ARG(0), ARG(1));
+            return;
+        } else {
+            qemu_timeval tv;
+            struct gdb_timeval *p;
+            result = qemu_gettimeofday(&tv);
+            if (result != 0) {
+                p = lock_user(ARG(0), sizeof(struct gdb_timeval), 0);
+                p->tv_sec = cpu_to_be32(tv.tv_sec);
+                p->tv_usec = cpu_to_be64(tv.tv_usec);
+                unlock_user(p, ARG(0), sizeof(struct gdb_timeval));
+            }
+        }
+        break;
+    case HOSTED_ISATTY:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "isatty,%x", ARG(0));
+            return;
+        } else {
+            result = isatty(ARG(0));
+        }
+        break;
+    case HOSTED_SYSTEM:
+        if (use_gdb_syscalls()) {
+            gdb_do_syscall(m68k_semi_cb, "system,%s",
+                           ARG(0), (int)ARG(1));
+            return;
+        } else {
+            p = lock_user_string(ARG(0));
+            result = system(p);
+            unlock_user(p, ARG(0), 0);
+        }
+        break;
+    case HOSTED_INIT_SIM:
+#if defined(CONFIG_USER_ONLY)
+        {
+        TaskState *ts = env->opaque;
+        /* Allocate the heap using sbrk.  */
+        if (!ts->heap_limit) {
+            long ret;
+            uint32_t size;
+            uint32_t base;
+
+            base = do_brk(0);
+            size = SEMIHOSTING_HEAP_SIZE;
+            /* Try a big heap, and reduce the size if that fails.  */
+            for (;;) {
+                ret = do_brk(base + size);
+                if (ret != -1)
+                    break;
+                size >>= 1;
+            }
+            ts->heap_limit = base + size;
+        }
+        /* This call may happen before we have writable memory, so return
+           values directly in registers.  */
+        env->dregs[1] = ts->heap_limit;
+        env->aregs[7] = ts->stack_base;
+        }
+#else
+        /* FIXME: This is wrong for boards where RAM does not start at
+           address zero.  */
+        env->dregs[1] = ram_size;
+        env->aregs[7] = ram_size;
+#endif
+        return;
+    default:
+        cpu_abort(env, "Unsupported semihosting syscall %d\n", nr);
+        result = 0;
+    }
+    tput32(args, result);
+    tput32(args + 4, errno);
+}
diff --git a/mips-dis.c b/mips-dis.c
index 2e7dc85..7cf0793 100644
--- a/mips-dis.c
+++ b/mips-dis.c
@@ -207,12 +207,72 @@
 #define	OP_OP_SDC2		0x3e
 #define	OP_OP_SDC3		0x3f	/* a.k.a. sd */
 
+/* MIPS DSP ASE */
+#define OP_SH_DSPACC		11
+#define OP_MASK_DSPACC  	0x3
+#define OP_SH_DSPACC_S  	21
+#define OP_MASK_DSPACC_S	0x3
+#define OP_SH_DSPSFT		20
+#define OP_MASK_DSPSFT  	0x3f
+#define OP_SH_DSPSFT_7  	19
+#define OP_MASK_DSPSFT_7	0x7f
+#define OP_SH_SA3		21
+#define OP_MASK_SA3		0x7
+#define OP_SH_SA4		21
+#define OP_MASK_SA4		0xf
+#define OP_SH_IMM8		16
+#define OP_MASK_IMM8		0xff
+#define OP_SH_IMM10		16
+#define OP_MASK_IMM10		0x3ff
+#define OP_SH_WRDSP		11
+#define OP_MASK_WRDSP		0x3f
+#define OP_SH_RDDSP		16
+#define OP_MASK_RDDSP		0x3f
+#define OP_SH_BP		11
+#define OP_MASK_BP		0x3
+
+/* MIPS MT ASE */
+#define OP_SH_MT_U		5
+#define OP_MASK_MT_U		0x1
+#define OP_SH_MT_H		4
+#define OP_MASK_MT_H		0x1
+#define OP_SH_MTACC_T		18
+#define OP_MASK_MTACC_T		0x3
+#define OP_SH_MTACC_D		13
+#define OP_MASK_MTACC_D		0x3
+
+#define	OP_OP_COP0		0x10
+#define	OP_OP_COP1		0x11
+#define	OP_OP_COP2		0x12
+#define	OP_OP_COP3		0x13
+#define	OP_OP_LWC1		0x31
+#define	OP_OP_LWC2		0x32
+#define	OP_OP_LWC3		0x33	/* a.k.a. pref */
+#define	OP_OP_LDC1		0x35
+#define	OP_OP_LDC2		0x36
+#define	OP_OP_LDC3		0x37	/* a.k.a. ld */
+#define	OP_OP_SWC1		0x39
+#define	OP_OP_SWC2		0x3a
+#define	OP_OP_SWC3		0x3b
+#define	OP_OP_SDC1		0x3d
+#define	OP_OP_SDC2		0x3e
+#define	OP_OP_SDC3		0x3f	/* a.k.a. sd */
+
 /* Values in the 'VSEL' field.  */
 #define MDMX_FMTSEL_IMM_QH	0x1d
 #define MDMX_FMTSEL_IMM_OB	0x1e
 #define MDMX_FMTSEL_VEC_QH	0x15
 #define MDMX_FMTSEL_VEC_OB	0x16
 
+/* UDI */
+#define OP_SH_UDI1		6
+#define OP_MASK_UDI1		0x1f
+#define OP_SH_UDI2		6
+#define OP_MASK_UDI2		0x3ff
+#define OP_SH_UDI3		6
+#define OP_MASK_UDI3		0x7fff
+#define OP_SH_UDI4		6
+#define OP_MASK_UDI4		0xfffff
 /* This structure holds information for a particular instruction.  */
 
 struct mips_opcode
@@ -235,6 +295,8 @@
      of bits describing the instruction, notably any relevant hazard
      information.  */
   unsigned long pinfo;
+  /* A collection of additional bits describing the instruction. */
+  unsigned long pinfo2;
   /* A collection of bits describing the instruction sets of which this
      instruction or macro is a member. */
   unsigned long membership;
@@ -276,19 +338,20 @@
    "x" accept and ignore register name
    "z" must be zero register
    "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD)
-   "+A" 5 bit ins/ext position, which becomes LSB (OP_*_SHAMT).
+   "+A" 5 bit ins/ext/dins/dext/dinsm/dextm position, which becomes
+        LSB (OP_*_SHAMT).
 	Enforces: 0 <= pos < 32.
-   "+B" 5 bit ins size, which becomes MSB (OP_*_INSMSB).
+   "+B" 5 bit ins/dins size, which becomes MSB (OP_*_INSMSB).
 	Requires that "+A" or "+E" occur first to set position.
 	Enforces: 0 < (pos+size) <= 32.
-   "+C" 5 bit ext size, which becomes MSBD (OP_*_EXTMSBD).
+   "+C" 5 bit ext/dext size, which becomes MSBD (OP_*_EXTMSBD).
 	Requires that "+A" or "+E" occur first to set position.
 	Enforces: 0 < (pos+size) <= 32.
 	(Also used by "dext" w/ different limits, but limits for
 	that are checked by the M_DEXT macro.)
-   "+E" 5 bit dins/dext position, which becomes LSB-32 (OP_*_SHAMT).
+   "+E" 5 bit dinsu/dextu position, which becomes LSB-32 (OP_*_SHAMT).
 	Enforces: 32 <= pos < 64.
-   "+F" 5 bit "dinsm" size, which becomes MSB-32 (OP_*_INSMSB).
+   "+F" 5 bit "dinsm/dinsu" size, which becomes MSB-32 (OP_*_INSMSB).
 	Requires that "+A" or "+E" occur first to set position.
 	Enforces: 32 < (pos+size) <= 64.
    "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD).
@@ -329,13 +392,42 @@
    "l" 32 bit floating point constant in .lit4
 
    MDMX instruction operands (note that while these use the FP register
-   fields, they accept both $fN and $vN names for the registers):  
+   fields, they accept both $fN and $vN names for the registers):
    "O"	MDMX alignment offset (OP_*_ALN)
    "Q"	MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT)
-   "X"	MDMX destination register (OP_*_FD) 
+   "X"	MDMX destination register (OP_*_FD)
    "Y"	MDMX source register (OP_*_FS)
    "Z"	MDMX source register (OP_*_FT)
 
+   DSP ASE usage:
+   "2" 2 bit unsigned immediate for byte align (OP_*_BP)
+   "3" 3 bit unsigned immediate (OP_*_SA3)
+   "4" 4 bit unsigned immediate (OP_*_SA4)
+   "5" 8 bit unsigned immediate (OP_*_IMM8)
+   "6" 5 bit unsigned immediate (OP_*_RS)
+   "7" 2 bit dsp accumulator register (OP_*_DSPACC)
+   "8" 6 bit unsigned immediate (OP_*_WRDSP)
+   "9" 2 bit dsp accumulator register (OP_*_DSPACC_S)
+   "0" 6 bit signed immediate (OP_*_DSPSFT)
+   ":" 7 bit signed immediate (OP_*_DSPSFT_7)
+   "'" 6 bit unsigned immediate (OP_*_RDDSP)
+   "@" 10 bit signed immediate (OP_*_IMM10)
+
+   MT ASE usage:
+   "!" 1 bit usermode flag (OP_*_MT_U)
+   "$" 1 bit load high flag (OP_*_MT_H)
+   "*" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_T)
+   "&" 2 bit dsp/smartmips accumulator register (OP_*_MTACC_D)
+   "g" 5 bit coprocessor 1 and 2 destination register (OP_*_RD)
+   "+t" 5 bit coprocessor 0 destination register (OP_*_RT)
+   "+T" 5 bit coprocessor 0 destination register (OP_*_RT) - disassembly only
+
+   UDI immediates:
+   "+1" UDI immediate bits 6-10
+   "+2" UDI immediate bits 6-15
+   "+3" UDI immediate bits 6-20
+   "+4" UDI immediate bits 6-25
+
    Other:
    "()" parens surrounding optional value
    ","  separates operands
@@ -343,13 +435,16 @@
    "+"  Start of extension sequence.
 
    Characters used so far, for quick reference when adding more:
-   "%[]<>(),+"
+   "234567890"
+   "%[]<>(),+:'@!$*&"
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-   "abcdefhijklopqrstuvwxz"
+   "abcdefghijklopqrstuvwxz"
 
    Extension character sequences used so far ("+" followed by the
    following), for quick reference when adding more:
-   "ABCDEFGHI"
+   "1234"
+   "ABCDEFGHIT"
+   "t"
 */
 
 /* These are the bits which may be set in the pinfo field of an
@@ -419,10 +514,16 @@
 #define INSN_MULT                   0x40000000
 /* Instruction synchronize shared memory.  */
 #define INSN_SYNC		    0x80000000
-/* Instruction reads MDMX accumulator.  XXX FIXME: No bits left!  */
-#define INSN_READ_MDMX_ACC	    0
-/* Instruction writes MDMX accumulator.  XXX FIXME: No bits left!  */
-#define INSN_WRITE_MDMX_ACC	    0
+
+/* These are the bits which may be set in the pinfo2 field of an
+   instruction. */
+
+/* Instruction is a simple alias (I.E. "move" for daddu/addu/or) */
+#define	INSN2_ALIAS		    0x00000001
+/* Instruction reads MDMX accumulator. */
+#define INSN2_READ_MDMX_ACC	    0x00000002
+/* Instruction writes MDMX accumulator. */
+#define INSN2_WRITE_MDMX_ACC	    0x00000004
 
 /* Instruction is actually a macro.  It should be ignored by the
    disassembler, and requires special treatment by the assembler.  */
@@ -447,12 +548,13 @@
 /* Masks used for MIPS-defined ASEs.  */
 #define INSN_ASE_MASK		  0x0000f000
 
+/* DSP ASE */
+#define INSN_DSP                  0x00001000
+#define INSN_DSP64                0x00002000
 /* MIPS 16 ASE */
-#define INSN_MIPS16               0x00002000
+#define INSN_MIPS16               0x00004000
 /* MIPS-3D ASE */
-#define INSN_MIPS3D               0x00004000
-/* MDMX ASE */ 
-#define INSN_MDMX                 0x00008000
+#define INSN_MIPS3D               0x00008000
 
 /* Chip specific instructions.  These are bitmasks.  */
 
@@ -477,6 +579,15 @@
 /* NEC VR5500 instruction.  */
 #define INSN_5500		  0x02000000
 
+/* MDMX ASE */
+#define INSN_MDMX                 0x04000000
+/* MT ASE */
+#define INSN_MT                   0x08000000
+/* SmartMIPS ASE  */
+#define INSN_SMARTMIPS            0x10000000
+/* DSP R2 ASE  */
+#define INSN_DSPR2                0x20000000
+
 /* MIPS ISA defines, use instead of hardcoding ISA level.  */
 
 #define       ISA_UNKNOWN     0               /* Gas internal use.  */
@@ -533,6 +644,7 @@
     (((insn)->membership & isa) != 0					\
      || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0)	\
      || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0)	\
+     || (cpu == CPU_RM9000 && ((insn)->membership & INSN_4650) != 0)	\
      || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0)	\
      || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0)	\
      || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0)	\
@@ -563,6 +675,7 @@
   M_ADD_I,
   M_ADDU_I,
   M_AND_I,
+  M_BALIGN,
   M_BEQ,
   M_BEQ_I,
   M_BEQL_I,
@@ -601,6 +714,7 @@
   M_BNE,
   M_BNE_I,
   M_BNEL_I,
+  M_CACHE_AB,
   M_DABS,
   M_DADD_I,
   M_DADDU_I,
@@ -907,6 +1021,11 @@
    "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5)
    */
 
+/* Save/restore encoding for the args field when all 4 registers are
+   either saved as arguments or saved/restored as statics.  */
+#define MIPS16_ALL_ARGS    0xe
+#define MIPS16_ALL_STATICS 0xb
+
 /* For the mips16, we use the same opcode table format and a few of
    the same flags.  However, most of the flags are different.  */
 
@@ -1008,8 +1127,8 @@
 
 #define IS_M    INSN_MULT
 
-#define WR_MACC INSN_WRITE_MDMX_ACC
-#define RD_MACC INSN_READ_MDMX_ACC
+#define WR_MACC INSN2_WRITE_MDMX_ACC
+#define RD_MACC INSN2_READ_MDMX_ACC
 
 #define I1	INSN_ISA1
 #define I2	INSN_ISA2
@@ -1024,6 +1143,9 @@
 /* MIPS64 MIPS-3D ASE support.  */
 #define I16     INSN_MIPS16
 
+/* MIPS32 SmartMIPS ASE support.  */
+#define SMT	INSN_SMARTMIPS
+
 /* MIPS64 MIPS-3D ASE support.  */
 #define M3D     INSN_MIPS3D
 
@@ -1051,6 +1173,38 @@
 #define G3      (I4             \
                  )
 
+/* MIPS DSP ASE support.
+   NOTE:
+   1. MIPS DSP ASE includes 4 accumulators ($ac0 - $ac3).  $ac0 is the pair
+   of original HI and LO.  $ac1, $ac2 and $ac3 are new registers, and have
+   the same structure as $ac0 (HI + LO).  For DSP instructions that write or
+   read accumulators (that may be $ac0), we add WR_a (WR_HILO) or RD_a
+   (RD_HILO) attributes, such that HILO dependencies are maintained
+   conservatively.
+
+   2. For some mul. instructions that use integer registers as destinations
+   but destroy HI+LO as side-effect, we add WR_HILO to their attributes.
+
+   3. MIPS DSP ASE includes a new DSP control register, which has 6 fields
+   (ccond, outflag, EFI, c, scount, pos).  Many DSP instructions read or write
+   certain fields of the DSP control register.  For simplicity, we decide not
+   to track dependencies of these fields.
+   However, "bposge32" is a branch instruction that depends on the "pos"
+   field.  In order to make sure that GAS does not reorder DSP instructions
+   that writes the "pos" field and "bposge32", we add DSP_VOLA (INSN_TRAP)
+   attribute to those instructions that write the "pos" field.  */
+
+#define WR_a	WR_HILO	/* Write dsp accumulators (reuse WR_HILO)  */
+#define RD_a	RD_HILO	/* Read dsp accumulators (reuse RD_HILO)  */
+#define MOD_a	WR_a|RD_a
+#define DSP_VOLA	INSN_TRAP
+#define D32	INSN_DSP
+#define D33	INSN_DSPR2
+#define D64	INSN_DSP64
+
+/* MIPS MT ASE support.  */
+#define MT32	INSN_MT
+
 /* The order of overloaded instructions matters.  Label arguments and
    register arguments look the same. Instructions that can have either
    for arguments must apear in the correct order in this table for the
@@ -1060,7 +1214,7 @@
 
    Because of the lookup algorithm used, entries with the same opcode
    name must be contiguous.
- 
+
    Many instructions are short hand for other instructions (i.e., The
    jal <register> instruction is short for jalr <register>).  */
 
@@ -1070,1083 +1224,1524 @@
    them first.  The assemblers uses a hash table based on the
    instruction name anyhow.  */
 /* name,    args,	match,	    mask,	pinfo,          	membership */
-{"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	I4|I32|G3	},
-{"prefx",   "h,t(b)",	0x4c00000f, 0xfc0007ff, RD_b|RD_t,		I4	},
-{"nop",     "",         0x00000000, 0xffffffff, 0,              	I1      }, /* sll */
-{"ssnop",   "",         0x00000040, 0xffffffff, 0,              	I32|N55	}, /* sll */
-{"ehb",     "",         0x000000c0, 0xffffffff, 0,              	I33	}, /* sll */
-{"li",      "t,j",      0x24000000, 0xffe00000, WR_t,			I1	}, /* addiu */
-{"li",	    "t,i",	0x34000000, 0xffe00000, WR_t,			I1	}, /* ori */
-{"li",      "t,I",	0,    (int) M_LI,	INSN_MACRO,		I1	},
-{"move",    "d,s",	0,    (int) M_MOVE,	INSN_MACRO,		I1	},
-{"move",    "d,s",	0x0000002d, 0xfc1f07ff, WR_d|RD_s,		I3	},/* daddu */
-{"move",    "d,s",	0x00000021, 0xfc1f07ff, WR_d|RD_s,		I1	},/* addu */
-{"move",    "d,s",	0x00000025, 0xfc1f07ff,	WR_d|RD_s,		I1	},/* or */
-{"b",       "p",	0x10000000, 0xffff0000,	UBD,			I1	},/* beq 0,0 */
-{"b",       "p",	0x04010000, 0xffff0000,	UBD,			I1	},/* bgez 0 */
-{"bal",     "p",	0x04110000, 0xffff0000,	UBD|WR_31,		I1	},/* bgezal 0*/
+{"pref",    "k,o(b)",   0xcc000000, 0xfc000000, RD_b,           	0,		I4|I32|G3	},
+{"prefx",   "h,t(b)",	0x4c00000f, 0xfc0007ff, RD_b|RD_t,		0,		I4|I33	},
+{"nop",     "",         0x00000000, 0xffffffff, 0,              	INSN2_ALIAS,	I1      }, /* sll */
+{"ssnop",   "",         0x00000040, 0xffffffff, 0,              	INSN2_ALIAS,	I32|N55	}, /* sll */
+{"ehb",     "",         0x000000c0, 0xffffffff, 0,              	INSN2_ALIAS,	I33	}, /* sll */
+{"li",      "t,j",      0x24000000, 0xffe00000, WR_t,			INSN2_ALIAS,	I1	}, /* addiu */
+{"li",	    "t,i",	0x34000000, 0xffe00000, WR_t,			INSN2_ALIAS,	I1	}, /* ori */
+{"li",      "t,I",	0,    (int) M_LI,	INSN_MACRO,		0,		I1	},
+{"move",    "d,s",	0,    (int) M_MOVE,	INSN_MACRO,		0,		I1	},
+{"move",    "d,s",	0x0000002d, 0xfc1f07ff, WR_d|RD_s,		INSN2_ALIAS,	I3	},/* daddu */
+{"move",    "d,s",	0x00000021, 0xfc1f07ff, WR_d|RD_s,		INSN2_ALIAS,	I1	},/* addu */
+{"move",    "d,s",	0x00000025, 0xfc1f07ff,	WR_d|RD_s,		INSN2_ALIAS,	I1	},/* or */
+{"b",       "p",	0x10000000, 0xffff0000,	UBD,			INSN2_ALIAS,	I1	},/* beq 0,0 */
+{"b",       "p",	0x04010000, 0xffff0000,	UBD,			INSN2_ALIAS,	I1	},/* bgez 0 */
+{"bal",     "p",	0x04110000, 0xffff0000,	UBD|WR_31,		INSN2_ALIAS,	I1	},/* bgezal 0*/
 
-{"abs",     "d,v",	0,    (int) M_ABS,	INSN_MACRO,		I1	},
-{"abs.s",   "D,V",	0x46000005, 0xffff003f,	WR_D|RD_S|FP_S,		I1	},
-{"abs.d",   "D,V",	0x46200005, 0xffff003f,	WR_D|RD_S|FP_D,		I1	},
-{"abs.ps",  "D,V",	0x46c00005, 0xffff003f,	WR_D|RD_S|FP_D,		I5	},
-{"add",     "d,v,t",	0x00000020, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"add",     "t,r,I",	0,    (int) M_ADD_I,	INSN_MACRO,		I1	},
-{"add.s",   "D,V,T",	0x46000000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	I1	},
-{"add.d",   "D,V,T",	0x46200000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I1	},
-{"add.ob",  "X,Y,Q",	0x7800000b, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"add.ob",  "D,S,T",	0x4ac0000b, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"add.ob",  "D,S,T[e]",	0x4800000b, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"add.ob",  "D,S,k",	0x4bc0000b, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"add.ps",  "D,V,T",	0x46c00000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
-{"add.qh",  "X,Y,Q",	0x7820000b, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"adda.ob", "Y,Q",	0x78000037, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"adda.qh", "Y,Q",	0x78200037, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"addi",    "t,r,j",	0x20000000, 0xfc000000,	WR_t|RD_s,		I1	},
-{"addiu",   "t,r,j",	0x24000000, 0xfc000000,	WR_t|RD_s,		I1	},
-{"addl.ob", "Y,Q",	0x78000437, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"addl.qh", "Y,Q",	0x78200437, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"addr.ps", "D,S,T",	0x46c00018, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	M3D	},
-{"addu",    "d,v,t",	0x00000021, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"addu",    "t,r,I",	0,    (int) M_ADDU_I,	INSN_MACRO,		I1	},
-{"alni.ob", "X,Y,Z,O",	0x78000018, 0xff00003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"alni.ob", "D,S,T,%",	0x48000018, 0xff00003f,	WR_D|RD_S|RD_T, 	N54	},
-{"alni.qh", "X,Y,Z,O",	0x7800001a, 0xff00003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"alnv.ps", "D,V,T,s",	0x4c00001e, 0xfc00003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
-{"alnv.ob", "X,Y,Z,s",	0x78000019, 0xfc00003f,	WR_D|RD_S|RD_T|RD_s|FP_D, MX|SB1	},
-{"alnv.qh", "X,Y,Z,s",	0x7800001b, 0xfc00003f,	WR_D|RD_S|RD_T|RD_s|FP_D, MX	},
-{"and",     "d,v,t",	0x00000024, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"and",     "t,r,I",	0,    (int) M_AND_I,	INSN_MACRO,		I1	},
-{"and.ob",  "X,Y,Q",	0x7800000c, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"and.ob",  "D,S,T",	0x4ac0000c, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"and.ob",  "D,S,T[e]",	0x4800000c, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"and.ob",  "D,S,k",	0x4bc0000c, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"and.qh",  "X,Y,Q",	0x7820000c, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"andi",    "t,r,i",	0x30000000, 0xfc000000,	WR_t|RD_s,		I1	},
+{"abs",     "d,v",	0,    (int) M_ABS,	INSN_MACRO,		0,		I1	},
+{"abs.s",   "D,V",	0x46000005, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"abs.d",   "D,V",	0x46200005, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I1	},
+{"abs.ps",  "D,V",	0x46c00005, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I5|I33	},
+{"add",     "d,v,t",	0x00000020, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"add",     "t,r,I",	0,    (int) M_ADD_I,	INSN_MACRO,		0,		I1	},
+{"add.s",   "D,V,T",	0x46000000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		I1	},
+{"add.d",   "D,V,T",	0x46200000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I1	},
+{"add.ob",  "X,Y,Q",	0x7800000b, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"add.ob",  "D,S,T",	0x4ac0000b, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"add.ob",  "D,S,T[e]",	0x4800000b, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"add.ob",  "D,S,k",	0x4bc0000b, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"add.ps",  "D,V,T",	0x46c00000, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"add.qh",  "X,Y,Q",	0x7820000b, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"adda.ob", "Y,Q",	0x78000037, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"adda.qh", "Y,Q",	0x78200037, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"addi",    "t,r,j",	0x20000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"addiu",   "t,r,j",	0x24000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"addl.ob", "Y,Q",	0x78000437, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"addl.qh", "Y,Q",	0x78200437, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"addr.ps", "D,S,T",	0x46c00018, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		M3D	},
+{"addu",    "d,v,t",	0x00000021, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"addu",    "t,r,I",	0,    (int) M_ADDU_I,	INSN_MACRO,		0,		I1	},
+{"alni.ob", "X,Y,Z,O",	0x78000018, 0xff00003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"alni.ob", "D,S,T,%",	0x48000018, 0xff00003f,	WR_D|RD_S|RD_T, 	0,		N54	},
+{"alni.qh", "X,Y,Z,O",	0x7800001a, 0xff00003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"alnv.ps", "D,V,T,s",	0x4c00001e, 0xfc00003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"alnv.ob", "X,Y,Z,s",	0x78000019, 0xfc00003f,	WR_D|RD_S|RD_T|RD_s|FP_D, 0,		MX|SB1	},
+{"alnv.qh", "X,Y,Z,s",	0x7800001b, 0xfc00003f,	WR_D|RD_S|RD_T|RD_s|FP_D, 0,		MX	},
+{"and",     "d,v,t",	0x00000024, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"and",     "t,r,I",	0,    (int) M_AND_I,	INSN_MACRO,		0,		I1	},
+{"and.ob",  "X,Y,Q",	0x7800000c, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"and.ob",  "D,S,T",	0x4ac0000c, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"and.ob",  "D,S,T[e]",	0x4800000c, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"and.ob",  "D,S,k",	0x4bc0000c, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"and.qh",  "X,Y,Q",	0x7820000c, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"andi",    "t,r,i",	0x30000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
 /* b is at the top of the table.  */
 /* bal is at the top of the table.  */
-{"bc0f",    "p",	0x41000000, 0xffff0000,	CBD|RD_CC,		I1	},
-{"bc0fl",   "p",	0x41020000, 0xffff0000,	CBL|RD_CC,		I2|T3	},
-{"bc0t",    "p",	0x41010000, 0xffff0000,	CBD|RD_CC,		I1	},
-{"bc0tl",   "p",	0x41030000, 0xffff0000,	CBL|RD_CC,		I2|T3	},
-{"bc1any2f", "N,p",	0x45200000, 0xffe30000,	CBD|RD_CC|FP_S,		M3D	},
-{"bc1any2t", "N,p",	0x45210000, 0xffe30000,	CBD|RD_CC|FP_S,		M3D	},
-{"bc1any4f", "N,p",	0x45400000, 0xffe30000,	CBD|RD_CC|FP_S,		M3D	},
-{"bc1any4t", "N,p",	0x45410000, 0xffe30000,	CBD|RD_CC|FP_S,		M3D	},
-{"bc1f",    "p",	0x45000000, 0xffff0000,	CBD|RD_CC|FP_S,		I1	},
-{"bc1f",    "N,p",      0x45000000, 0xffe30000, CBD|RD_CC|FP_S, 	I4|I32	},
-{"bc1fl",   "p",	0x45020000, 0xffff0000,	CBL|RD_CC|FP_S,		I2|T3	},
-{"bc1fl",   "N,p",      0x45020000, 0xffe30000, CBL|RD_CC|FP_S, 	I4|I32	},
-{"bc1t",    "p",	0x45010000, 0xffff0000,	CBD|RD_CC|FP_S,		I1	},
-{"bc1t",    "N,p",      0x45010000, 0xffe30000, CBD|RD_CC|FP_S, 	I4|I32	},
-{"bc1tl",   "p",	0x45030000, 0xffff0000,	CBL|RD_CC|FP_S,		I2|T3	},
-{"bc1tl",   "N,p",      0x45030000, 0xffe30000, CBL|RD_CC|FP_S, 	I4|I32	},
+/* bc0[tf]l? are at the bottom of the table.  */
+{"bc1any2f", "N,p",	0x45200000, 0xffe30000,	CBD|RD_CC|FP_S,		0,		M3D	},
+{"bc1any2t", "N,p",	0x45210000, 0xffe30000,	CBD|RD_CC|FP_S,		0,		M3D	},
+{"bc1any4f", "N,p",	0x45400000, 0xffe30000,	CBD|RD_CC|FP_S,		0,		M3D	},
+{"bc1any4t", "N,p",	0x45410000, 0xffe30000,	CBD|RD_CC|FP_S,		0,		M3D	},
+{"bc1f",    "p",	0x45000000, 0xffff0000,	CBD|RD_CC|FP_S,		0,		I1	},
+{"bc1f",    "N,p",      0x45000000, 0xffe30000, CBD|RD_CC|FP_S, 	0,		I4|I32	},
+{"bc1fl",   "p",	0x45020000, 0xffff0000,	CBL|RD_CC|FP_S,		0,		I2|T3	},
+{"bc1fl",   "N,p",      0x45020000, 0xffe30000, CBL|RD_CC|FP_S, 	0,		I4|I32	},
+{"bc1t",    "p",	0x45010000, 0xffff0000,	CBD|RD_CC|FP_S,		0,		I1	},
+{"bc1t",    "N,p",      0x45010000, 0xffe30000, CBD|RD_CC|FP_S, 	0,		I4|I32	},
+{"bc1tl",   "p",	0x45030000, 0xffff0000,	CBL|RD_CC|FP_S,		0,		I2|T3	},
+{"bc1tl",   "N,p",      0x45030000, 0xffe30000, CBL|RD_CC|FP_S, 	0,		I4|I32	},
 /* bc2* are at the bottom of the table.  */
-{"bc3f",    "p",	0x4d000000, 0xffff0000,	CBD|RD_CC,		I1	},
-{"bc3fl",   "p",	0x4d020000, 0xffff0000,	CBL|RD_CC,		I2|T3	},
-{"bc3t",    "p",	0x4d010000, 0xffff0000,	CBD|RD_CC,		I1	},
-{"bc3tl",   "p",	0x4d030000, 0xffff0000,	CBL|RD_CC,		I2|T3	},
-{"beqz",    "s,p",	0x10000000, 0xfc1f0000,	CBD|RD_s,		I1	},
-{"beqzl",   "s,p",	0x50000000, 0xfc1f0000,	CBL|RD_s,		I2|T3	},
-{"beq",     "s,t,p",	0x10000000, 0xfc000000,	CBD|RD_s|RD_t,		I1	},
-{"beq",     "s,I,p",	0,    (int) M_BEQ_I,	INSN_MACRO,		I1	},
-{"beql",    "s,t,p",	0x50000000, 0xfc000000,	CBL|RD_s|RD_t,		I2|T3	},
-{"beql",    "s,I,p",	0,    (int) M_BEQL_I,	INSN_MACRO,		I2|T3	},
-{"bge",     "s,t,p",	0,    (int) M_BGE,	INSN_MACRO,		I1	},
-{"bge",     "s,I,p",	0,    (int) M_BGE_I,	INSN_MACRO,		I1	},
-{"bgel",    "s,t,p",	0,    (int) M_BGEL,	INSN_MACRO,		I2|T3	},
-{"bgel",    "s,I,p",	0,    (int) M_BGEL_I,	INSN_MACRO,		I2|T3	},
-{"bgeu",    "s,t,p",	0,    (int) M_BGEU,	INSN_MACRO,		I1	},
-{"bgeu",    "s,I,p",	0,    (int) M_BGEU_I,	INSN_MACRO,		I1	},
-{"bgeul",   "s,t,p",	0,    (int) M_BGEUL,	INSN_MACRO,		I2|T3	},
-{"bgeul",   "s,I,p",	0,    (int) M_BGEUL_I,	INSN_MACRO,		I2|T3	},
-{"bgez",    "s,p",	0x04010000, 0xfc1f0000,	CBD|RD_s,		I1	},
-{"bgezl",   "s,p",	0x04030000, 0xfc1f0000,	CBL|RD_s,		I2|T3	},
-{"bgezal",  "s,p",	0x04110000, 0xfc1f0000,	CBD|RD_s|WR_31,		I1	},
-{"bgezall", "s,p",	0x04130000, 0xfc1f0000,	CBL|RD_s|WR_31,		I2|T3	},
-{"bgt",     "s,t,p",	0,    (int) M_BGT,	INSN_MACRO,		I1	},
-{"bgt",     "s,I,p",	0,    (int) M_BGT_I,	INSN_MACRO,		I1	},
-{"bgtl",    "s,t,p",	0,    (int) M_BGTL,	INSN_MACRO,		I2|T3	},
-{"bgtl",    "s,I,p",	0,    (int) M_BGTL_I,	INSN_MACRO,		I2|T3	},
-{"bgtu",    "s,t,p",	0,    (int) M_BGTU,	INSN_MACRO,		I1	},
-{"bgtu",    "s,I,p",	0,    (int) M_BGTU_I,	INSN_MACRO,		I1	},
-{"bgtul",   "s,t,p",	0,    (int) M_BGTUL,	INSN_MACRO,		I2|T3	},
-{"bgtul",   "s,I,p",	0,    (int) M_BGTUL_I,	INSN_MACRO,		I2|T3	},
-{"bgtz",    "s,p",	0x1c000000, 0xfc1f0000,	CBD|RD_s,		I1	},
-{"bgtzl",   "s,p",	0x5c000000, 0xfc1f0000,	CBL|RD_s,		I2|T3	},
-{"ble",     "s,t,p",	0,    (int) M_BLE,	INSN_MACRO,		I1	},
-{"ble",     "s,I,p",	0,    (int) M_BLE_I,	INSN_MACRO,		I1	},
-{"blel",    "s,t,p",	0,    (int) M_BLEL,	INSN_MACRO,		I2|T3	},
-{"blel",    "s,I,p",	0,    (int) M_BLEL_I,	INSN_MACRO,		I2|T3	},
-{"bleu",    "s,t,p",	0,    (int) M_BLEU,	INSN_MACRO,		I1	},
-{"bleu",    "s,I,p",	0,    (int) M_BLEU_I,	INSN_MACRO,		I1	},
-{"bleul",   "s,t,p",	0,    (int) M_BLEUL,	INSN_MACRO,		I2|T3	},
-{"bleul",   "s,I,p",	0,    (int) M_BLEUL_I,	INSN_MACRO,		I2|T3	},
-{"blez",    "s,p",	0x18000000, 0xfc1f0000,	CBD|RD_s,		I1	},
-{"blezl",   "s,p",	0x58000000, 0xfc1f0000,	CBL|RD_s,		I2|T3	},
-{"blt",     "s,t,p",	0,    (int) M_BLT,	INSN_MACRO,		I1	},
-{"blt",     "s,I,p",	0,    (int) M_BLT_I,	INSN_MACRO,		I1	},
-{"bltl",    "s,t,p",	0,    (int) M_BLTL,	INSN_MACRO,		I2|T3	},
-{"bltl",    "s,I,p",	0,    (int) M_BLTL_I,	INSN_MACRO,		I2|T3	},
-{"bltu",    "s,t,p",	0,    (int) M_BLTU,	INSN_MACRO,		I1	},
-{"bltu",    "s,I,p",	0,    (int) M_BLTU_I,	INSN_MACRO,		I1	},
-{"bltul",   "s,t,p",	0,    (int) M_BLTUL,	INSN_MACRO,		I2|T3	},
-{"bltul",   "s,I,p",	0,    (int) M_BLTUL_I,	INSN_MACRO,		I2|T3	},
-{"bltz",    "s,p",	0x04000000, 0xfc1f0000,	CBD|RD_s,		I1	},
-{"bltzl",   "s,p",	0x04020000, 0xfc1f0000,	CBL|RD_s,		I2|T3	},
-{"bltzal",  "s,p",	0x04100000, 0xfc1f0000,	CBD|RD_s|WR_31,		I1	},
-{"bltzall", "s,p",	0x04120000, 0xfc1f0000,	CBL|RD_s|WR_31,		I2|T3	},
-{"bnez",    "s,p",	0x14000000, 0xfc1f0000,	CBD|RD_s,		I1	},
-{"bnezl",   "s,p",	0x54000000, 0xfc1f0000,	CBL|RD_s,		I2|T3	},
-{"bne",     "s,t,p",	0x14000000, 0xfc000000,	CBD|RD_s|RD_t,		I1	},
-{"bne",     "s,I,p",	0,    (int) M_BNE_I,	INSN_MACRO,		I1	},
-{"bnel",    "s,t,p",	0x54000000, 0xfc000000,	CBL|RD_s|RD_t, 		I2|T3	},
-{"bnel",    "s,I,p",	0,    (int) M_BNEL_I,	INSN_MACRO,		I2|T3	},
-{"break",   "",		0x0000000d, 0xffffffff,	TRAP,			I1	},
-{"break",   "c",	0x0000000d, 0xfc00ffff,	TRAP,			I1	},
-{"break",   "c,q",	0x0000000d, 0xfc00003f,	TRAP,			I1	},
-{"c.f.d",   "S,T",	0x46200030, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.f.d",   "M,S,T",    0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.f.s",   "S,T",      0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.f.s",   "M,S,T",    0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.f.ps",  "S,T",	0x46c00030, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.f.ps",  "M,S,T",	0x46c00030, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.un.d",  "S,T",	0x46200031, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.un.d",  "M,S,T",    0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.un.s",  "S,T",      0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.un.s",  "M,S,T",    0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.un.ps", "S,T",	0x46c00031, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.un.ps", "M,S,T",	0x46c00031, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.eq.d",  "S,T",	0x46200032, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.eq.d",  "M,S,T",    0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.eq.s",  "S,T",      0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.eq.s",  "M,S,T",    0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.eq.ob", "Y,Q",	0x78000001, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"c.eq.ob", "S,T",	0x4ac00001, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.eq.ob", "S,T[e]",	0x48000001, 0xfe2007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.eq.ob", "S,k",	0x4bc00001, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.eq.ps", "S,T",	0x46c00032, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.eq.ps", "M,S,T",	0x46c00032, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.eq.qh", "Y,Q",	0x78200001, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	MX	},
-{"c.ueq.d", "S,T",	0x46200033, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.ueq.d", "M,S,T",    0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.ueq.s", "S,T",      0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.ueq.s", "M,S,T",    0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.ueq.ps","S,T",	0x46c00033, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ueq.ps","M,S,T",	0x46c00033, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.olt.d", "S,T",      0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D,   I1      },
-{"c.olt.d", "M,S,T",    0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.olt.s", "S,T",	0x46000034, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	I1	},
-{"c.olt.s", "M,S,T",    0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.olt.ps","S,T",	0x46c00034, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.olt.ps","M,S,T",	0x46c00034, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ult.d", "S,T",	0x46200035, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.ult.d", "M,S,T",    0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.ult.s", "S,T",      0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.ult.s", "M,S,T",    0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.ult.ps","S,T",	0x46c00035, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ult.ps","M,S,T",	0x46c00035, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ole.d", "S,T",      0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D,   I1      },
-{"c.ole.d", "M,S,T",    0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.ole.s", "S,T",      0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.ole.s", "M,S,T",    0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.ole.ps","S,T",	0x46c00036, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ole.ps","M,S,T",	0x46c00036, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ule.d", "S,T",	0x46200037, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.ule.d", "M,S,T",    0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.ule.s", "S,T",      0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.ule.s", "M,S,T",    0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.ule.ps","S,T",	0x46c00037, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ule.ps","M,S,T",	0x46c00037, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.sf.d",  "S,T",	0x46200038, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.sf.d",  "M,S,T",    0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.sf.s",  "S,T",      0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.sf.s",  "M,S,T",    0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.sf.ps", "S,T",	0x46c00038, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.sf.ps", "M,S,T",	0x46c00038, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ngle.d","S,T",	0x46200039, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.ngle.d","M,S,T",    0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.ngle.s","S,T",      0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.ngle.s","M,S,T",    0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.ngle.ps","S,T",	0x46c00039, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ngle.ps","M,S,T",	0x46c00039, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.seq.d", "S,T",	0x4620003a, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.seq.d", "M,S,T",    0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.seq.s", "S,T",      0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.seq.s", "M,S,T",    0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.seq.ps","S,T",	0x46c0003a, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.seq.ps","M,S,T",	0x46c0003a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ngl.d", "S,T",	0x4620003b, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.ngl.d", "M,S,T",    0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.ngl.s", "S,T",      0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.ngl.s", "M,S,T",    0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.ngl.ps","S,T",	0x46c0003b, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ngl.ps","M,S,T",	0x46c0003b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.lt.d",  "S,T",	0x4620003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.lt.d",  "M,S,T",    0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.lt.s",  "S,T",	0x4600003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	I1	},
-{"c.lt.s",  "M,S,T",    0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.lt.ob", "Y,Q",	0x78000004, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"c.lt.ob", "S,T",	0x4ac00004, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.lt.ob", "S,T[e]",	0x48000004, 0xfe2007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.lt.ob", "S,k",	0x4bc00004, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.lt.ps", "S,T",	0x46c0003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.lt.ps", "M,S,T",	0x46c0003c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.lt.qh", "Y,Q",	0x78200004, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	MX	},
-{"c.nge.d", "S,T",	0x4620003d, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.nge.d", "M,S,T",    0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.nge.s", "S,T",      0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.nge.s", "M,S,T",    0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.nge.ps","S,T",	0x46c0003d, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.nge.ps","M,S,T",	0x46c0003d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.le.d",  "S,T",	0x4620003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.le.d",  "M,S,T",    0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.le.s",  "S,T",	0x4600003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	I1	},
-{"c.le.s",  "M,S,T",    0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.le.ob", "Y,Q",	0x78000005, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"c.le.ob", "S,T",	0x4ac00005, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.le.ob", "S,T[e]",	0x48000005, 0xfe2007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.le.ob", "S,k",	0x4bc00005, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"c.le.ps", "S,T",	0x46c0003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.le.ps", "M,S,T",	0x46c0003e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.le.qh", "Y,Q",	0x78200005, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	MX	},
-{"c.ngt.d", "S,T",	0x4620003f, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I1	},
-{"c.ngt.d", "M,S,T",    0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   I4|I32	},
-{"c.ngt.s", "S,T",      0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   I1      },
-{"c.ngt.s", "M,S,T",    0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   I4|I32	},
-{"c.ngt.ps","S,T",	0x46c0003f, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"c.ngt.ps","M,S,T",	0x46c0003f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	I5	},
-{"cabs.eq.d",  "M,S,T",	0x46200072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.eq.ps", "M,S,T",	0x46c00072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.eq.s",  "M,S,T",	0x46000072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.f.d",   "M,S,T",	0x46200070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.f.ps",  "M,S,T",	0x46c00070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.f.s",   "M,S,T",	0x46000070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.le.d",  "M,S,T",	0x4620007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.le.ps", "M,S,T",	0x46c0007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.le.s",  "M,S,T",	0x4600007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.lt.d",  "M,S,T",	0x4620007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.lt.ps", "M,S,T",	0x46c0007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.lt.s",  "M,S,T",	0x4600007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.nge.d", "M,S,T",	0x4620007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.nge.ps","M,S,T",	0x46c0007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.nge.s", "M,S,T",	0x4600007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.ngl.d", "M,S,T",	0x4620007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ngl.ps","M,S,T",	0x46c0007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ngl.s", "M,S,T",	0x4600007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.ngle.d","M,S,T",	0x46200079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ngle.s","M,S,T",	0x46000079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.ngt.d", "M,S,T",	0x4620007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ngt.ps","M,S,T",	0x46c0007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ngt.s", "M,S,T",	0x4600007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.ole.d", "M,S,T",	0x46200076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ole.ps","M,S,T",	0x46c00076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ole.s", "M,S,T",	0x46000076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.olt.d", "M,S,T",	0x46200074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.olt.ps","M,S,T",	0x46c00074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.olt.s", "M,S,T",	0x46000074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.seq.d", "M,S,T",	0x4620007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.seq.ps","M,S,T",	0x46c0007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.seq.s", "M,S,T",	0x4600007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.sf.d",  "M,S,T",	0x46200078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.sf.ps", "M,S,T",	0x46c00078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.sf.s",  "M,S,T",	0x46000078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.ueq.d", "M,S,T",	0x46200073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ueq.ps","M,S,T",	0x46c00073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ueq.s", "M,S,T",	0x46000073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.ule.d", "M,S,T",	0x46200077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ule.ps","M,S,T",	0x46c00077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ule.s", "M,S,T",	0x46000077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.ult.d", "M,S,T",	0x46200075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ult.ps","M,S,T",	0x46c00075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.ult.s", "M,S,T",	0x46000075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cabs.un.d",  "M,S,T",	0x46200071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.un.ps", "M,S,T",	0x46c00071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	M3D	},
-{"cabs.un.s",  "M,S,T",	0x46000071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	M3D	},
-{"cache",   "k,o(b)",   0xbc000000, 0xfc000000, RD_b,           	I3|I32|T3},
-{"ceil.l.d", "D,S",	0x4620000a, 0xffff003f, WR_D|RD_S|FP_D,		I3	},
-{"ceil.l.s", "D,S",	0x4600000a, 0xffff003f, WR_D|RD_S|FP_S,		I3	},
-{"ceil.w.d", "D,S",	0x4620000e, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
-{"ceil.w.s", "D,S",	0x4600000e, 0xffff003f, WR_D|RD_S|FP_S,		I2	},
-{"cfc0",    "t,G",	0x40400000, 0xffe007ff,	LCD|WR_t|RD_C0,		I1	},
-{"cfc1",    "t,G",	0x44400000, 0xffe007ff,	LCD|WR_t|RD_C1|FP_S,	I1	},
-{"cfc1",    "t,S",	0x44400000, 0xffe007ff,	LCD|WR_t|RD_C1|FP_S,	I1	},
+/* bc3* are at the bottom of the table.  */
+{"beqz",    "s,p",	0x10000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"beqzl",   "s,p",	0x50000000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"beq",     "s,t,p",	0x10000000, 0xfc000000,	CBD|RD_s|RD_t,		0,		I1	},
+{"beq",     "s,I,p",	0,    (int) M_BEQ_I,	INSN_MACRO,		0,		I1	},
+{"beql",    "s,t,p",	0x50000000, 0xfc000000,	CBL|RD_s|RD_t,		0,		I2|T3	},
+{"beql",    "s,I,p",	0,    (int) M_BEQL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bge",     "s,t,p",	0,    (int) M_BGE,	INSN_MACRO,		0,		I1	},
+{"bge",     "s,I,p",	0,    (int) M_BGE_I,	INSN_MACRO,		0,		I1	},
+{"bgel",    "s,t,p",	0,    (int) M_BGEL,	INSN_MACRO,		0,		I2|T3	},
+{"bgel",    "s,I,p",	0,    (int) M_BGEL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bgeu",    "s,t,p",	0,    (int) M_BGEU,	INSN_MACRO,		0,		I1	},
+{"bgeu",    "s,I,p",	0,    (int) M_BGEU_I,	INSN_MACRO,		0,		I1	},
+{"bgeul",   "s,t,p",	0,    (int) M_BGEUL,	INSN_MACRO,		0,		I2|T3	},
+{"bgeul",   "s,I,p",	0,    (int) M_BGEUL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bgez",    "s,p",	0x04010000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"bgezl",   "s,p",	0x04030000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"bgezal",  "s,p",	0x04110000, 0xfc1f0000,	CBD|RD_s|WR_31,		0,		I1	},
+{"bgezall", "s,p",	0x04130000, 0xfc1f0000,	CBL|RD_s|WR_31,		0,		I2|T3	},
+{"bgt",     "s,t,p",	0,    (int) M_BGT,	INSN_MACRO,		0,		I1	},
+{"bgt",     "s,I,p",	0,    (int) M_BGT_I,	INSN_MACRO,		0,		I1	},
+{"bgtl",    "s,t,p",	0,    (int) M_BGTL,	INSN_MACRO,		0,		I2|T3	},
+{"bgtl",    "s,I,p",	0,    (int) M_BGTL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bgtu",    "s,t,p",	0,    (int) M_BGTU,	INSN_MACRO,		0,		I1	},
+{"bgtu",    "s,I,p",	0,    (int) M_BGTU_I,	INSN_MACRO,		0,		I1	},
+{"bgtul",   "s,t,p",	0,    (int) M_BGTUL,	INSN_MACRO,		0,		I2|T3	},
+{"bgtul",   "s,I,p",	0,    (int) M_BGTUL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bgtz",    "s,p",	0x1c000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"bgtzl",   "s,p",	0x5c000000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"ble",     "s,t,p",	0,    (int) M_BLE,	INSN_MACRO,		0,		I1	},
+{"ble",     "s,I,p",	0,    (int) M_BLE_I,	INSN_MACRO,		0,		I1	},
+{"blel",    "s,t,p",	0,    (int) M_BLEL,	INSN_MACRO,		0,		I2|T3	},
+{"blel",    "s,I,p",	0,    (int) M_BLEL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bleu",    "s,t,p",	0,    (int) M_BLEU,	INSN_MACRO,		0,		I1	},
+{"bleu",    "s,I,p",	0,    (int) M_BLEU_I,	INSN_MACRO,		0,		I1	},
+{"bleul",   "s,t,p",	0,    (int) M_BLEUL,	INSN_MACRO,		0,		I2|T3	},
+{"bleul",   "s,I,p",	0,    (int) M_BLEUL_I,	INSN_MACRO,		0,		I2|T3	},
+{"blez",    "s,p",	0x18000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"blezl",   "s,p",	0x58000000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"blt",     "s,t,p",	0,    (int) M_BLT,	INSN_MACRO,		0,		I1	},
+{"blt",     "s,I,p",	0,    (int) M_BLT_I,	INSN_MACRO,		0,		I1	},
+{"bltl",    "s,t,p",	0,    (int) M_BLTL,	INSN_MACRO,		0,		I2|T3	},
+{"bltl",    "s,I,p",	0,    (int) M_BLTL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bltu",    "s,t,p",	0,    (int) M_BLTU,	INSN_MACRO,		0,		I1	},
+{"bltu",    "s,I,p",	0,    (int) M_BLTU_I,	INSN_MACRO,		0,		I1	},
+{"bltul",   "s,t,p",	0,    (int) M_BLTUL,	INSN_MACRO,		0,		I2|T3	},
+{"bltul",   "s,I,p",	0,    (int) M_BLTUL_I,	INSN_MACRO,		0,		I2|T3	},
+{"bltz",    "s,p",	0x04000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"bltzl",   "s,p",	0x04020000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"bltzal",  "s,p",	0x04100000, 0xfc1f0000,	CBD|RD_s|WR_31,		0,		I1	},
+{"bltzall", "s,p",	0x04120000, 0xfc1f0000,	CBL|RD_s|WR_31,		0,		I2|T3	},
+{"bnez",    "s,p",	0x14000000, 0xfc1f0000,	CBD|RD_s,		0,		I1	},
+{"bnezl",   "s,p",	0x54000000, 0xfc1f0000,	CBL|RD_s,		0,		I2|T3	},
+{"bne",     "s,t,p",	0x14000000, 0xfc000000,	CBD|RD_s|RD_t,		0,		I1	},
+{"bne",     "s,I,p",	0,    (int) M_BNE_I,	INSN_MACRO,		0,		I1	},
+{"bnel",    "s,t,p",	0x54000000, 0xfc000000,	CBL|RD_s|RD_t, 		0,		I2|T3	},
+{"bnel",    "s,I,p",	0,    (int) M_BNEL_I,	INSN_MACRO,		0,		I2|T3	},
+{"break",   "",		0x0000000d, 0xffffffff,	TRAP,			0,		I1	},
+{"break",   "c",	0x0000000d, 0xfc00ffff,	TRAP,			0,		I1	},
+{"break",   "c,q",	0x0000000d, 0xfc00003f,	TRAP,			0,		I1	},
+{"c.f.d",   "S,T",	0x46200030, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.f.d",   "M,S,T",    0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.f.s",   "S,T",      0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.f.s",   "M,S,T",    0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.f.ps",  "S,T",	0x46c00030, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.f.ps",  "M,S,T",	0x46c00030, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.un.d",  "S,T",	0x46200031, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.un.d",  "M,S,T",    0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.un.s",  "S,T",      0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.un.s",  "M,S,T",    0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.un.ps", "S,T",	0x46c00031, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.un.ps", "M,S,T",	0x46c00031, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.eq.d",  "S,T",	0x46200032, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.eq.d",  "M,S,T",    0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.eq.s",  "S,T",      0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.eq.s",  "M,S,T",    0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.eq.ob", "Y,Q",	0x78000001, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"c.eq.ob", "S,T",	0x4ac00001, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.eq.ob", "S,T[e]",	0x48000001, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.eq.ob", "S,k",	0x4bc00001, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.eq.ps", "S,T",	0x46c00032, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.eq.ps", "M,S,T",	0x46c00032, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.eq.qh", "Y,Q",	0x78200001, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX	},
+{"c.ueq.d", "S,T",	0x46200033, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ueq.d", "M,S,T",    0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ueq.s", "S,T",      0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ueq.s", "M,S,T",    0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ueq.ps","S,T",	0x46c00033, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ueq.ps","M,S,T",	0x46c00033, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.olt.d", "S,T",      0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D,   0,		I1      },
+{"c.olt.d", "M,S,T",    0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.olt.s", "S,T",	0x46000034, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	0,		I1	},
+{"c.olt.s", "M,S,T",    0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.olt.ps","S,T",	0x46c00034, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.olt.ps","M,S,T",	0x46c00034, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ult.d", "S,T",	0x46200035, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ult.d", "M,S,T",    0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ult.s", "S,T",      0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ult.s", "M,S,T",    0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ult.ps","S,T",	0x46c00035, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ult.ps","M,S,T",	0x46c00035, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ole.d", "S,T",      0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D,   0,		I1      },
+{"c.ole.d", "M,S,T",    0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ole.s", "S,T",      0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ole.s", "M,S,T",    0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ole.ps","S,T",	0x46c00036, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ole.ps","M,S,T",	0x46c00036, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ule.d", "S,T",	0x46200037, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ule.d", "M,S,T",    0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ule.s", "S,T",      0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ule.s", "M,S,T",    0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ule.ps","S,T",	0x46c00037, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ule.ps","M,S,T",	0x46c00037, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.sf.d",  "S,T",	0x46200038, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.sf.d",  "M,S,T",    0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.sf.s",  "S,T",      0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.sf.s",  "M,S,T",    0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.sf.ps", "S,T",	0x46c00038, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.sf.ps", "M,S,T",	0x46c00038, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngle.d","S,T",	0x46200039, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ngle.d","M,S,T",    0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ngle.s","S,T",      0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ngle.s","M,S,T",    0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ngle.ps","S,T",	0x46c00039, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngle.ps","M,S,T",	0x46c00039, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.seq.d", "S,T",	0x4620003a, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.seq.d", "M,S,T",    0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.seq.s", "S,T",      0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.seq.s", "M,S,T",    0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.seq.ps","S,T",	0x46c0003a, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.seq.ps","M,S,T",	0x46c0003a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngl.d", "S,T",	0x4620003b, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ngl.d", "M,S,T",    0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ngl.s", "S,T",      0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ngl.s", "M,S,T",    0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ngl.ps","S,T",	0x46c0003b, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngl.ps","M,S,T",	0x46c0003b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.lt.d",  "S,T",	0x4620003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.lt.d",  "M,S,T",    0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.lt.s",  "S,T",	0x4600003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	0,		I1	},
+{"c.lt.s",  "M,S,T",    0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.lt.ob", "Y,Q",	0x78000004, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"c.lt.ob", "S,T",	0x4ac00004, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.lt.ob", "S,T[e]",	0x48000004, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.lt.ob", "S,k",	0x4bc00004, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.lt.ps", "S,T",	0x46c0003c, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.lt.ps", "M,S,T",	0x46c0003c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.lt.qh", "Y,Q",	0x78200004, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX	},
+{"c.nge.d", "S,T",	0x4620003d, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.nge.d", "M,S,T",    0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.nge.s", "S,T",      0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.nge.s", "M,S,T",    0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.nge.ps","S,T",	0x46c0003d, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.nge.ps","M,S,T",	0x46c0003d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.le.d",  "S,T",	0x4620003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.le.d",  "M,S,T",    0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.le.s",  "S,T",	0x4600003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_S,	0,		I1	},
+{"c.le.s",  "M,S,T",    0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.le.ob", "Y,Q",	0x78000005, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"c.le.ob", "S,T",	0x4ac00005, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.le.ob", "S,T[e]",	0x48000005, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.le.ob", "S,k",	0x4bc00005, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"c.le.ps", "S,T",	0x46c0003e, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.le.ps", "M,S,T",	0x46c0003e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.le.qh", "Y,Q",	0x78200005, 0xfc2007ff,	WR_CC|RD_S|RD_T|FP_D,	0,		MX	},
+{"c.ngt.d", "S,T",	0x4620003f, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I1	},
+{"c.ngt.d", "M,S,T",    0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D,   0,		I4|I32	},
+{"c.ngt.s", "S,T",      0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S,   0,		I1      },
+{"c.ngt.s", "M,S,T",    0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S,   0,		I4|I32	},
+{"c.ngt.ps","S,T",	0x46c0003f, 0xffe007ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"c.ngt.ps","M,S,T",	0x46c0003f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		I5|I33	},
+{"cabs.eq.d",  "M,S,T",	0x46200072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.eq.ps", "M,S,T",	0x46c00072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.eq.s",  "M,S,T",	0x46000072, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.f.d",   "M,S,T",	0x46200070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.f.ps",  "M,S,T",	0x46c00070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.f.s",   "M,S,T",	0x46000070, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.le.d",  "M,S,T",	0x4620007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.le.ps", "M,S,T",	0x46c0007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.le.s",  "M,S,T",	0x4600007e, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.lt.d",  "M,S,T",	0x4620007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.lt.ps", "M,S,T",	0x46c0007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.lt.s",  "M,S,T",	0x4600007c, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.nge.d", "M,S,T",	0x4620007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.nge.ps","M,S,T",	0x46c0007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.nge.s", "M,S,T",	0x4600007d, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ngl.d", "M,S,T",	0x4620007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngl.ps","M,S,T",	0x46c0007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngl.s", "M,S,T",	0x4600007b, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ngle.d","M,S,T",	0x46200079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngle.s","M,S,T",	0x46000079, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ngt.d", "M,S,T",	0x4620007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngt.ps","M,S,T",	0x46c0007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ngt.s", "M,S,T",	0x4600007f, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ole.d", "M,S,T",	0x46200076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ole.ps","M,S,T",	0x46c00076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ole.s", "M,S,T",	0x46000076, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.olt.d", "M,S,T",	0x46200074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.olt.ps","M,S,T",	0x46c00074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.olt.s", "M,S,T",	0x46000074, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.seq.d", "M,S,T",	0x4620007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.seq.ps","M,S,T",	0x46c0007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.seq.s", "M,S,T",	0x4600007a, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.sf.d",  "M,S,T",	0x46200078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.sf.ps", "M,S,T",	0x46c00078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.sf.s",  "M,S,T",	0x46000078, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ueq.d", "M,S,T",	0x46200073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ueq.ps","M,S,T",	0x46c00073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ueq.s", "M,S,T",	0x46000073, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ule.d", "M,S,T",	0x46200077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ule.ps","M,S,T",	0x46c00077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ule.s", "M,S,T",	0x46000077, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.ult.d", "M,S,T",	0x46200075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ult.ps","M,S,T",	0x46c00075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.ult.s", "M,S,T",	0x46000075, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+{"cabs.un.d",  "M,S,T",	0x46200071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.un.ps", "M,S,T",	0x46c00071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_D,	0,		M3D	},
+{"cabs.un.s",  "M,S,T",	0x46000071, 0xffe000ff,	RD_S|RD_T|WR_CC|FP_S,	0,		M3D	},
+/* CW4010 instructions which are aliases for the cache instruction.  */
+{"flushi",  "",		0xbc010000, 0xffffffff, 0,			0,		L1	},
+{"flushd",  "",		0xbc020000, 0xffffffff, 0, 			0,		L1	},
+{"flushid", "",		0xbc030000, 0xffffffff, 0, 			0,		L1	},
+{"wb", 	    "o(b)",	0xbc040000, 0xfc1f0000, SM|RD_b,		0,		L1	},
+{"cache",   "k,o(b)",   0xbc000000, 0xfc000000, RD_b,           	0,		I3|I32|T3},
+{"cache",   "k,A(b)",	0,    (int) M_CACHE_AB, INSN_MACRO,		0,		I3|I32|T3},
+{"ceil.l.d", "D,S",	0x4620000a, 0xffff003f, WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"ceil.l.s", "D,S",	0x4600000a, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"ceil.w.d", "D,S",	0x4620000e, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"ceil.w.s", "D,S",	0x4600000e, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
+{"cfc0",    "t,G",	0x40400000, 0xffe007ff,	LCD|WR_t|RD_C0,		0,		I1	},
+{"cfc1",    "t,G",	0x44400000, 0xffe007ff,	LCD|WR_t|RD_C1|FP_S,	0,		I1	},
+{"cfc1",    "t,S",	0x44400000, 0xffe007ff,	LCD|WR_t|RD_C1|FP_S,	0,		I1	},
 /* cfc2 is at the bottom of the table.  */
-{"cfc3",    "t,G",	0x4c400000, 0xffe007ff,	LCD|WR_t|RD_C3,		I1	},
-{"clo",     "U,s",      0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 	I32|N55 },
-{"clz",     "U,s",      0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 	I32|N55 },
-{"ctc0",    "t,G",	0x40c00000, 0xffe007ff,	COD|RD_t|WR_CC,		I1	},
-{"ctc1",    "t,G",	0x44c00000, 0xffe007ff,	COD|RD_t|WR_CC|FP_S,	I1	},
-{"ctc1",    "t,S",	0x44c00000, 0xffe007ff,	COD|RD_t|WR_CC|FP_S,	I1	},
+/* cfc3 is at the bottom of the table.  */
+{"cftc1",   "d,E",	0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0,		MT32	},
+{"cftc1",   "d,T",	0x41000023, 0xffe007ff, TRAP|LCD|WR_d|RD_C1|FP_S, 0,		MT32	},
+{"cftc2",   "d,E",	0x41000025, 0xffe007ff, TRAP|LCD|WR_d|RD_C2,	0,		MT32	},
+{"clo",     "U,s",      0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, 	0,		I32|N55 },
+{"clz",     "U,s",      0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, 	0,		I32|N55 },
+{"ctc0",    "t,G",	0x40c00000, 0xffe007ff,	COD|RD_t|WR_CC,		0,		I1	},
+{"ctc1",    "t,G",	0x44c00000, 0xffe007ff,	COD|RD_t|WR_CC|FP_S,	0,		I1	},
+{"ctc1",    "t,S",	0x44c00000, 0xffe007ff,	COD|RD_t|WR_CC|FP_S,	0,		I1	},
 /* ctc2 is at the bottom of the table.  */
-{"ctc3",    "t,G",	0x4cc00000, 0xffe007ff,	COD|RD_t|WR_CC,		I1	},
-{"cvt.d.l", "D,S",	0x46a00021, 0xffff003f,	WR_D|RD_S|FP_D,		I3	},
-{"cvt.d.s", "D,S",	0x46000021, 0xffff003f,	WR_D|RD_S|FP_D|FP_S,	I1	},
-{"cvt.d.w", "D,S",	0x46800021, 0xffff003f,	WR_D|RD_S|FP_D,		I1	},
-{"cvt.l.d", "D,S",	0x46200025, 0xffff003f,	WR_D|RD_S|FP_D,		I3	},
-{"cvt.l.s", "D,S",	0x46000025, 0xffff003f,	WR_D|RD_S|FP_S,		I3	},
-{"cvt.s.l", "D,S",	0x46a00020, 0xffff003f,	WR_D|RD_S|FP_S,		I3	},
-{"cvt.s.d", "D,S",	0x46200020, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	I1	},
-{"cvt.s.w", "D,S",	0x46800020, 0xffff003f,	WR_D|RD_S|FP_S,		I1	},
-{"cvt.s.pl","D,S",	0x46c00028, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	I5	},
-{"cvt.s.pu","D,S",	0x46c00020, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	I5	},
-{"cvt.w.d", "D,S",	0x46200024, 0xffff003f,	WR_D|RD_S|FP_D,		I1	},
-{"cvt.w.s", "D,S",	0x46000024, 0xffff003f,	WR_D|RD_S|FP_S,		I1	},
-{"cvt.ps.pw", "D,S",	0x46800026, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	M3D	},
-{"cvt.ps.s","D,V,T",	0x46000026, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
-{"cvt.pw.ps", "D,S",	0x46c00024, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	M3D	},
-{"dabs",    "d,v",	0,    (int) M_DABS,	INSN_MACRO,		I3	},
-{"dadd",    "d,v,t",	0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t,		I3	},
-{"dadd",    "t,r,I",	0,    (int) M_DADD_I,	INSN_MACRO,		I3	},
-{"daddi",   "t,r,j",	0x60000000, 0xfc000000, WR_t|RD_s,		I3	},
-{"daddiu",  "t,r,j",	0x64000000, 0xfc000000, WR_t|RD_s,		I3	},
-{"daddu",   "d,v,t",	0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t,		I3	},
-{"daddu",   "t,r,I",	0,    (int) M_DADDU_I,	INSN_MACRO,		I3	},
-{"dbreak",  "",		0x7000003f, 0xffffffff,	0,			N5	},
-{"dclo",    "U,s",      0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, 	I64|N55 },
-{"dclz",    "U,s",      0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, 	I64|N55 },
+/* ctc3 is at the bottom of the table.  */
+{"cttc1",   "t,g",	0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0,		MT32	},
+{"cttc1",   "t,S",	0x41800023, 0xffe007ff, TRAP|COD|RD_t|WR_CC|FP_S, 0,		MT32	},
+{"cttc2",   "t,g",	0x41800025, 0xffe007ff, TRAP|COD|RD_t|WR_CC,	0,		MT32	},
+{"cvt.d.l", "D,S",	0x46a00021, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"cvt.d.s", "D,S",	0x46000021, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I1	},
+{"cvt.d.w", "D,S",	0x46800021, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I1	},
+{"cvt.l.d", "D,S",	0x46200025, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"cvt.l.s", "D,S",	0x46000025, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"cvt.s.l", "D,S",	0x46a00020, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"cvt.s.d", "D,S",	0x46200020, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I1	},
+{"cvt.s.w", "D,S",	0x46800020, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"cvt.s.pl","D,S",	0x46c00028, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I5|I33	},
+{"cvt.s.pu","D,S",	0x46c00020, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I5|I33	},
+{"cvt.w.d", "D,S",	0x46200024, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I1	},
+{"cvt.w.s", "D,S",	0x46000024, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"cvt.ps.pw", "D,S",	0x46800026, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		M3D	},
+{"cvt.ps.s","D,V,T",	0x46000026, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S|FP_D, 0,		I5|I33	},
+{"cvt.pw.ps", "D,S",	0x46c00024, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		M3D	},
+{"dabs",    "d,v",	0,    (int) M_DABS,	INSN_MACRO,		0,		I3	},
+{"dadd",    "d,v,t",	0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		I3	},
+{"dadd",    "t,r,I",	0,    (int) M_DADD_I,	INSN_MACRO,		0,		I3	},
+{"daddi",   "t,r,j",	0x60000000, 0xfc000000, WR_t|RD_s,		0,		I3	},
+{"daddiu",  "t,r,j",	0x64000000, 0xfc000000, WR_t|RD_s,		0,		I3	},
+{"daddu",   "d,v,t",	0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		I3	},
+{"daddu",   "t,r,I",	0,    (int) M_DADDU_I,	INSN_MACRO,		0,		I3	},
+{"dbreak",  "",		0x7000003f, 0xffffffff,	0,			0,		N5	},
+{"dclo",    "U,s",      0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, 	0,		I64|N55 },
+{"dclz",    "U,s",      0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, 	0,		I64|N55 },
 /* dctr and dctw are used on the r5000.  */
-{"dctr",    "o(b)",	0xbc050000, 0xfc1f0000, RD_b,			I3	},
-{"dctw",    "o(b)",	0xbc090000, 0xfc1f0000, RD_b,			I3	},
-{"deret",   "",         0x4200001f, 0xffffffff, 0, 			I32|G2	},
-{"dext",    "t,r,I,+I",	0,    (int) M_DEXT,	INSN_MACRO,		I65	},
-{"dext",    "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s,    		I65	},
-{"dextm",   "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s,    		I65	},
-{"dextu",   "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s,    		I65	},
+{"dctr",    "o(b)",	0xbc050000, 0xfc1f0000, RD_b,			0,		I3	},
+{"dctw",    "o(b)",	0xbc090000, 0xfc1f0000, RD_b,			0,		I3	},
+{"deret",   "",         0x4200001f, 0xffffffff, 0, 			0,		I32|G2	},
+{"dext",    "t,r,I,+I",	0,    (int) M_DEXT,	INSN_MACRO,		0,		I65	},
+{"dext",    "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+{"dextm",   "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+{"dextu",   "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
 /* For ddiv, see the comments about div.  */
-{"ddiv",    "z,s,t",    0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I3      },
-{"ddiv",    "d,v,t",	0,    (int) M_DDIV_3,	INSN_MACRO,		I3	},
-{"ddiv",    "d,v,I",	0,    (int) M_DDIV_3I,	INSN_MACRO,		I3	},
+{"ddiv",    "z,s,t",    0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3      },
+{"ddiv",    "d,v,t",	0,    (int) M_DDIV_3,	INSN_MACRO,		0,		I3	},
+{"ddiv",    "d,v,I",	0,    (int) M_DDIV_3I,	INSN_MACRO,		0,		I3	},
 /* For ddivu, see the comments about div.  */
-{"ddivu",   "z,s,t",    0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I3      },
-{"ddivu",   "d,v,t",	0,    (int) M_DDIVU_3,	INSN_MACRO,		I3	},
-{"ddivu",   "d,v,I",	0,    (int) M_DDIVU_3I,	INSN_MACRO,		I3	},
-{"di",      "",		0x41606000, 0xffffffff,	WR_t|WR_C0,		I33	},
-{"di",      "t",	0x41606000, 0xffe0ffff,	WR_t|WR_C0,		I33	},
-{"dins",    "t,r,I,+I",	0,    (int) M_DINS,	INSN_MACRO,		I65	},
-{"dins",    "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s,    		I65	},
-{"dinsm",   "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s,    		I65	},
-{"dinsu",   "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s,    		I65	},
+{"ddivu",   "z,s,t",    0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3      },
+{"ddivu",   "d,v,t",	0,    (int) M_DDIVU_3,	INSN_MACRO,		0,		I3	},
+{"ddivu",   "d,v,I",	0,    (int) M_DDIVU_3I,	INSN_MACRO,		0,		I3	},
+{"di",      "",		0x41606000, 0xffffffff,	WR_t|WR_C0,		0,		I33	},
+{"di",      "t",	0x41606000, 0xffe0ffff,	WR_t|WR_C0,		0,		I33	},
+{"dins",    "t,r,I,+I",	0,    (int) M_DINS,	INSN_MACRO,		0,		I65	},
+{"dins",    "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+{"dinsm",   "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
+{"dinsu",   "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s,    		0,		I65	},
 /* The MIPS assembler treats the div opcode with two operands as
    though the first operand appeared twice (the first operand is both
    a source and a destination).  To get the div machine instruction,
    you must use an explicit destination of $0.  */
-{"div",     "z,s,t",    0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I1      },
-{"div",     "z,t",      0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO,      I1      },
-{"div",     "d,v,t",	0,    (int) M_DIV_3,	INSN_MACRO,		I1	},
-{"div",     "d,v,I",	0,    (int) M_DIV_3I,	INSN_MACRO,		I1	},
-{"div.d",   "D,V,T",	0x46200003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I1	},
-{"div.s",   "D,V,T",	0x46000003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	I1	},
-{"div.ps",  "D,V,T",	0x46c00003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	SB1	},
+{"div",     "z,s,t",    0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I1      },
+{"div",     "z,t",      0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO,      0,		I1      },
+{"div",     "d,v,t",	0,    (int) M_DIV_3,	INSN_MACRO,		0,		I1	},
+{"div",     "d,v,I",	0,    (int) M_DIV_3I,	INSN_MACRO,		0,		I1	},
+{"div.d",   "D,V,T",	0x46200003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I1	},
+{"div.s",   "D,V,T",	0x46000003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		I1	},
+{"div.ps",  "D,V,T",	0x46c00003, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		SB1	},
 /* For divu, see the comments about div.  */
-{"divu",    "z,s,t",    0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I1      },
-{"divu",    "z,t",      0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO,      I1      },
-{"divu",    "d,v,t",	0,    (int) M_DIVU_3,	INSN_MACRO,		I1	},
-{"divu",    "d,v,I",	0,    (int) M_DIVU_3I,	INSN_MACRO,		I1	},
-{"dla",     "t,A(b)",	0,    (int) M_DLA_AB,	INSN_MACRO,		I3	},
-{"dlca",    "t,A(b)",	0,    (int) M_DLCA_AB,	INSN_MACRO,		I3	},
-{"dli",     "t,j",      0x24000000, 0xffe00000, WR_t,			I3	}, /* addiu */
-{"dli",	    "t,i",	0x34000000, 0xffe00000, WR_t,			I3	}, /* ori */
-{"dli",     "t,I",	0,    (int) M_DLI,	INSN_MACRO,		I3	},
-{"dmacc",   "d,s,t",	0x00000029, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	N412	},
-{"dmacchi", "d,s,t",	0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	N412	},
-{"dmacchis", "d,s,t",	0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	N412	},
-{"dmacchiu", "d,s,t",	0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	N412	},
-{"dmacchius", "d,s,t",	0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	N412	},
-{"dmaccs",  "d,s,t",	0x00000429, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	N412	},
-{"dmaccu",  "d,s,t",	0x00000069, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	N412	},
-{"dmaccus", "d,s,t",	0x00000469, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	N412	},
-{"dmadd16", "s,t",      0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO,       N411    },
-{"dmfc0",   "t,G",	0x40200000, 0xffe007ff, LCD|WR_t|RD_C0,		I3	},
-{"dmfc0",   "t,+D",     0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	I64     },
-{"dmfc0",   "t,G,H",    0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	I64     },
-{"dmtc0",   "t,G",	0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC,	I3	},
-{"dmtc0",   "t,+D",     0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I64     },
-{"dmtc0",   "t,G,H",    0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I64     },
-{"dmfc1",   "t,S",	0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S,	I3	},
-{"dmfc1",   "t,G",      0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S,     I3      },
-{"dmtc1",   "t,S",	0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S,	I3	},
-{"dmtc1",   "t,G",      0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S,     I3      },
+{"divu",    "z,s,t",    0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I1      },
+{"divu",    "z,t",      0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO,      0,		I1      },
+{"divu",    "d,v,t",	0,    (int) M_DIVU_3,	INSN_MACRO,		0,		I1	},
+{"divu",    "d,v,I",	0,    (int) M_DIVU_3I,	INSN_MACRO,		0,		I1	},
+{"dla",     "t,A(b)",	0,    (int) M_DLA_AB,	INSN_MACRO,		0,		I3	},
+{"dlca",    "t,A(b)",	0,    (int) M_DLCA_AB,	INSN_MACRO,		0,		I3	},
+{"dli",     "t,j",      0x24000000, 0xffe00000, WR_t,			0,		I3	}, /* addiu */
+{"dli",	    "t,i",	0x34000000, 0xffe00000, WR_t,			0,		I3	}, /* ori */
+{"dli",     "t,I",	0,    (int) M_DLI,	INSN_MACRO,		0,		I3	},
+{"dmacc",   "d,s,t",	0x00000029, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmacchi", "d,s,t",	0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmacchis", "d,s,t",	0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmacchiu", "d,s,t",	0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmacchius", "d,s,t",	0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmaccs",  "d,s,t",	0x00000429, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmaccu",  "d,s,t",	0x00000069, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmaccus", "d,s,t",	0x00000469, 0xfc0007ff,	RD_s|RD_t|WR_LO|WR_d,	0,		N412	},
+{"dmadd16", "s,t",      0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO,       0,		N411    },
+{"dmfc0",   "t,G",	0x40200000, 0xffe007ff, LCD|WR_t|RD_C0,		0,		I3	},
+{"dmfc0",   "t,+D",     0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	0,		I64     },
+{"dmfc0",   "t,G,H",    0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, 	0,		I64     },
+{"dmt",     "",		0x41600bc1, 0xffffffff, TRAP,			0,		MT32	},
+{"dmt",     "t",	0x41600bc1, 0xffe0ffff, TRAP|WR_t,		0,		MT32	},
+{"dmtc0",   "t,G",	0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC,	0,		I3	},
+{"dmtc0",   "t,+D",     0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   0,		I64     },
+{"dmtc0",   "t,G,H",    0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   0,		I64     },
+{"dmfc1",   "t,S",	0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D,	0,		I3	},
+{"dmfc1",   "t,G",      0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_D,     0,		I3      },
+{"dmtc1",   "t,S",	0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D,	0,		I3	},
+{"dmtc1",   "t,G",      0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_D,     0,		I3      },
 /* dmfc2 is at the bottom of the table.  */
 /* dmtc2 is at the bottom of the table.  */
-{"dmfc3",   "t,G",      0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, 	I3      },
-{"dmfc3",   "t,G,H",    0x4c200000, 0xffe007f8, LCD|WR_t|RD_C3, 	I64     },
-{"dmtc3",   "t,G",      0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC,   I3      },
-{"dmtc3",   "t,G,H",    0x4ca00000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC,   I64     },
-{"dmul",    "d,v,t",	0,    (int) M_DMUL,	INSN_MACRO,		I3	},
-{"dmul",    "d,v,I",	0,    (int) M_DMUL_I,	INSN_MACRO,		I3	},
-{"dmulo",   "d,v,t",	0,    (int) M_DMULO,	INSN_MACRO,		I3	},
-{"dmulo",   "d,v,I",	0,    (int) M_DMULO_I,	INSN_MACRO,		I3	},
-{"dmulou",  "d,v,t",	0,    (int) M_DMULOU,	INSN_MACRO,		I3	},
-{"dmulou",  "d,v,I",	0,    (int) M_DMULOU_I,	INSN_MACRO,		I3	},
-{"dmult",   "s,t",      0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I3	},
-{"dmultu",  "s,t",      0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I3	},
-{"dneg",    "d,w",	0x0000002e, 0xffe007ff,	WR_d|RD_t,		I3	}, /* dsub 0 */
-{"dnegu",   "d,w",	0x0000002f, 0xffe007ff,	WR_d|RD_t,		I3	}, /* dsubu 0*/
-{"drem",    "z,s,t",    0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I3      },
-{"drem",    "d,v,t",	3,    (int) M_DREM_3,	INSN_MACRO,		I3	},
-{"drem",    "d,v,I",	3,    (int) M_DREM_3I,	INSN_MACRO,		I3	},
-{"dremu",   "z,s,t",    0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I3      },
-{"dremu",   "d,v,t",	3,    (int) M_DREMU_3,	INSN_MACRO,		I3	},
-{"dremu",   "d,v,I",	3,    (int) M_DREMU_3I,	INSN_MACRO,		I3	},
-{"dret",    "",		0x7000003e, 0xffffffff,	0,			N5	},
-{"drol",    "d,v,t",	0,    (int) M_DROL,	INSN_MACRO,		I3	},
-{"drol",    "d,v,I",	0,    (int) M_DROL_I,	INSN_MACRO,		I3	},
-{"dror",    "d,v,t",	0,    (int) M_DROR,	INSN_MACRO,		I3	},
-{"dror",    "d,v,I",	0,    (int) M_DROR_I,	INSN_MACRO,		I3	},
-{"dror",    "d,w,<",	0x0020003a, 0xffe0003f,	WR_d|RD_t,		N5|I65	},
-{"drorv",   "d,t,s",	0x00000056, 0xfc0007ff,	RD_t|RD_s|WR_d,		N5|I65	},
-{"dror32",  "d,w,<",	0x0020003e, 0xffe0003f,	WR_d|RD_t,		N5|I65	},
-{"drotl",   "d,v,t",	0,    (int) M_DROL,	INSN_MACRO,		I65	},
-{"drotl",   "d,v,I",	0,    (int) M_DROL_I,	INSN_MACRO,		I65	},
-{"drotr",   "d,v,t",	0,    (int) M_DROR,	INSN_MACRO,		I65	},
-{"drotr",   "d,v,I",	0,    (int) M_DROR_I,	INSN_MACRO,		I65	},
-{"drotrv",  "d,t,s",	0x00000056, 0xfc0007ff,	RD_t|RD_s|WR_d,		I65	},
-{"drotr32", "d,w,<",	0x0020003e, 0xffe0003f,	WR_d|RD_t,		I65	},
-{"dsbh",    "d,w",	0x7c0000a4, 0xffe007ff,	WR_d|RD_t,		I65	},
-{"dshd",    "d,w",	0x7c000164, 0xffe007ff,	WR_d|RD_t,		I65	},
-{"dsllv",   "d,t,s",	0x00000014, 0xfc0007ff,	WR_d|RD_t|RD_s,		I3	},
-{"dsll32",  "d,w,<",	0x0000003c, 0xffe0003f, WR_d|RD_t,		I3	},
-{"dsll",    "d,w,s",	0x00000014, 0xfc0007ff,	WR_d|RD_t|RD_s,		I3	}, /* dsllv */
-{"dsll",    "d,w,>",	0x0000003c, 0xffe0003f, WR_d|RD_t,		I3	}, /* dsll32 */
-{"dsll",    "d,w,<",	0x00000038, 0xffe0003f,	WR_d|RD_t,		I3	},
-{"dsrav",   "d,t,s",	0x00000017, 0xfc0007ff,	WR_d|RD_t|RD_s,		I3	},
-{"dsra32",  "d,w,<",	0x0000003f, 0xffe0003f, WR_d|RD_t,		I3	},
-{"dsra",    "d,w,s",	0x00000017, 0xfc0007ff,	WR_d|RD_t|RD_s,		I3	}, /* dsrav */
-{"dsra",    "d,w,>",	0x0000003f, 0xffe0003f, WR_d|RD_t,		I3	}, /* dsra32 */
-{"dsra",    "d,w,<",	0x0000003b, 0xffe0003f,	WR_d|RD_t,		I3	},
-{"dsrlv",   "d,t,s",	0x00000016, 0xfc0007ff,	WR_d|RD_t|RD_s,		I3	},
-{"dsrl32",  "d,w,<",	0x0000003e, 0xffe0003f, WR_d|RD_t,		I3	},
-{"dsrl",    "d,w,s",	0x00000016, 0xfc0007ff,	WR_d|RD_t|RD_s,		I3	}, /* dsrlv */
-{"dsrl",    "d,w,>",	0x0000003e, 0xffe0003f, WR_d|RD_t,		I3	}, /* dsrl32 */
-{"dsrl",    "d,w,<",	0x0000003a, 0xffe0003f,	WR_d|RD_t,		I3	},
-{"dsub",    "d,v,t",	0x0000002e, 0xfc0007ff,	WR_d|RD_s|RD_t,		I3	},
-{"dsub",    "d,v,I",	0,    (int) M_DSUB_I,	INSN_MACRO,		I3	},
-{"dsubu",   "d,v,t",	0x0000002f, 0xfc0007ff,	WR_d|RD_s|RD_t,		I3	},
-{"dsubu",   "d,v,I",	0,    (int) M_DSUBU_I,	INSN_MACRO,		I3	},
-{"ei",      "",		0x41606020, 0xffffffff,	WR_t|WR_C0,		I33	},
-{"ei",      "t",	0x41606020, 0xffe0ffff,	WR_t|WR_C0,		I33	},
-{"eret",    "",         0x42000018, 0xffffffff, 0,      		I3|I32	},
-{"ext",     "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s,    		I33	},
-{"floor.l.d", "D,S",	0x4620000b, 0xffff003f, WR_D|RD_S|FP_D,		I3	},
-{"floor.l.s", "D,S",	0x4600000b, 0xffff003f, WR_D|RD_S|FP_S,		I3	},
-{"floor.w.d", "D,S",	0x4620000f, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
-{"floor.w.s", "D,S",	0x4600000f, 0xffff003f, WR_D|RD_S|FP_S,		I2	},
-{"flushi",  "",		0xbc010000, 0xffffffff, 0,			L1	},
-{"flushd",  "",		0xbc020000, 0xffffffff, 0, 			L1	},
-{"flushid", "",		0xbc030000, 0xffffffff, 0, 			L1	},
-{"hibernate","",        0x42000023, 0xffffffff,	0, 			V1	},
-{"ins",     "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s,    		I33	},
-{"jr",      "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		I1	},
-{"jr.hb",   "s",	0x00000408, 0xfc1fffff,	UBD|RD_s,		I33	},
-{"j",       "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		I1	}, /* jr */
+/* dmfc3 is at the bottom of the table.  */
+/* dmtc3 is at the bottom of the table.  */
+{"dmul",    "d,v,t",	0,    (int) M_DMUL,	INSN_MACRO,		0,		I3	},
+{"dmul",    "d,v,I",	0,    (int) M_DMUL_I,	INSN_MACRO,		0,		I3	},
+{"dmulo",   "d,v,t",	0,    (int) M_DMULO,	INSN_MACRO,		0,		I3	},
+{"dmulo",   "d,v,I",	0,    (int) M_DMULO_I,	INSN_MACRO,		0,		I3	},
+{"dmulou",  "d,v,t",	0,    (int) M_DMULOU,	INSN_MACRO,		0,		I3	},
+{"dmulou",  "d,v,I",	0,    (int) M_DMULOU_I,	INSN_MACRO,		0,		I3	},
+{"dmult",   "s,t",      0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3	},
+{"dmultu",  "s,t",      0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3	},
+{"dneg",    "d,w",	0x0000002e, 0xffe007ff,	WR_d|RD_t,		0,		I3	}, /* dsub 0 */
+{"dnegu",   "d,w",	0x0000002f, 0xffe007ff,	WR_d|RD_t,		0,		I3	}, /* dsubu 0*/
+{"drem",    "z,s,t",    0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3      },
+{"drem",    "d,v,t",	3,    (int) M_DREM_3,	INSN_MACRO,		0,		I3	},
+{"drem",    "d,v,I",	3,    (int) M_DREM_3I,	INSN_MACRO,		0,		I3	},
+{"dremu",   "z,s,t",    0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I3      },
+{"dremu",   "d,v,t",	3,    (int) M_DREMU_3,	INSN_MACRO,		0,		I3	},
+{"dremu",   "d,v,I",	3,    (int) M_DREMU_3I,	INSN_MACRO,		0,		I3	},
+{"dret",    "",		0x7000003e, 0xffffffff,	0,			0,		N5	},
+{"drol",    "d,v,t",	0,    (int) M_DROL,	INSN_MACRO,		0,		I3	},
+{"drol",    "d,v,I",	0,    (int) M_DROL_I,	INSN_MACRO,		0,		I3	},
+{"dror",    "d,v,t",	0,    (int) M_DROR,	INSN_MACRO,		0,		I3	},
+{"dror",    "d,v,I",	0,    (int) M_DROR_I,	INSN_MACRO,		0,		I3	},
+{"dror",    "d,w,<",	0x0020003a, 0xffe0003f,	WR_d|RD_t,		0,		N5|I65	},
+{"drorv",   "d,t,s",	0x00000056, 0xfc0007ff,	RD_t|RD_s|WR_d,		0,		N5|I65	},
+{"dror32",  "d,w,<",	0x0020003e, 0xffe0003f,	WR_d|RD_t,		0,		N5|I65	},
+{"drotl",   "d,v,t",	0,    (int) M_DROL,	INSN_MACRO,		0,		I65	},
+{"drotl",   "d,v,I",	0,    (int) M_DROL_I,	INSN_MACRO,		0,		I65	},
+{"drotr",   "d,v,t",	0,    (int) M_DROR,	INSN_MACRO,		0,		I65	},
+{"drotr",   "d,v,I",	0,    (int) M_DROR_I,	INSN_MACRO,		0,		I65	},
+{"drotrv",  "d,t,s",	0x00000056, 0xfc0007ff,	RD_t|RD_s|WR_d,		0,		I65	},
+{"drotr32", "d,w,<",	0x0020003e, 0xffe0003f,	WR_d|RD_t,		0,		I65	},
+{"dsbh",    "d,w",	0x7c0000a4, 0xffe007ff,	WR_d|RD_t,		0,		I65	},
+{"dshd",    "d,w",	0x7c000164, 0xffe007ff,	WR_d|RD_t,		0,		I65	},
+{"dsllv",   "d,t,s",	0x00000014, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	},
+{"dsll32",  "d,w,<",	0x0000003c, 0xffe0003f, WR_d|RD_t,		0,		I3	},
+{"dsll",    "d,w,s",	0x00000014, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	}, /* dsllv */
+{"dsll",    "d,w,>",	0x0000003c, 0xffe0003f, WR_d|RD_t,		0,		I3	}, /* dsll32 */
+{"dsll",    "d,w,<",	0x00000038, 0xffe0003f,	WR_d|RD_t,		0,		I3	},
+{"dsrav",   "d,t,s",	0x00000017, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	},
+{"dsra32",  "d,w,<",	0x0000003f, 0xffe0003f, WR_d|RD_t,		0,		I3	},
+{"dsra",    "d,w,s",	0x00000017, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	}, /* dsrav */
+{"dsra",    "d,w,>",	0x0000003f, 0xffe0003f, WR_d|RD_t,		0,		I3	}, /* dsra32 */
+{"dsra",    "d,w,<",	0x0000003b, 0xffe0003f,	WR_d|RD_t,		0,		I3	},
+{"dsrlv",   "d,t,s",	0x00000016, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	},
+{"dsrl32",  "d,w,<",	0x0000003e, 0xffe0003f, WR_d|RD_t,		0,		I3	},
+{"dsrl",    "d,w,s",	0x00000016, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I3	}, /* dsrlv */
+{"dsrl",    "d,w,>",	0x0000003e, 0xffe0003f, WR_d|RD_t,		0,		I3	}, /* dsrl32 */
+{"dsrl",    "d,w,<",	0x0000003a, 0xffe0003f,	WR_d|RD_t,		0,		I3	},
+{"dsub",    "d,v,t",	0x0000002e, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I3	},
+{"dsub",    "d,v,I",	0,    (int) M_DSUB_I,	INSN_MACRO,		0,		I3	},
+{"dsubu",   "d,v,t",	0x0000002f, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I3	},
+{"dsubu",   "d,v,I",	0,    (int) M_DSUBU_I,	INSN_MACRO,		0,		I3	},
+{"dvpe",    "",		0x41600001, 0xffffffff, TRAP,			0,		MT32	},
+{"dvpe",    "t",	0x41600001, 0xffe0ffff, TRAP|WR_t,		0,		MT32	},
+{"ei",      "",		0x41606020, 0xffffffff,	WR_t|WR_C0,		0,		I33	},
+{"ei",      "t",	0x41606020, 0xffe0ffff,	WR_t|WR_C0,		0,		I33	},
+{"emt",     "",		0x41600be1, 0xffffffff, TRAP,			0,		MT32	},
+{"emt",     "t",	0x41600be1, 0xffe0ffff, TRAP|WR_t,		0,		MT32	},
+{"eret",    "",         0x42000018, 0xffffffff, 0,      		0,		I3|I32	},
+{"evpe",    "",		0x41600021, 0xffffffff, TRAP,			0,		MT32	},
+{"evpe",    "t",	0x41600021, 0xffe0ffff, TRAP|WR_t,		0,		MT32	},
+{"ext",     "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s,    		0,		I33	},
+{"floor.l.d", "D,S",	0x4620000b, 0xffff003f, WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"floor.l.s", "D,S",	0x4600000b, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"floor.w.d", "D,S",	0x4620000f, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"floor.w.s", "D,S",	0x4600000f, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
+{"hibernate","",        0x42000023, 0xffffffff,	0, 			0,		V1	},
+{"ins",     "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s,    		0,		I33	},
+{"jr",      "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		0,		I1	},
+/* jr.hb is officially MIPS{32,64}R2, but it works on R1 as jr with
+   the same hazard barrier effect.  */
+{"jr.hb",   "s",	0x00000408, 0xfc1fffff,	UBD|RD_s,		0,		I32	},
+{"j",       "s",	0x00000008, 0xfc1fffff,	UBD|RD_s,		0,		I1	}, /* jr */
 /* SVR4 PIC code requires special handling for j, so it must be a
    macro.  */
-{"j",	    "a",	0,     (int) M_J_A,	INSN_MACRO,		I1	},
+{"j",	    "a",	0,     (int) M_J_A,	INSN_MACRO,		0,		I1	},
 /* This form of j is used by the disassembler and internally by the
    assembler, but will never match user input (because the line above
    will match first).  */
-{"j",       "a",	0x08000000, 0xfc000000,	UBD,			I1	},
-{"jalr",    "s",	0x0000f809, 0xfc1fffff,	UBD|RD_s|WR_d,		I1	},
-{"jalr",    "d,s",	0x00000009, 0xfc1f07ff,	UBD|RD_s|WR_d,		I1	},
-{"jalr.hb", "s",	0x0000fc09, 0xfc1fffff,	UBD|RD_s|WR_d,		I33	},
-{"jalr.hb", "d,s",	0x00000409, 0xfc1f07ff,	UBD|RD_s|WR_d,		I33	},
+{"j",       "a",	0x08000000, 0xfc000000,	UBD,			0,		I1	},
+{"jalr",    "s",	0x0000f809, 0xfc1fffff,	UBD|RD_s|WR_d,		0,		I1	},
+{"jalr",    "d,s",	0x00000009, 0xfc1f07ff,	UBD|RD_s|WR_d,		0,		I1	},
+/* jalr.hb is officially MIPS{32,64}R2, but it works on R1 as jalr
+   with the same hazard barrier effect.  */
+{"jalr.hb", "s",	0x0000fc09, 0xfc1fffff,	UBD|RD_s|WR_d,		0,		I32	},
+{"jalr.hb", "d,s",	0x00000409, 0xfc1f07ff,	UBD|RD_s|WR_d,		0,		I32	},
 /* SVR4 PIC code requires special handling for jal, so it must be a
    macro.  */
-{"jal",     "d,s",	0,     (int) M_JAL_2,	INSN_MACRO,		I1	},
-{"jal",     "s",	0,     (int) M_JAL_1,	INSN_MACRO,		I1	},
-{"jal",     "a",	0,     (int) M_JAL_A,	INSN_MACRO,		I1	},
+{"jal",     "d,s",	0,     (int) M_JAL_2,	INSN_MACRO,		0,		I1	},
+{"jal",     "s",	0,     (int) M_JAL_1,	INSN_MACRO,		0,		I1	},
+{"jal",     "a",	0,     (int) M_JAL_A,	INSN_MACRO,		0,		I1	},
 /* This form of jal is used by the disassembler and internally by the
    assembler, but will never match user input (because the line above
    will match first).  */
-{"jal",     "a",	0x0c000000, 0xfc000000,	UBD|WR_31,		I1	},
-{"jalx",    "a",	0x74000000, 0xfc000000, UBD|WR_31,		I16     },
-{"la",      "t,A(b)",	0,    (int) M_LA_AB,	INSN_MACRO,		I1	},
-{"lb",      "t,o(b)",	0x80000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
-{"lb",      "t,A(b)",	0,    (int) M_LB_AB,	INSN_MACRO,		I1	},
-{"lbu",     "t,o(b)",	0x90000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
-{"lbu",     "t,A(b)",	0,    (int) M_LBU_AB,	INSN_MACRO,		I1	},
-{"lca",     "t,A(b)",	0,    (int) M_LCA_AB,	INSN_MACRO,		I1	},
-{"ld",	    "t,o(b)",   0xdc000000, 0xfc000000, WR_t|RD_b,		I3	},
-{"ld",      "t,o(b)",	0,    (int) M_LD_OB,	INSN_MACRO,		I1	},
-{"ld",      "t,A(b)",	0,    (int) M_LD_AB,	INSN_MACRO,		I1	},
-{"ldc1",    "T,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	I2	},
-{"ldc1",    "E,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	I2	},
-{"ldc1",    "T,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		I2	},
-{"ldc1",    "E,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		I2	},
-{"l.d",     "T,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	I2	}, /* ldc1 */
-{"l.d",     "T,o(b)",	0,    (int) M_L_DOB,	INSN_MACRO,		I1	},
-{"l.d",     "T,A(b)",	0,    (int) M_L_DAB,	INSN_MACRO,		I1	},
-{"ldc2",    "E,o(b)",	0xd8000000, 0xfc000000, CLD|RD_b|WR_CC,		I2	},
-{"ldc2",    "E,A(b)",	0,    (int) M_LDC2_AB,	INSN_MACRO,		I2	},
-{"ldc3",    "E,o(b)",	0xdc000000, 0xfc000000, CLD|RD_b|WR_CC,		I2	},
-{"ldc3",    "E,A(b)",	0,    (int) M_LDC3_AB,	INSN_MACRO,		I2	},
-{"ldl",	    "t,o(b)",	0x68000000, 0xfc000000, LDD|WR_t|RD_b,		I3	},
-{"ldl",	    "t,A(b)",	0,    (int) M_LDL_AB,	INSN_MACRO,		I3	},
-{"ldr",	    "t,o(b)",	0x6c000000, 0xfc000000, LDD|WR_t|RD_b,		I3	},
-{"ldr",     "t,A(b)",	0,    (int) M_LDR_AB,	INSN_MACRO,		I3	},
-{"ldxc1",   "D,t(b)",	0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b,	I4	},
-{"lh",      "t,o(b)",	0x84000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
-{"lh",      "t,A(b)",	0,    (int) M_LH_AB,	INSN_MACRO,		I1	},
-{"lhu",     "t,o(b)",	0x94000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
-{"lhu",     "t,A(b)",	0,    (int) M_LHU_AB,	INSN_MACRO,		I1	},
+{"jal",     "a",	0x0c000000, 0xfc000000,	UBD|WR_31,		0,		I1	},
+{"jalx",    "a",	0x74000000, 0xfc000000, UBD|WR_31,		0,		I16     },
+{"la",      "t,A(b)",	0,    (int) M_LA_AB,	INSN_MACRO,		0,		I1	},
+{"lb",      "t,o(b)",	0x80000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lb",      "t,A(b)",	0,    (int) M_LB_AB,	INSN_MACRO,		0,		I1	},
+{"lbu",     "t,o(b)",	0x90000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lbu",     "t,A(b)",	0,    (int) M_LBU_AB,	INSN_MACRO,		0,		I1	},
+{"lca",     "t,A(b)",	0,    (int) M_LCA_AB,	INSN_MACRO,		0,		I1	},
+{"ld",	    "t,o(b)",   0xdc000000, 0xfc000000, WR_t|RD_b,		0,		I3	},
+{"ld",      "t,o(b)",	0,    (int) M_LD_OB,	INSN_MACRO,		0,		I1	},
+{"ld",      "t,A(b)",	0,    (int) M_LD_AB,	INSN_MACRO,		0,		I1	},
+{"ldc1",    "T,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	0,		I2	},
+{"ldc1",    "E,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	0,		I2	},
+{"ldc1",    "T,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		0,		I2	},
+{"ldc1",    "E,A(b)",	0,    (int) M_LDC1_AB,	INSN_MACRO,		0,		I2	},
+{"l.d",     "T,o(b)",	0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D,	0,		I2	}, /* ldc1 */
+{"l.d",     "T,o(b)",	0,    (int) M_L_DOB,	INSN_MACRO,		0,		I1	},
+{"l.d",     "T,A(b)",	0,    (int) M_L_DAB,	INSN_MACRO,		0,		I1	},
+{"ldc2",    "E,o(b)",	0xd8000000, 0xfc000000, CLD|RD_b|WR_CC,		0,		I2	},
+{"ldc2",    "E,A(b)",	0,    (int) M_LDC2_AB,	INSN_MACRO,		0,		I2	},
+{"ldc3",    "E,o(b)",	0xdc000000, 0xfc000000, CLD|RD_b|WR_CC,		0,		I2	},
+{"ldc3",    "E,A(b)",	0,    (int) M_LDC3_AB,	INSN_MACRO,		0,		I2	},
+{"ldl",	    "t,o(b)",	0x68000000, 0xfc000000, LDD|WR_t|RD_b,		0,		I3	},
+{"ldl",	    "t,A(b)",	0,    (int) M_LDL_AB,	INSN_MACRO,		0,		I3	},
+{"ldr",	    "t,o(b)",	0x6c000000, 0xfc000000, LDD|WR_t|RD_b,		0,		I3	},
+{"ldr",     "t,A(b)",	0,    (int) M_LDR_AB,	INSN_MACRO,		0,		I3	},
+{"ldxc1",   "D,t(b)",	0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0,		I4|I33	},
+{"lh",      "t,o(b)",	0x84000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lh",      "t,A(b)",	0,    (int) M_LH_AB,	INSN_MACRO,		0,		I1	},
+{"lhu",     "t,o(b)",	0x94000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lhu",     "t,A(b)",	0,    (int) M_LHU_AB,	INSN_MACRO,		0,		I1	},
 /* li is at the start of the table.  */
-{"li.d",    "t,F",	0,    (int) M_LI_D,	INSN_MACRO,		I1	},
-{"li.d",    "T,L",	0,    (int) M_LI_DD,	INSN_MACRO,		I1	},
-{"li.s",    "t,f",	0,    (int) M_LI_S,	INSN_MACRO,		I1	},
-{"li.s",    "T,l",	0,    (int) M_LI_SS,	INSN_MACRO,		I1	},
-{"ll",	    "t,o(b)",	0xc0000000, 0xfc000000, LDD|RD_b|WR_t,		I2	},
-{"ll",	    "t,A(b)",	0,    (int) M_LL_AB,	INSN_MACRO,		I2	},
-{"lld",	    "t,o(b)",	0xd0000000, 0xfc000000, LDD|RD_b|WR_t,		I3	},
-{"lld",     "t,A(b)",	0,    (int) M_LLD_AB,	INSN_MACRO,		I3	},
-{"lui",     "t,u",	0x3c000000, 0xffe00000,	WR_t,			I1	},
-{"luxc1",   "D,t(b)",	0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b,	I5|N55	},
-{"lw",      "t,o(b)",	0x8c000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
-{"lw",      "t,A(b)",	0,    (int) M_LW_AB,	INSN_MACRO,		I1	},
-{"lwc0",    "E,o(b)",	0xc0000000, 0xfc000000,	CLD|RD_b|WR_CC,		I1	},
-{"lwc0",    "E,A(b)",	0,    (int) M_LWC0_AB,	INSN_MACRO,		I1	},
-{"lwc1",    "T,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	I1	},
-{"lwc1",    "E,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	I1	},
-{"lwc1",    "T,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		I1	},
-{"lwc1",    "E,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		I1	},
-{"l.s",     "T,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	I1	}, /* lwc1 */
-{"l.s",     "T,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		I1	},
-{"lwc2",    "E,o(b)",	0xc8000000, 0xfc000000,	CLD|RD_b|WR_CC,		I1	},
-{"lwc2",    "E,A(b)",	0,    (int) M_LWC2_AB,	INSN_MACRO,		I1	},
-{"lwc3",    "E,o(b)",	0xcc000000, 0xfc000000,	CLD|RD_b|WR_CC,		I1	},
-{"lwc3",    "E,A(b)",	0,    (int) M_LWC3_AB,	INSN_MACRO,		I1	},
-{"lwl",     "t,o(b)",	0x88000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
-{"lwl",     "t,A(b)",	0,    (int) M_LWL_AB,	INSN_MACRO,		I1	},
-{"lcache",  "t,o(b)",	0x88000000, 0xfc000000,	LDD|RD_b|WR_t,		I2	}, /* same */
-{"lcache",  "t,A(b)",	0,    (int) M_LWL_AB,	INSN_MACRO,		I2	}, /* as lwl */
-{"lwr",     "t,o(b)",	0x98000000, 0xfc000000,	LDD|RD_b|WR_t,		I1	},
-{"lwr",     "t,A(b)",	0,    (int) M_LWR_AB,	INSN_MACRO,		I1	},
-{"flush",   "t,o(b)",	0x98000000, 0xfc000000,	LDD|RD_b|WR_t,		I2	}, /* same */
-{"flush",   "t,A(b)",	0,    (int) M_LWR_AB,	INSN_MACRO,		I2	}, /* as lwr */
-{"lwu",     "t,o(b)",	0x9c000000, 0xfc000000,	LDD|RD_b|WR_t,		I3	},
-{"lwu",     "t,A(b)",	0,    (int) M_LWU_AB,	INSN_MACRO,		I3	},
-{"lwxc1",   "D,t(b)",	0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b,	I4	},
-{"macc",    "d,s,t",	0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412    },
-{"macc",    "d,s,t",	0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	N5      },
-{"maccs",   "d,s,t",	0x00000428, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, N412    },
-{"macchi",  "d,s,t",	0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412    },
-{"macchi",  "d,s,t",	0x00000358, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5      },
-{"macchis", "d,s,t",	0x00000628, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, N412    },
-{"macchiu", "d,s,t",	0x00000268, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, N412    },
-{"macchiu", "d,s,t",	0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	N5      },
-{"macchius","d,s,t",	0x00000668, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, N412    },
-{"maccu",   "d,s,t",	0x00000068, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, N412    },
-{"maccu",   "d,s,t",	0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	N5      },
-{"maccus",  "d,s,t",	0x00000468, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, N412    },
-{"mad",     "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     P3      },
-{"madu",    "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     P3      },
-{"madd.d",  "D,R,S,T",	0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D,    I4	},
-{"madd.s",  "D,R,S,T",	0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S,    I4	},
-{"madd.ps", "D,R,S,T",	0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D,    I5	},
-{"madd",    "s,t",      0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO,           L1 },
-{"madd",    "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          I32|N55},
-{"madd",    "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M,      G1 },
-{"madd",    "d,s,t",    0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 },
-{"maddu",   "s,t",      0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO,           L1 },
-{"maddu",   "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          I32|N55},
-{"maddu",   "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M,      G1	},
-{"maddu",   "d,s,t",    0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1	},
-{"madd16",  "s,t",      0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO,	N411    },
-{"max.ob",  "X,Y,Q",	0x78000007, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"max.ob",  "D,S,T",	0x4ac00007, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"max.ob",  "D,S,T[e]",	0x48000007, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"max.ob",  "D,S,k",	0x4bc00007, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"max.qh",  "X,Y,Q",	0x78200007, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"mfpc",    "t,P",	0x4000c801, 0xffe0ffc1,	LCD|WR_t|RD_C0,		M1|N5	},
-{"mfps",    "t,P",	0x4000c800, 0xffe0ffc1,	LCD|WR_t|RD_C0,		M1|N5	},
-{"mfc0",    "t,G",	0x40000000, 0xffe007ff,	LCD|WR_t|RD_C0,		I1	},
-{"mfc0",    "t,+D",     0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	I32     },
-{"mfc0",    "t,G,H",    0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	I32     },
-{"mfc1",    "t,S",	0x44000000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	I1	},
-{"mfc1",    "t,G",	0x44000000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	I1	},
-{"mfhc1",   "t,S",	0x44600000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	I33	},
-{"mfhc1",   "t,G",	0x44600000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	I33	},
+{"li.d",    "t,F",	0,    (int) M_LI_D,	INSN_MACRO,		0,		I1	},
+{"li.d",    "T,L",	0,    (int) M_LI_DD,	INSN_MACRO,		0,		I1	},
+{"li.s",    "t,f",	0,    (int) M_LI_S,	INSN_MACRO,		0,		I1	},
+{"li.s",    "T,l",	0,    (int) M_LI_SS,	INSN_MACRO,		0,		I1	},
+{"ll",	    "t,o(b)",	0xc0000000, 0xfc000000, LDD|RD_b|WR_t,		0,		I2	},
+{"ll",	    "t,A(b)",	0,    (int) M_LL_AB,	INSN_MACRO,		0,		I2	},
+{"lld",	    "t,o(b)",	0xd0000000, 0xfc000000, LDD|RD_b|WR_t,		0,		I3	},
+{"lld",     "t,A(b)",	0,    (int) M_LLD_AB,	INSN_MACRO,		0,		I3	},
+{"lui",     "t,u",	0x3c000000, 0xffe00000,	WR_t,			0,		I1	},
+{"luxc1",   "D,t(b)",	0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0,		I5|I33|N55},
+{"lw",      "t,o(b)",	0x8c000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lw",      "t,A(b)",	0,    (int) M_LW_AB,	INSN_MACRO,		0,		I1	},
+{"lwc0",    "E,o(b)",	0xc0000000, 0xfc000000,	CLD|RD_b|WR_CC,		0,		I1	},
+{"lwc0",    "E,A(b)",	0,    (int) M_LWC0_AB,	INSN_MACRO,		0,		I1	},
+{"lwc1",    "T,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	0,		I1	},
+{"lwc1",    "E,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	0,		I1	},
+{"lwc1",    "T,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		0,		I1	},
+{"lwc1",    "E,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		0,		I1	},
+{"l.s",     "T,o(b)",	0xc4000000, 0xfc000000,	CLD|RD_b|WR_T|FP_S,	0,		I1	}, /* lwc1 */
+{"l.s",     "T,A(b)",	0,    (int) M_LWC1_AB,	INSN_MACRO,		0,		I1	},
+{"lwc2",    "E,o(b)",	0xc8000000, 0xfc000000,	CLD|RD_b|WR_CC,		0,		I1	},
+{"lwc2",    "E,A(b)",	0,    (int) M_LWC2_AB,	INSN_MACRO,		0,		I1	},
+{"lwc3",    "E,o(b)",	0xcc000000, 0xfc000000,	CLD|RD_b|WR_CC,		0,		I1	},
+{"lwc3",    "E,A(b)",	0,    (int) M_LWC3_AB,	INSN_MACRO,		0,		I1	},
+{"lwl",     "t,o(b)",	0x88000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lwl",     "t,A(b)",	0,    (int) M_LWL_AB,	INSN_MACRO,		0,		I1	},
+{"lcache",  "t,o(b)",	0x88000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I2	}, /* same */
+{"lcache",  "t,A(b)",	0,    (int) M_LWL_AB,	INSN_MACRO,		0,		I2	}, /* as lwl */
+{"lwr",     "t,o(b)",	0x98000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I1	},
+{"lwr",     "t,A(b)",	0,    (int) M_LWR_AB,	INSN_MACRO,		0,		I1	},
+{"flush",   "t,o(b)",	0x98000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I2	}, /* same */
+{"flush",   "t,A(b)",	0,    (int) M_LWR_AB,	INSN_MACRO,		0,		I2	}, /* as lwr */
+{"fork",    "d,s,t",	0x7c000008, 0xfc0007ff, TRAP|WR_d|RD_s|RD_t,	0,		MT32	},
+{"lwu",     "t,o(b)",	0x9c000000, 0xfc000000,	LDD|RD_b|WR_t,		0,		I3	},
+{"lwu",     "t,A(b)",	0,    (int) M_LWU_AB,	INSN_MACRO,		0,		I3	},
+{"lwxc1",   "D,t(b)",	0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b|FP_D, 0,		I4|I33	},
+{"lwxs",    "d,t(b)",	0x70000088, 0xfc0007ff,	LDD|RD_b|RD_t|WR_d,	0,		SMT	},
+{"macc",    "d,s,t",	0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macc",    "d,s,t",	0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	0,		N5      },
+{"maccs",   "d,s,t",	0x00000428, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macchi",  "d,s,t",	0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macchi",  "d,s,t",	0x00000358, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5      },
+{"macchis", "d,s,t",	0x00000628, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macchiu", "d,s,t",	0x00000268, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"macchiu", "d,s,t",	0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	0,		N5      },
+{"macchius","d,s,t",	0x00000668, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"maccu",   "d,s,t",	0x00000068, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"maccu",   "d,s,t",	0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d,	0,		N5      },
+{"maccus",  "d,s,t",	0x00000468, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d, 0,		N412    },
+{"mad",     "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     0,		P3      },
+{"madu",    "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     0,		P3      },
+{"madd.d",  "D,R,S,T",	0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D,    0,		I4|I33	},
+{"madd.s",  "D,R,S,T",	0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S,    0,		I4|I33	},
+{"madd.ps", "D,R,S,T",	0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D,    0,		I5|I33	},
+{"madd",    "s,t",      0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO,           0,		L1	},
+{"madd",    "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          0,		I32|N55	},
+{"madd",    "s,t",      0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M,      0,		G1	},
+{"madd",    "7,s,t",	0x70000000, 0xfc00e7ff, MOD_a|RD_s|RD_t,             0,         D33	},
+{"madd",    "d,s,t",    0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0,		G1	},
+{"maddp",   "s,t",      0x70000441, 0xfc00ffff,	RD_s|RD_t|MOD_HILO,	     0,		SMT	},
+{"maddu",   "s,t",      0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO,           0,		L1	},
+{"maddu",   "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO,          0,		I32|N55	},
+{"maddu",   "s,t",      0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M,      0,		G1	},
+{"maddu",   "7,s,t",	0x70000001, 0xfc00e7ff, MOD_a|RD_s|RD_t,             0,         D33	},
+{"maddu",   "d,s,t",    0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0,		G1	},
+{"madd16",  "s,t",      0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO,	0,		N411    },
+{"max.ob",  "X,Y,Q",	0x78000007, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"max.ob",  "D,S,T",	0x4ac00007, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"max.ob",  "D,S,T[e]",	0x48000007, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"max.ob",  "D,S,k",	0x4bc00007, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"max.qh",  "X,Y,Q",	0x78200007, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"mfpc",    "t,P",	0x4000c801, 0xffe0ffc1,	LCD|WR_t|RD_C0,		0,		M1|N5	},
+{"mfps",    "t,P",	0x4000c800, 0xffe0ffc1,	LCD|WR_t|RD_C0,		0,		M1|N5	},
+{"mftacx",  "d",	0x41020021, 0xffff07ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftacx",  "d,*",	0x41020021, 0xfff307ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftc0",   "d,+t",	0x41000000, 0xffe007ff, TRAP|LCD|WR_d|RD_C0,	0,		MT32	},
+{"mftc0",   "d,+T",	0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0,	0,		MT32	},
+{"mftc0",   "d,E,H",	0x41000000, 0xffe007f8, TRAP|LCD|WR_d|RD_C0,	0,		MT32	},
+{"mftc1",   "d,T",	0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0,		MT32	},
+{"mftc1",   "d,E",	0x41000022, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_S, 0,		MT32	},
+{"mftc2",   "d,E",	0x41000024, 0xffe007ff, TRAP|LCD|WR_d|RD_C2,	0,		MT32	},
+{"mftdsp",  "d",	0x41100021, 0xffff07ff, TRAP|WR_d,		0,		MT32	},
+{"mftgpr",  "d,t",	0x41000020, 0xffe007ff, TRAP|WR_d|RD_t,		0,		MT32	},
+{"mfthc1",  "d,T",	0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0,		MT32	},
+{"mfthc1",  "d,E",	0x41000032, 0xffe007ff, TRAP|LCD|WR_d|RD_T|FP_D, 0,		MT32	},
+{"mfthc2",  "d,E",	0x41000034, 0xffe007ff, TRAP|LCD|WR_d|RD_C2,	0,		MT32	},
+{"mfthi",   "d",	0x41010021, 0xffff07ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mfthi",   "d,*",	0x41010021, 0xfff307ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftlo",   "d",	0x41000021, 0xffff07ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftlo",   "d,*",	0x41000021, 0xfff307ff, TRAP|WR_d|RD_a,		0,		MT32	},
+{"mftr",    "d,t,!,H,$", 0x41000000, 0xffe007c8, TRAP|WR_d,		0,		MT32	},
+{"mfc0",    "t,G",	0x40000000, 0xffe007ff,	LCD|WR_t|RD_C0,		0,		I1	},
+{"mfc0",    "t,+D",     0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	0,		I32     },
+{"mfc0",    "t,G,H",    0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, 	0,		I32     },
+{"mfc1",    "t,S",	0x44000000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	0,		I1	},
+{"mfc1",    "t,G",	0x44000000, 0xffe007ff,	LCD|WR_t|RD_S|FP_S,	0,		I1	},
+{"mfhc1",   "t,S",	0x44600000, 0xffe007ff,	LCD|WR_t|RD_S|FP_D,	0,		I33	},
+{"mfhc1",   "t,G",	0x44600000, 0xffe007ff,	LCD|WR_t|RD_S|FP_D,	0,		I33	},
 /* mfc2 is at the bottom of the table.  */
 /* mfhc2 is at the bottom of the table.  */
-{"mfc3",    "t,G",	0x4c000000, 0xffe007ff,	LCD|WR_t|RD_C3,		I1	},
-{"mfc3",    "t,G,H",    0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 	I32     },
-{"mfdr",    "t,G",	0x7000003d, 0xffe007ff,	LCD|WR_t|RD_C0,		N5      },
-{"mfhi",    "d",	0x00000010, 0xffff07ff,	WR_d|RD_HI,		I1	},
-{"mflo",    "d",	0x00000012, 0xffff07ff,	WR_d|RD_LO,		I1	},
-{"min.ob",  "X,Y,Q",	0x78000006, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"min.ob",  "D,S,T",	0x4ac00006, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"min.ob",  "D,S,T[e]",	0x48000006, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"min.ob",  "D,S,k",	0x4bc00006, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"min.qh",  "X,Y,Q",	0x78200006, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"mov.d",   "D,S",	0x46200006, 0xffff003f,	WR_D|RD_S|FP_D,		I1	},
-{"mov.s",   "D,S",	0x46000006, 0xffff003f,	WR_D|RD_S|FP_S,		I1	},
-{"mov.ps",  "D,S",	0x46c00006, 0xffff003f,	WR_D|RD_S|FP_D,		I5	},
-{"movf",    "d,s,N",    0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_D|FP_S, I4|I32},
-{"movf.d",  "D,S,N",    0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   I4|I32	},
-{"movf.l",  "D,S,N",	0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	MX|SB1	},
-{"movf.l",  "X,Y,N",	0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	MX|SB1	},
-{"movf.s",  "D,S,N",    0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S,   I4|I32	},
-{"movf.ps", "D,S,N",	0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	I5	},
-{"movn",    "d,v,t",    0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 	I4|I32	},
-{"ffc",     "d,v",	0x0000000b, 0xfc1f07ff,	WR_d|RD_s,		L1	},
-{"movn.d",  "D,S,t",    0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    I4|I32	},
-{"movn.l",  "D,S,t",    0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    MX|SB1	},
-{"movn.l",  "X,Y,t",    0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    MX|SB1	},
-{"movn.s",  "D,S,t",    0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S,    I4|I32	},
-{"movn.ps", "D,S,t",    0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    I5	},
-{"movt",    "d,s,N",    0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC,        I4|I32	},
-{"movt.d",  "D,S,N",    0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   I4|I32	},
-{"movt.l",  "D,S,N",    0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   MX|SB1	},
-{"movt.l",  "X,Y,N",    0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   MX|SB1	},
-{"movt.s",  "D,S,N",    0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S,   I4|I32	},
-{"movt.ps", "D,S,N",	0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	I5	},
-{"movz",    "d,v,t",    0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 	I4|I32	},
-{"ffs",     "d,v",	0x0000000a, 0xfc1f07ff,	WR_d|RD_s,		L1	},
-{"movz.d",  "D,S,t",    0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    I4|I32	},
-{"movz.l",  "D,S,t",    0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    MX|SB1	},
-{"movz.l",  "X,Y,t",    0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    MX|SB1	},
-{"movz.s",  "D,S,t",    0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S,    I4|I32	},
-{"movz.ps", "D,S,t",    0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    I5	},
-{"msac",    "d,s,t",	0x000001d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"msacu",   "d,s,t",	0x000001d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"msachi",  "d,s,t",	0x000003d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"msachiu", "d,s,t",	0x000003d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
+/* mfc3 is at the bottom of the table.  */
+{"mfdr",    "t,G",	0x7000003d, 0xffe007ff,	LCD|WR_t|RD_C0,		0,		N5      },
+{"mfhi",    "d",	0x00000010, 0xffff07ff,	WR_d|RD_HI,		0,		I1	},
+{"mfhi",    "d,9",	0x00000010, 0xff9f07ff, WR_d|RD_HI,		0,		D32	},
+{"mflo",    "d",	0x00000012, 0xffff07ff,	WR_d|RD_LO,		0,		I1	},
+{"mflo",    "d,9",	0x00000012, 0xff9f07ff, WR_d|RD_LO,		0,		D32	},
+{"mflhxu",  "d",	0x00000052, 0xffff07ff,	WR_d|MOD_HILO,		0,		SMT	},
+{"min.ob",  "X,Y,Q",	0x78000006, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"min.ob",  "D,S,T",	0x4ac00006, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"min.ob",  "D,S,T[e]",	0x48000006, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"min.ob",  "D,S,k",	0x4bc00006, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"min.qh",  "X,Y,Q",	0x78200006, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"mov.d",   "D,S",	0x46200006, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I1	},
+{"mov.s",   "D,S",	0x46000006, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"mov.ps",  "D,S",	0x46c00006, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I5|I33	},
+{"movf",    "d,s,N",    0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0,		I4|I32  },
+{"movf.d",  "D,S,N",    0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   0,		I4|I32	},
+{"movf.l",  "D,S,N",	0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	0,		MX|SB1	},
+{"movf.l",  "X,Y,N",	0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	0,		MX|SB1	},
+{"movf.s",  "D,S,N",    0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S,   0,		I4|I32	},
+{"movf.ps", "D,S,N",	0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	0,		I5|I33	},
+{"movn",    "d,v,t",    0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, 	0,		I4|I32	},
+{"ffc",     "d,v",	0x0000000b, 0xfc1f07ff,	WR_d|RD_s,		0,		L1	},
+{"movn.d",  "D,S,t",    0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		I4|I32	},
+{"movn.l",  "D,S,t",    0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		MX|SB1	},
+{"movn.l",  "X,Y,t",    0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		MX|SB1	},
+{"movn.s",  "D,S,t",    0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S,    0,		I4|I32	},
+{"movn.ps", "D,S,t",    0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		I5|I33	},
+{"movt",    "d,s,N",    0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_S|FP_D, 0,		I4|I32	},
+{"movt.d",  "D,S,N",    0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   0,		I4|I32	},
+{"movt.l",  "D,S,N",    0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   0,		MX|SB1	},
+{"movt.l",  "X,Y,N",    0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,   0,		MX|SB1	},
+{"movt.s",  "D,S,N",    0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S,   0,		I4|I32	},
+{"movt.ps", "D,S,N",	0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D,	0,		I5|I33	},
+{"movz",    "d,v,t",    0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, 	0,		I4|I32	},
+{"ffs",     "d,v",	0x0000000a, 0xfc1f07ff,	WR_d|RD_s,		0,		L1	},
+{"movz.d",  "D,S,t",    0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		I4|I32	},
+{"movz.l",  "D,S,t",    0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		MX|SB1	},
+{"movz.l",  "X,Y,t",    0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		MX|SB1	},
+{"movz.s",  "D,S,t",    0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S,    0,		I4|I32	},
+{"movz.ps", "D,S,t",    0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D,    0,		I5|I33	},
+{"msac",    "d,s,t",	0x000001d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"msacu",   "d,s,t",	0x000001d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"msachi",  "d,s,t",	0x000003d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"msachiu", "d,s,t",	0x000003d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
 /* move is at the top of the table.  */
-{"msgn.qh", "X,Y,Q",	0x78200000, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"msub.d",  "D,R,S,T",	0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4	},
-{"msub.s",  "D,R,S,T",	0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4	},
-{"msub.ps", "D,R,S,T",	0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5	},
-{"msub",    "s,t",      0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,	L1    	},
-{"msub",    "s,t",      0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     I32|N55 },
-{"msubu",   "s,t",      0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,	L1	},
-{"msubu",   "s,t",      0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     I32|N55	},
-{"mtpc",    "t,P",	0x4080c801, 0xffe0ffc1,	COD|RD_t|WR_C0,		M1|N5	},
-{"mtps",    "t,P",	0x4080c800, 0xffe0ffc1,	COD|RD_t|WR_C0,		M1|N5	},
-{"mtc0",    "t,G",	0x40800000, 0xffe007ff,	COD|RD_t|WR_C0|WR_CC,	I1	},
-{"mtc0",    "t,+D",     0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I32     },
-{"mtc0",    "t,G,H",    0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   I32     },
-{"mtc1",    "t,S",	0x44800000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	I1	},
-{"mtc1",    "t,G",	0x44800000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	I1	},
-{"mthc1",   "t,S",	0x44e00000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	I33	},
-{"mthc1",   "t,G",	0x44e00000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	I33	},
+{"msgn.qh", "X,Y,Q",	0x78200000, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"msub.d",  "D,R,S,T",	0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I4|I33	},
+{"msub.s",  "D,R,S,T",	0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0,		I4|I33	},
+{"msub.ps", "D,R,S,T",	0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I5|I33	},
+{"msub",    "s,t",      0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO,	0,		L1    	},
+{"msub",    "s,t",      0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     0,		I32|N55 },
+{"msub",    "7,s,t",	0x70000004, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"msubu",   "s,t",      0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO,	0,		L1	},
+{"msubu",   "s,t",      0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO,     0,		I32|N55	},
+{"msubu",   "7,s,t",	0x70000005, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"mtpc",    "t,P",	0x4080c801, 0xffe0ffc1,	COD|RD_t|WR_C0,		0,		M1|N5	},
+{"mtps",    "t,P",	0x4080c800, 0xffe0ffc1,	COD|RD_t|WR_C0,		0,		M1|N5	},
+{"mtc0",    "t,G",	0x40800000, 0xffe007ff,	COD|RD_t|WR_C0|WR_CC,	0,		I1	},
+{"mtc0",    "t,+D",     0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   0,		I32     },
+{"mtc0",    "t,G,H",    0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC,   0,		I32     },
+{"mtc1",    "t,S",	0x44800000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	0,		I1	},
+{"mtc1",    "t,G",	0x44800000, 0xffe007ff,	COD|RD_t|WR_S|FP_S,	0,		I1	},
+{"mthc1",   "t,S",	0x44e00000, 0xffe007ff,	COD|RD_t|WR_S|FP_D,	0,		I33	},
+{"mthc1",   "t,G",	0x44e00000, 0xffe007ff,	COD|RD_t|WR_S|FP_D,	0,		I33	},
 /* mtc2 is at the bottom of the table.  */
 /* mthc2 is at the bottom of the table.  */
-{"mtc3",    "t,G",	0x4c800000, 0xffe007ff,	COD|RD_t|WR_C3|WR_CC,	I1	},
-{"mtc3",    "t,G,H",    0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC,   I32     },
-{"mtdr",    "t,G",	0x7080003d, 0xffe007ff,	COD|RD_t|WR_C0,		N5	},
-{"mthi",    "s",	0x00000011, 0xfc1fffff,	RD_s|WR_HI,		I1	},
-{"mtlo",    "s",	0x00000013, 0xfc1fffff,	RD_s|WR_LO,		I1	},
-{"mul.d",   "D,V,T",	0x46200002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I1	},
-{"mul.s",   "D,V,T",	0x46000002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	I1	},
-{"mul.ob",  "X,Y,Q",	0x78000030, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"mul.ob",  "D,S,T",	0x4ac00030, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"mul.ob",  "D,S,T[e]",	0x48000030, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"mul.ob",  "D,S,k",	0x4bc00030, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"mul.ps",  "D,V,T",	0x46c00002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
-{"mul.qh",  "X,Y,Q",	0x78200030, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"mul",     "d,v,t",    0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, I32|P3|N55},
-{"mul",     "d,s,t",	0x00000058, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N54	},
-{"mul",     "d,v,t",	0,    (int) M_MUL,	INSN_MACRO,		I1	},
-{"mul",     "d,v,I",	0,    (int) M_MUL_I,	INSN_MACRO,		I1	},
-{"mula.ob", "Y,Q",	0x78000033, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"mula.ob", "S,T",	0x4ac00033, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mula.ob", "S,T[e]",	0x48000033, 0xfe2007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mula.ob", "S,k",	0x4bc00033, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mula.qh", "Y,Q",	0x78200033, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"mulhi",   "d,s,t",	0x00000258, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"mulhiu",  "d,s,t",	0x00000259, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"mull.ob", "Y,Q",	0x78000433, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D, MX|SB1	},
-{"mull.ob", "S,T",	0x4ac00433, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mull.ob", "S,T[e]",	0x48000433, 0xfe2007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mull.ob", "S,k",	0x4bc00433, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mull.qh", "Y,Q",	0x78200433, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"mulo",    "d,v,t",	0,    (int) M_MULO,	INSN_MACRO,		I1	},
-{"mulo",    "d,v,I",	0,    (int) M_MULO_I,	INSN_MACRO,		I1	},
-{"mulou",   "d,v,t",	0,    (int) M_MULOU,	INSN_MACRO,		I1	},
-{"mulou",   "d,v,I",	0,    (int) M_MULOU_I,	INSN_MACRO,		I1	},
-{"mulr.ps", "D,S,T",	0x46c0001a, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	M3D	},
-{"muls",    "d,s,t",	0x000000d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"mulsu",   "d,s,t",	0x000000d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"mulshi",  "d,s,t",	0x000002d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"mulshiu", "d,s,t",	0x000002d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"muls.ob", "Y,Q",	0x78000032, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"muls.ob", "S,T",	0x4ac00032, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"muls.ob", "S,T[e]",	0x48000032, 0xfe2007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"muls.ob", "S,k",	0x4bc00032, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"muls.qh", "Y,Q",	0x78200032, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"mulsl.ob", "Y,Q",	0x78000432, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"mulsl.ob", "S,T",	0x4ac00432, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mulsl.ob", "S,T[e]",	0x48000432, 0xfe2007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mulsl.ob", "S,k",	0x4bc00432, 0xffe007ff,	WR_CC|RD_S|RD_T,	N54	},
-{"mulsl.qh", "Y,Q",	0x78200432, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"mult",    "s,t",      0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1	},
-{"mult",    "d,s,t",    0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1	},
-{"multu",   "s,t",      0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1	},
-{"multu",   "d,s,t",    0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1	},
-{"mulu",    "d,s,t",	0x00000059, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	N5	},
-{"neg",     "d,w",	0x00000022, 0xffe007ff,	WR_d|RD_t,		I1	}, /* sub 0 */
-{"negu",    "d,w",	0x00000023, 0xffe007ff,	WR_d|RD_t,		I1	}, /* subu 0 */
-{"neg.d",   "D,V",	0x46200007, 0xffff003f,	WR_D|RD_S|FP_D,		I1	},
-{"neg.s",   "D,V",	0x46000007, 0xffff003f,	WR_D|RD_S|FP_S,		I1	},
-{"neg.ps",  "D,V",	0x46c00007, 0xffff003f,	WR_D|RD_S|FP_D,		I5	},
-{"nmadd.d", "D,R,S,T",	0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4	},
-{"nmadd.s", "D,R,S,T",	0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4	},
-{"nmadd.ps","D,R,S,T",	0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5	},
-{"nmsub.d", "D,R,S,T",	0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4	},
-{"nmsub.s", "D,R,S,T",	0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4	},
-{"nmsub.ps","D,R,S,T",	0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5	},
+/* mtc3 is at the bottom of the table.  */
+{"mtdr",    "t,G",	0x7080003d, 0xffe007ff,	COD|RD_t|WR_C0,		0,		N5	},
+{"mthi",    "s",	0x00000011, 0xfc1fffff,	RD_s|WR_HI,		0,		I1	},
+{"mthi",    "s,7",	0x00000011, 0xfc1fe7ff, RD_s|WR_HI,		0,		D32	},
+{"mtlo",    "s",	0x00000013, 0xfc1fffff,	RD_s|WR_LO,		0,		I1	},
+{"mtlo",    "s,7",	0x00000013, 0xfc1fe7ff, RD_s|WR_LO,		0,		D32	},
+{"mtlhx",   "s",	0x00000053, 0xfc1fffff,	RD_s|MOD_HILO,		0,		SMT	},
+{"mttc0",   "t,G",	0x41800000, 0xffe007ff, TRAP|COD|RD_t|WR_C0|WR_CC, 0,		MT32	},
+{"mttc0",   "t,+D",	0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0,		MT32	},
+{"mttc0",   "t,G,H",	0x41800000, 0xffe007f8, TRAP|COD|RD_t|WR_C0|WR_CC, 0,		MT32	},
+{"mttc1",   "t,S",	0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0,		MT32	},
+{"mttc1",   "t,G",	0x41800022, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_S, 0,		MT32	},
+{"mttc2",   "t,g",	0x41800024, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0,		MT32	},
+{"mttacx",  "t",	0x41801021, 0xffe0ffff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttacx",  "t,&",	0x41801021, 0xffe09fff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttdsp",  "t",	0x41808021, 0xffe0ffff, TRAP|RD_t,		0,		MT32	},
+{"mttgpr",  "t,d",	0x41800020, 0xffe007ff, TRAP|WR_d|RD_t,		0,		MT32	},
+{"mtthc1",  "t,S",	0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0,		MT32	},
+{"mtthc1",  "t,G",	0x41800032, 0xffe007ff, TRAP|COD|RD_t|WR_S|FP_D, 0,		MT32	},
+{"mtthc2",  "t,g",	0x41800034, 0xffe007ff, TRAP|COD|RD_t|WR_C2|WR_CC, 0,		MT32	},
+{"mtthi",   "t",	0x41800821, 0xffe0ffff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mtthi",   "t,&",	0x41800821, 0xffe09fff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttlo",   "t",	0x41800021, 0xffe0ffff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttlo",   "t,&",	0x41800021, 0xffe09fff, TRAP|WR_a|RD_t,		0,		MT32	},
+{"mttr",    "t,d,!,H,$", 0x41800000, 0xffe007c8, TRAP|RD_t,		0,		MT32	},
+{"mul.d",   "D,V,T",	0x46200002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I1	},
+{"mul.s",   "D,V,T",	0x46000002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		I1	},
+{"mul.ob",  "X,Y,Q",	0x78000030, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"mul.ob",  "D,S,T",	0x4ac00030, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"mul.ob",  "D,S,T[e]",	0x48000030, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"mul.ob",  "D,S,k",	0x4bc00030, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"mul.ps",  "D,V,T",	0x46c00002, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"mul.qh",  "X,Y,Q",	0x78200030, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"mul",     "d,v,t",    0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		I32|P3|N55},
+{"mul",     "d,s,t",	0x00000058, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N54	},
+{"mul",     "d,v,t",	0,    (int) M_MUL,	INSN_MACRO,		0,		I1	},
+{"mul",     "d,v,I",	0,    (int) M_MUL_I,	INSN_MACRO,		0,		I1	},
+{"mula.ob", "Y,Q",	0x78000033, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"mula.ob", "S,T",	0x4ac00033, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mula.ob", "S,T[e]",	0x48000033, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mula.ob", "S,k",	0x4bc00033, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mula.qh", "Y,Q",	0x78200033, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"mulhi",   "d,s,t",	0x00000258, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mulhiu",  "d,s,t",	0x00000259, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mull.ob", "Y,Q",	0x78000433, 0xfc2007ff,	RD_S|RD_T|FP_D, 	WR_MACC,	MX|SB1	},
+{"mull.ob", "S,T",	0x4ac00433, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mull.ob", "S,T[e]",	0x48000433, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mull.ob", "S,k",	0x4bc00433, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mull.qh", "Y,Q",	0x78200433, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"mulo",    "d,v,t",	0,    (int) M_MULO,	INSN_MACRO,		0,		I1	},
+{"mulo",    "d,v,I",	0,    (int) M_MULO_I,	INSN_MACRO,		0,		I1	},
+{"mulou",   "d,v,t",	0,    (int) M_MULOU,	INSN_MACRO,		0,		I1	},
+{"mulou",   "d,v,I",	0,    (int) M_MULOU_I,	INSN_MACRO,		0,		I1	},
+{"mulr.ps", "D,S,T",	0x46c0001a, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		M3D	},
+{"muls",    "d,s,t",	0x000000d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mulsu",   "d,s,t",	0x000000d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mulshi",  "d,s,t",	0x000002d8, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"mulshiu", "d,s,t",	0x000002d9, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"muls.ob", "Y,Q",	0x78000032, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"muls.ob", "S,T",	0x4ac00032, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"muls.ob", "S,T[e]",	0x48000032, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"muls.ob", "S,k",	0x4bc00032, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"muls.qh", "Y,Q",	0x78200032, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"mulsl.ob", "Y,Q",	0x78000432, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"mulsl.ob", "S,T",	0x4ac00432, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mulsl.ob", "S,T[e]",	0x48000432, 0xfe2007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mulsl.ob", "S,k",	0x4bc00432, 0xffe007ff,	WR_CC|RD_S|RD_T,	0,		N54	},
+{"mulsl.qh", "Y,Q",	0x78200432, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"mult",    "s,t",      0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0,		I1	},
+{"mult",    "7,s,t",	0x00000018, 0xfc00e7ff, WR_a|RD_s|RD_t,         0,              D33	},
+{"mult",    "d,s,t",    0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0,		G1	},
+{"multp",   "s,t",	0x00000459, 0xfc00ffff,	RD_s|RD_t|MOD_HILO,	0,		SMT	},
+{"multu",   "s,t",      0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, 0,		I1	},
+{"multu",   "7,s,t",	0x00000019, 0xfc00e7ff, WR_a|RD_s|RD_t,         0,              D33	},
+{"multu",   "d,s,t",    0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, 0,		G1	},
+{"mulu",    "d,s,t",	0x00000059, 0xfc0007ff,	RD_s|RD_t|WR_HILO|WR_d,	0,		N5	},
+{"neg",     "d,w",	0x00000022, 0xffe007ff,	WR_d|RD_t,		0,		I1	}, /* sub 0 */
+{"negu",    "d,w",	0x00000023, 0xffe007ff,	WR_d|RD_t,		0,		I1	}, /* subu 0 */
+{"neg.d",   "D,V",	0x46200007, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I1	},
+{"neg.s",   "D,V",	0x46000007, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I1	},
+{"neg.ps",  "D,V",	0x46c00007, 0xffff003f,	WR_D|RD_S|FP_D,		0,		I5|I33	},
+{"nmadd.d", "D,R,S,T",	0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I4|I33	},
+{"nmadd.s", "D,R,S,T",	0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0,		I4|I33	},
+{"nmadd.ps","D,R,S,T",	0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I5|I33	},
+{"nmsub.d", "D,R,S,T",	0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I4|I33	},
+{"nmsub.s", "D,R,S,T",	0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, 0,		I4|I33	},
+{"nmsub.ps","D,R,S,T",	0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, 0,		I5|I33	},
 /* nop is at the start of the table.  */
-{"nor",     "d,v,t",	0x00000027, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"nor",     "t,r,I",	0,    (int) M_NOR_I,	INSN_MACRO,		I1	},
-{"nor.ob",  "X,Y,Q",	0x7800000f, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"nor.ob",  "D,S,T",	0x4ac0000f, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"nor.ob",  "D,S,T[e]",	0x4800000f, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"nor.ob",  "D,S,k",	0x4bc0000f, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"nor.qh",  "X,Y,Q",	0x7820000f, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"not",     "d,v",	0x00000027, 0xfc1f07ff,	WR_d|RD_s|RD_t,		I1	},/*nor d,s,0*/
-{"or",      "d,v,t",	0x00000025, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"or",      "t,r,I",	0,    (int) M_OR_I,	INSN_MACRO,		I1	},
-{"or.ob",   "X,Y,Q",	0x7800000e, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"or.ob",   "D,S,T",	0x4ac0000e, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"or.ob",   "D,S,T[e]",	0x4800000e, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"or.ob",   "D,S,k",	0x4bc0000e, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"or.qh",   "X,Y,Q",	0x7820000e, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"ori",     "t,r,i",	0x34000000, 0xfc000000,	WR_t|RD_s,		I1	},
-{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	SB1	},
-{"pabsdiffc.ob", "Y,Q",	0x78000035, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	SB1	},
-{"pavg.ob", "X,Y,Q",	0x78000008, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	SB1	},
-{"pickf.ob", "X,Y,Q",	0x78000002, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"pickf.ob", "D,S,T",	0x4ac00002, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"pickf.ob", "D,S,k",	0x4bc00002, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"pickf.qh", "X,Y,Q",	0x78200002, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"pickt.ob", "X,Y,Q",	0x78000003, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"pickt.ob", "D,S,T",	0x4ac00003, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"pickt.ob", "D,S,k",	0x4bc00003, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"pickt.qh", "X,Y,Q",	0x78200003, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"pll.ps",  "D,V,T",	0x46c0002c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
-{"plu.ps",  "D,V,T",	0x46c0002d, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
+{"nor",     "d,v,t",	0x00000027, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"nor",     "t,r,I",	0,    (int) M_NOR_I,	INSN_MACRO,		0,		I1	},
+{"nor.ob",  "X,Y,Q",	0x7800000f, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"nor.ob",  "D,S,T",	0x4ac0000f, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"nor.ob",  "D,S,T[e]",	0x4800000f, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"nor.ob",  "D,S,k",	0x4bc0000f, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"nor.qh",  "X,Y,Q",	0x7820000f, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"not",     "d,v",	0x00000027, 0xfc1f07ff,	WR_d|RD_s|RD_t,		0,		I1	},/*nor d,s,0*/
+{"or",      "d,v,t",	0x00000025, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"or",      "t,r,I",	0,    (int) M_OR_I,	INSN_MACRO,		0,		I1	},
+{"or.ob",   "X,Y,Q",	0x7800000e, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"or.ob",   "D,S,T",	0x4ac0000e, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"or.ob",   "D,S,T[e]",	0x4800000e, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"or.ob",   "D,S,k",	0x4bc0000e, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"or.qh",   "X,Y,Q",	0x7820000e, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"ori",     "t,r,i",	0x34000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		SB1	},
+{"pabsdiffc.ob", "Y,Q",	0x78000035, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	SB1	},
+{"pavg.ob", "X,Y,Q",	0x78000008, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		SB1	},
+{"pickf.ob", "X,Y,Q",	0x78000002, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"pickf.ob", "D,S,T",	0x4ac00002, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickf.ob", "D,S,k",	0x4bc00002, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickf.qh", "X,Y,Q",	0x78200002, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"pickt.ob", "X,Y,Q",	0x78000003, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"pickt.ob", "D,S,T",	0x4ac00003, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickt.ob", "D,S,k",	0x4bc00003, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"pickt.qh", "X,Y,Q",	0x78200003, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"pll.ps",  "D,V,T",	0x46c0002c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"plu.ps",  "D,V,T",	0x46c0002d, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
   /* pref and prefx are at the start of the table.  */
-{"pul.ps",  "D,V,T",	0x46c0002e, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
-{"puu.ps",  "D,V,T",	0x46c0002f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
-{"rach.ob", "X",	0x7a00003f, 0xfffff83f,	WR_D|RD_MACC|FP_D,	MX|SB1	},
-{"rach.ob", "D",	0x4a00003f, 0xfffff83f,	WR_D,			N54	},
-{"rach.qh", "X",	0x7a20003f, 0xfffff83f,	WR_D|RD_MACC|FP_D,	MX	},
-{"racl.ob", "X",	0x7800003f, 0xfffff83f,	WR_D|RD_MACC|FP_D,	MX|SB1	},
-{"racl.ob", "D",	0x4800003f, 0xfffff83f,	WR_D,			N54	},
-{"racl.qh", "X",	0x7820003f, 0xfffff83f,	WR_D|RD_MACC|FP_D,	MX	},
-{"racm.ob", "X",	0x7900003f, 0xfffff83f,	WR_D|RD_MACC|FP_D,	MX|SB1	},
-{"racm.ob", "D",	0x4900003f, 0xfffff83f,	WR_D,			N54	},
-{"racm.qh", "X",	0x7920003f, 0xfffff83f,	WR_D|RD_MACC|FP_D,	MX	},
-{"recip.d", "D,S",	0x46200015, 0xffff003f, WR_D|RD_S|FP_D,		I4	},
-{"recip.ps","D,S",	0x46c00015, 0xffff003f, WR_D|RD_S|FP_D,		SB1	},
-{"recip.s", "D,S",	0x46000015, 0xffff003f, WR_D|RD_S|FP_S,		I4	},
-{"recip1.d",  "D,S",	0x4620001d, 0xffff003f,	WR_D|RD_S|FP_D,		M3D	},
-{"recip1.ps", "D,S",	0x46c0001d, 0xffff003f,	WR_D|RD_S|FP_S,		M3D	},
-{"recip1.s",  "D,S",	0x4600001d, 0xffff003f,	WR_D|RD_S|FP_S,		M3D	},
-{"recip2.d",  "D,S,T",	0x4620001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	M3D	},
-{"recip2.ps", "D,S,T",	0x46c0001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	M3D	},
-{"recip2.s",  "D,S,T",	0x4600001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	M3D	},
-{"rem",     "z,s,t",    0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I1	},
-{"rem",     "d,v,t",	0,    (int) M_REM_3,	INSN_MACRO,		I1	},
-{"rem",     "d,v,I",	0,    (int) M_REM_3I,	INSN_MACRO,		I1	},
-{"remu",    "z,s,t",    0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO,      I1	},
-{"remu",    "d,v,t",	0,    (int) M_REMU_3,	INSN_MACRO,		I1	},
-{"remu",    "d,v,I",	0,    (int) M_REMU_3I,	INSN_MACRO,		I1	},
-{"rdhwr",   "t,K",	0x7c00003b, 0xffe007ff, WR_t,			I33	},
-{"rdpgpr",  "d,w",	0x41400000, 0xffe007ff, WR_d,			I33	},
-{"rfe",     "",		0x42000010, 0xffffffff,	0,			I1|T3	},
-{"rnas.qh", "X,Q",	0x78200025, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX	},
-{"rnau.ob", "X,Q",	0x78000021, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX|SB1	},
-{"rnau.qh", "X,Q",	0x78200021, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX	},
-{"rnes.qh", "X,Q",	0x78200026, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX	},
-{"rneu.ob", "X,Q",	0x78000022, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX|SB1	},
-{"rneu.qh", "X,Q",	0x78200022, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX	},
-{"rol",     "d,v,t",	0,    (int) M_ROL,	INSN_MACRO,		I1	},
-{"rol",     "d,v,I",	0,    (int) M_ROL_I,	INSN_MACRO,		I1	},
-{"ror",     "d,v,t",	0,    (int) M_ROR,	INSN_MACRO,		I1	},
-{"ror",     "d,v,I",	0,    (int) M_ROR_I,	INSN_MACRO,		I1	},
-{"ror",	    "d,w,<",	0x00200002, 0xffe0003f,	WR_d|RD_t,		N5|I33	},
-{"rorv",    "d,t,s",	0x00000046, 0xfc0007ff,	RD_t|RD_s|WR_d,		N5|I33	},
-{"rotl",    "d,v,t",	0,    (int) M_ROL,	INSN_MACRO,		I33	},
-{"rotl",    "d,v,I",	0,    (int) M_ROL_I,	INSN_MACRO,		I33	},
-{"rotr",    "d,v,t",	0,    (int) M_ROR,	INSN_MACRO,		I33	},
-{"rotr",    "d,v,I",	0,    (int) M_ROR_I,	INSN_MACRO,		I33	},
-{"rotrv",   "d,t,s",	0x00000046, 0xfc0007ff,	RD_t|RD_s|WR_d,		I33	},
-{"round.l.d", "D,S",	0x46200008, 0xffff003f, WR_D|RD_S|FP_D,		I3	},
-{"round.l.s", "D,S",	0x46000008, 0xffff003f, WR_D|RD_S|FP_S,		I3	},
-{"round.w.d", "D,S",	0x4620000c, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
-{"round.w.s", "D,S",	0x4600000c, 0xffff003f, WR_D|RD_S|FP_S,		I2	},
-{"rsqrt.d", "D,S",	0x46200016, 0xffff003f, WR_D|RD_S|FP_D,		I4	},
-{"rsqrt.ps","D,S",	0x46c00016, 0xffff003f, WR_D|RD_S|FP_D,		SB1	},
-{"rsqrt.s", "D,S",	0x46000016, 0xffff003f, WR_D|RD_S|FP_S,		I4	},
-{"rsqrt1.d",  "D,S",	0x4620001e, 0xffff003f,	WR_D|RD_S|FP_D,		M3D	},
-{"rsqrt1.ps", "D,S",	0x46c0001e, 0xffff003f,	WR_D|RD_S|FP_S,		M3D	},
-{"rsqrt1.s",  "D,S",	0x4600001e, 0xffff003f,	WR_D|RD_S|FP_S,		M3D	},
-{"rsqrt2.d",  "D,S,T",	0x4620001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	M3D	},
-{"rsqrt2.ps", "D,S,T",	0x46c0001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	M3D	},
-{"rsqrt2.s",  "D,S,T",	0x4600001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	M3D	},
-{"rzs.qh",  "X,Q",	0x78200024, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX	},
-{"rzu.ob",  "X,Q",	0x78000020, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX|SB1	},
-{"rzu.ob",  "D,k",	0x4bc00020, 0xffe0f83f,	WR_D|RD_S|RD_T,		N54	},
-{"rzu.qh",  "X,Q",	0x78200020, 0xfc20f83f,	WR_D|RD_MACC|RD_T|FP_D,	MX	},
-{"sb",      "t,o(b)",	0xa0000000, 0xfc000000,	SM|RD_t|RD_b,		I1	},
-{"sb",      "t,A(b)",	0,    (int) M_SB_AB,	INSN_MACRO,		I1	},
-{"sc",	    "t,o(b)",	0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b,	I2	},
-{"sc",	    "t,A(b)",	0,    (int) M_SC_AB,	INSN_MACRO,		I2	},
-{"scd",	    "t,o(b)",	0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b,	I3	},
-{"scd",	    "t,A(b)",	0,    (int) M_SCD_AB,	INSN_MACRO,		I3	},
-{"sd",	    "t,o(b)",	0xfc000000, 0xfc000000,	SM|RD_t|RD_b,		I3	},
-{"sd",      "t,o(b)",	0,    (int) M_SD_OB,	INSN_MACRO,		I1	},
-{"sd",      "t,A(b)",	0,    (int) M_SD_AB,	INSN_MACRO,		I1	},
-{"sdbbp",   "",		0x0000000e, 0xffffffff,	TRAP,           	G2	},
-{"sdbbp",   "c",	0x0000000e, 0xfc00ffff,	TRAP,			G2	},
-{"sdbbp",   "c,q",	0x0000000e, 0xfc00003f,	TRAP,			G2	},
-{"sdbbp",   "",         0x7000003f, 0xffffffff, TRAP,           	I32     },
-{"sdbbp",   "B",        0x7000003f, 0xfc00003f, TRAP,           	I32     },
-{"sdc1",    "T,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	I2	},
-{"sdc1",    "E,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	I2	},
-{"sdc1",    "T,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		I2	},
-{"sdc1",    "E,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		I2	},
-{"sdc2",    "E,o(b)",	0xf8000000, 0xfc000000, SM|RD_C2|RD_b,		I2	},
-{"sdc2",    "E,A(b)",	0,    (int) M_SDC2_AB,	INSN_MACRO,		I2	},
-{"sdc3",    "E,o(b)",	0xfc000000, 0xfc000000, SM|RD_C3|RD_b,		I2	},
-{"sdc3",    "E,A(b)",	0,    (int) M_SDC3_AB,	INSN_MACRO,		I2	},
-{"s.d",     "T,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	I2	},
-{"s.d",     "T,o(b)",	0,    (int) M_S_DOB,	INSN_MACRO,		I1	},
-{"s.d",     "T,A(b)",	0,    (int) M_S_DAB,	INSN_MACRO,		I1	},
-{"sdl",     "t,o(b)",	0xb0000000, 0xfc000000,	SM|RD_t|RD_b,		I3	},
-{"sdl",     "t,A(b)",	0,    (int) M_SDL_AB,	INSN_MACRO,		I3	},
-{"sdr",     "t,o(b)",	0xb4000000, 0xfc000000,	SM|RD_t|RD_b,		I3	},
-{"sdr",     "t,A(b)",	0,    (int) M_SDR_AB,	INSN_MACRO,		I3	},
-{"sdxc1",   "S,t(b)",   0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b,	I4	},
-{"seb",     "d,w",	0x7c000420, 0xffe007ff,	WR_d|RD_t,		I33	},
-{"seh",     "d,w",	0x7c000620, 0xffe007ff,	WR_d|RD_t,		I33	},
-{"selsl",   "d,v,t",	0x00000005, 0xfc0007ff,	WR_d|RD_s|RD_t,		L1	},
-{"selsr",   "d,v,t",	0x00000001, 0xfc0007ff,	WR_d|RD_s|RD_t,		L1	},
-{"seq",     "d,v,t",	0,    (int) M_SEQ,	INSN_MACRO,		I1	},
-{"seq",     "d,v,I",	0,    (int) M_SEQ_I,	INSN_MACRO,		I1	},
-{"sge",     "d,v,t",	0,    (int) M_SGE,	INSN_MACRO,		I1	},
-{"sge",     "d,v,I",	0,    (int) M_SGE_I,	INSN_MACRO,		I1	},
-{"sgeu",    "d,v,t",	0,    (int) M_SGEU,	INSN_MACRO,		I1	},
-{"sgeu",    "d,v,I",	0,    (int) M_SGEU_I,	INSN_MACRO,		I1	},
-{"sgt",     "d,v,t",	0,    (int) M_SGT,	INSN_MACRO,		I1	},
-{"sgt",     "d,v,I",	0,    (int) M_SGT_I,	INSN_MACRO,		I1	},
-{"sgtu",    "d,v,t",	0,    (int) M_SGTU,	INSN_MACRO,		I1	},
-{"sgtu",    "d,v,I",	0,    (int) M_SGTU_I,	INSN_MACRO,		I1	},
-{"sh",      "t,o(b)",	0xa4000000, 0xfc000000,	SM|RD_t|RD_b,		I1	},
-{"sh",      "t,A(b)",	0,    (int) M_SH_AB,	INSN_MACRO,		I1	},
-{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX	},
-{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, 	N54	},
-{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX	},
-{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, 	N54	},
-{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX	},
-{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, 	N54	},
-{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX	},
-{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, 	N54	},
-{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX	},
-{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX	},
-{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"sle",     "d,v,t",	0,    (int) M_SLE,	INSN_MACRO,		I1	},
-{"sle",     "d,v,I",	0,    (int) M_SLE_I,	INSN_MACRO,		I1	},
-{"sleu",    "d,v,t",	0,    (int) M_SLEU,	INSN_MACRO,		I1	},
-{"sleu",    "d,v,I",	0,    (int) M_SLEU_I,	INSN_MACRO,		I1	},
-{"sllv",    "d,t,s",	0x00000004, 0xfc0007ff,	WR_d|RD_t|RD_s,		I1	},
-{"sll",     "d,w,s",	0x00000004, 0xfc0007ff,	WR_d|RD_t|RD_s,		I1	}, /* sllv */
-{"sll",     "d,w,<",	0x00000000, 0xffe0003f,	WR_d|RD_t,		I1	},
-{"sll.ob",  "X,Y,Q",	0x78000010, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"sll.ob",  "D,S,T[e]",	0x48000010, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"sll.ob",  "D,S,k",	0x4bc00010, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"sll.qh",  "X,Y,Q",	0x78200010, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"slt",     "d,v,t",	0x0000002a, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"slt",     "d,v,I",	0,    (int) M_SLT_I,	INSN_MACRO,		I1	},
-{"slti",    "t,r,j",	0x28000000, 0xfc000000,	WR_t|RD_s,		I1	},
-{"sltiu",   "t,r,j",	0x2c000000, 0xfc000000,	WR_t|RD_s,		I1	},
-{"sltu",    "d,v,t",	0x0000002b, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"sltu",    "d,v,I",	0,    (int) M_SLTU_I,	INSN_MACRO,		I1	},
-{"sne",     "d,v,t",	0,    (int) M_SNE,	INSN_MACRO,		I1	},
-{"sne",     "d,v,I",	0,    (int) M_SNE_I,	INSN_MACRO,		I1	},
-{"sqrt.d",  "D,S",	0x46200004, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
-{"sqrt.s",  "D,S",	0x46000004, 0xffff003f, WR_D|RD_S|FP_S,		I2	},
-{"sqrt.ps", "D,S",	0x46c00004, 0xffff003f, WR_D|RD_S|FP_D,		SB1	},
-{"srav",    "d,t,s",	0x00000007, 0xfc0007ff,	WR_d|RD_t|RD_s,		I1	},
-{"sra",     "d,w,s",	0x00000007, 0xfc0007ff,	WR_d|RD_t|RD_s,		I1	}, /* srav */
-{"sra",     "d,w,<",	0x00000003, 0xffe0003f,	WR_d|RD_t,		I1	},
-{"sra.qh",  "X,Y,Q",	0x78200013, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"srlv",    "d,t,s",	0x00000006, 0xfc0007ff,	WR_d|RD_t|RD_s,		I1	},
-{"srl",     "d,w,s",	0x00000006, 0xfc0007ff,	WR_d|RD_t|RD_s,		I1	}, /* srlv */
-{"srl",     "d,w,<",	0x00000002, 0xffe0003f,	WR_d|RD_t,		I1	},
-{"srl.ob",  "X,Y,Q",	0x78000012, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"srl.ob",  "D,S,T[e]",	0x48000012, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"srl.ob",  "D,S,k",	0x4bc00012, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"srl.qh",  "X,Y,Q",	0x78200012, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
+{"pul.ps",  "D,V,T",	0x46c0002e, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"puu.ps",  "D,V,T",	0x46c0002f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"pperm",   "s,t",	0x70000481, 0xfc00ffff,	MOD_HILO|RD_s|RD_t,	0,		SMT	},
+{"rach.ob", "X",	0x7a00003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX|SB1	},
+{"rach.ob", "D",	0x4a00003f, 0xfffff83f,	WR_D,			0,		N54	},
+{"rach.qh", "X",	0x7a20003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX	},
+{"racl.ob", "X",	0x7800003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX|SB1	},
+{"racl.ob", "D",	0x4800003f, 0xfffff83f,	WR_D,			0,		N54	},
+{"racl.qh", "X",	0x7820003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX	},
+{"racm.ob", "X",	0x7900003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX|SB1	},
+{"racm.ob", "D",	0x4900003f, 0xfffff83f,	WR_D,			0,		N54	},
+{"racm.qh", "X",	0x7920003f, 0xfffff83f,	WR_D|FP_D,		RD_MACC,	MX	},
+{"recip.d", "D,S",	0x46200015, 0xffff003f, WR_D|RD_S|FP_D,		0,		I4|I33	},
+{"recip.ps","D,S",	0x46c00015, 0xffff003f, WR_D|RD_S|FP_D,		0,		SB1	},
+{"recip.s", "D,S",	0x46000015, 0xffff003f, WR_D|RD_S|FP_S,		0,		I4|I33	},
+{"recip1.d",  "D,S",	0x4620001d, 0xffff003f,	WR_D|RD_S|FP_D,		0,		M3D	},
+{"recip1.ps", "D,S",	0x46c0001d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		M3D	},
+{"recip1.s",  "D,S",	0x4600001d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		M3D	},
+{"recip2.d",  "D,S,T",	0x4620001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		M3D	},
+{"recip2.ps", "D,S,T",	0x46c0001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		M3D	},
+{"recip2.s",  "D,S,T",	0x4600001c, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		M3D	},
+{"rem",     "z,s,t",    0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I1	},
+{"rem",     "d,v,t",	0,    (int) M_REM_3,	INSN_MACRO,		0,		I1	},
+{"rem",     "d,v,I",	0,    (int) M_REM_3I,	INSN_MACRO,		0,		I1	},
+{"remu",    "z,s,t",    0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO,      0,		I1	},
+{"remu",    "d,v,t",	0,    (int) M_REMU_3,	INSN_MACRO,		0,		I1	},
+{"remu",    "d,v,I",	0,    (int) M_REMU_3I,	INSN_MACRO,		0,		I1	},
+{"rdhwr",   "t,K",	0x7c00003b, 0xffe007ff, WR_t,			0,		I33	},
+{"rdpgpr",  "d,w",	0x41400000, 0xffe007ff, WR_d,			0,		I33	},
+{"rfe",     "",		0x42000010, 0xffffffff,	0,			0,		I1|T3	},
+{"rnas.qh", "X,Q",	0x78200025, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rnau.ob", "X,Q",	0x78000021, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX|SB1	},
+{"rnau.qh", "X,Q",	0x78200021, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rnes.qh", "X,Q",	0x78200026, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rneu.ob", "X,Q",	0x78000022, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX|SB1	},
+{"rneu.qh", "X,Q",	0x78200022, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rol",     "d,v,t",	0,    (int) M_ROL,	INSN_MACRO,		0,		I1	},
+{"rol",     "d,v,I",	0,    (int) M_ROL_I,	INSN_MACRO,		0,		I1	},
+{"ror",     "d,v,t",	0,    (int) M_ROR,	INSN_MACRO,		0,		I1	},
+{"ror",     "d,v,I",	0,    (int) M_ROR_I,	INSN_MACRO,		0,		I1	},
+{"ror",	    "d,w,<",	0x00200002, 0xffe0003f,	WR_d|RD_t,		0,		N5|I33|SMT },
+{"rorv",    "d,t,s",	0x00000046, 0xfc0007ff,	RD_t|RD_s|WR_d,		0,		N5|I33|SMT },
+{"rotl",    "d,v,t",	0,    (int) M_ROL,	INSN_MACRO,		0,		I33|SMT	},
+{"rotl",    "d,v,I",	0,    (int) M_ROL_I,	INSN_MACRO,		0,		I33|SMT	},
+{"rotr",    "d,v,t",	0,    (int) M_ROR,	INSN_MACRO,		0,		I33|SMT	},
+{"rotr",    "d,v,I",	0,    (int) M_ROR_I,	INSN_MACRO,		0,		I33|SMT	},
+{"rotrv",   "d,t,s",	0x00000046, 0xfc0007ff,	RD_t|RD_s|WR_d,		0,		I33|SMT	},
+{"round.l.d", "D,S",	0x46200008, 0xffff003f, WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"round.l.s", "D,S",	0x46000008, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"round.w.d", "D,S",	0x4620000c, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"round.w.s", "D,S",	0x4600000c, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
+{"rsqrt.d", "D,S",	0x46200016, 0xffff003f, WR_D|RD_S|FP_D,		0,		I4|I33	},
+{"rsqrt.ps","D,S",	0x46c00016, 0xffff003f, WR_D|RD_S|FP_D,		0,		SB1	},
+{"rsqrt.s", "D,S",	0x46000016, 0xffff003f, WR_D|RD_S|FP_S,		0,		I4|I33	},
+{"rsqrt1.d",  "D,S",	0x4620001e, 0xffff003f,	WR_D|RD_S|FP_D,		0,		M3D	},
+{"rsqrt1.ps", "D,S",	0x46c0001e, 0xffff003f,	WR_D|RD_S|FP_S,		0,		M3D	},
+{"rsqrt1.s",  "D,S",	0x4600001e, 0xffff003f,	WR_D|RD_S|FP_S,		0,		M3D	},
+{"rsqrt2.d",  "D,S,T",	0x4620001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		M3D	},
+{"rsqrt2.ps", "D,S,T",	0x46c0001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		M3D	},
+{"rsqrt2.s",  "D,S,T",	0x4600001f, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		M3D	},
+{"rzs.qh",  "X,Q",	0x78200024, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"rzu.ob",  "X,Q",	0x78000020, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX|SB1	},
+{"rzu.ob",  "D,k",	0x4bc00020, 0xffe0f83f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"rzu.qh",  "X,Q",	0x78200020, 0xfc20f83f,	WR_D|RD_T|FP_D,		RD_MACC,	MX	},
+{"sb",      "t,o(b)",	0xa0000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"sb",      "t,A(b)",	0,    (int) M_SB_AB,	INSN_MACRO,		0,		I1	},
+{"sc",	    "t,o(b)",	0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b,	0,		I2	},
+{"sc",	    "t,A(b)",	0,    (int) M_SC_AB,	INSN_MACRO,		0,		I2	},
+{"scd",	    "t,o(b)",	0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b,	0,		I3	},
+{"scd",	    "t,A(b)",	0,    (int) M_SCD_AB,	INSN_MACRO,		0,		I3	},
+{"sd",	    "t,o(b)",	0xfc000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
+{"sd",      "t,o(b)",	0,    (int) M_SD_OB,	INSN_MACRO,		0,		I1	},
+{"sd",      "t,A(b)",	0,    (int) M_SD_AB,	INSN_MACRO,		0,		I1	},
+{"sdbbp",   "",		0x0000000e, 0xffffffff,	TRAP,           	0,		G2	},
+{"sdbbp",   "c",	0x0000000e, 0xfc00ffff,	TRAP,			0,		G2	},
+{"sdbbp",   "c,q",	0x0000000e, 0xfc00003f,	TRAP,			0,		G2	},
+{"sdbbp",   "",         0x7000003f, 0xffffffff, TRAP,           	0,		I32     },
+{"sdbbp",   "B",        0x7000003f, 0xfc00003f, TRAP,           	0,		I32     },
+{"sdc1",    "T,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	0,		I2	},
+{"sdc1",    "E,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	0,		I2	},
+{"sdc1",    "T,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		0,		I2	},
+{"sdc1",    "E,A(b)",	0,    (int) M_SDC1_AB,	INSN_MACRO,		0,		I2	},
+{"sdc2",    "E,o(b)",	0xf8000000, 0xfc000000, SM|RD_C2|RD_b,		0,		I2	},
+{"sdc2",    "E,A(b)",	0,    (int) M_SDC2_AB,	INSN_MACRO,		0,		I2	},
+{"sdc3",    "E,o(b)",	0xfc000000, 0xfc000000, SM|RD_C3|RD_b,		0,		I2	},
+{"sdc3",    "E,A(b)",	0,    (int) M_SDC3_AB,	INSN_MACRO,		0,		I2	},
+{"s.d",     "T,o(b)",	0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D,	0,		I2	},
+{"s.d",     "T,o(b)",	0,    (int) M_S_DOB,	INSN_MACRO,		0,		I1	},
+{"s.d",     "T,A(b)",	0,    (int) M_S_DAB,	INSN_MACRO,		0,		I1	},
+{"sdl",     "t,o(b)",	0xb0000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
+{"sdl",     "t,A(b)",	0,    (int) M_SDL_AB,	INSN_MACRO,		0,		I3	},
+{"sdr",     "t,o(b)",	0xb4000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I3	},
+{"sdr",     "t,A(b)",	0,    (int) M_SDR_AB,	INSN_MACRO,		0,		I3	},
+{"sdxc1",   "S,t(b)",   0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_D,	0,		I4|I33	},
+{"seb",     "d,w",	0x7c000420, 0xffe007ff,	WR_d|RD_t,		0,		I33	},
+{"seh",     "d,w",	0x7c000620, 0xffe007ff,	WR_d|RD_t,		0,		I33	},
+{"selsl",   "d,v,t",	0x00000005, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		L1	},
+{"selsr",   "d,v,t",	0x00000001, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		L1	},
+{"seq",     "d,v,t",	0,    (int) M_SEQ,	INSN_MACRO,		0,		I1	},
+{"seq",     "d,v,I",	0,    (int) M_SEQ_I,	INSN_MACRO,		0,		I1	},
+{"sge",     "d,v,t",	0,    (int) M_SGE,	INSN_MACRO,		0,		I1	},
+{"sge",     "d,v,I",	0,    (int) M_SGE_I,	INSN_MACRO,		0,		I1	},
+{"sgeu",    "d,v,t",	0,    (int) M_SGEU,	INSN_MACRO,		0,		I1	},
+{"sgeu",    "d,v,I",	0,    (int) M_SGEU_I,	INSN_MACRO,		0,		I1	},
+{"sgt",     "d,v,t",	0,    (int) M_SGT,	INSN_MACRO,		0,		I1	},
+{"sgt",     "d,v,I",	0,    (int) M_SGT_I,	INSN_MACRO,		0,		I1	},
+{"sgtu",    "d,v,t",	0,    (int) M_SGTU,	INSN_MACRO,		0,		I1	},
+{"sgtu",    "d,v,I",	0,    (int) M_SGTU_I,	INSN_MACRO,		0,		I1	},
+{"sh",      "t,o(b)",	0xa4000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"sh",      "t,A(b)",	0,    (int) M_SH_AB,	INSN_MACRO,		0,		I1	},
+{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, 	0,		N54	},
+{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, 	0,		N54	},
+{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, 	0,		N54	},
+{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, 	0,		N54	},
+{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"sle",     "d,v,t",	0,    (int) M_SLE,	INSN_MACRO,		0,		I1	},
+{"sle",     "d,v,I",	0,    (int) M_SLE_I,	INSN_MACRO,		0,		I1	},
+{"sleu",    "d,v,t",	0,    (int) M_SLEU,	INSN_MACRO,		0,		I1	},
+{"sleu",    "d,v,I",	0,    (int) M_SLEU_I,	INSN_MACRO,		0,		I1	},
+{"sllv",    "d,t,s",	0x00000004, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	},
+{"sll",     "d,w,s",	0x00000004, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	}, /* sllv */
+{"sll",     "d,w,<",	0x00000000, 0xffe0003f,	WR_d|RD_t,		0,		I1	},
+{"sll.ob",  "X,Y,Q",	0x78000010, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"sll.ob",  "D,S,T[e]",	0x48000010, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sll.ob",  "D,S,k",	0x4bc00010, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sll.qh",  "X,Y,Q",	0x78200010, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"slt",     "d,v,t",	0x0000002a, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"slt",     "d,v,I",	0,    (int) M_SLT_I,	INSN_MACRO,		0,		I1	},
+{"slti",    "t,r,j",	0x28000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"sltiu",   "t,r,j",	0x2c000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"sltu",    "d,v,t",	0x0000002b, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"sltu",    "d,v,I",	0,    (int) M_SLTU_I,	INSN_MACRO,		0,		I1	},
+{"sne",     "d,v,t",	0,    (int) M_SNE,	INSN_MACRO,		0,		I1	},
+{"sne",     "d,v,I",	0,    (int) M_SNE_I,	INSN_MACRO,		0,		I1	},
+{"sqrt.d",  "D,S",	0x46200004, 0xffff003f, WR_D|RD_S|FP_D,		0,		I2	},
+{"sqrt.s",  "D,S",	0x46000004, 0xffff003f, WR_D|RD_S|FP_S,		0,		I2	},
+{"sqrt.ps", "D,S",	0x46c00004, 0xffff003f, WR_D|RD_S|FP_D,		0,		SB1	},
+{"srav",    "d,t,s",	0x00000007, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	},
+{"sra",     "d,w,s",	0x00000007, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	}, /* srav */
+{"sra",     "d,w,<",	0x00000003, 0xffe0003f,	WR_d|RD_t,		0,		I1	},
+{"sra.qh",  "X,Y,Q",	0x78200013, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"srlv",    "d,t,s",	0x00000006, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	},
+{"srl",     "d,w,s",	0x00000006, 0xfc0007ff,	WR_d|RD_t|RD_s,		0,		I1	}, /* srlv */
+{"srl",     "d,w,<",	0x00000002, 0xffe0003f,	WR_d|RD_t,		0,		I1	},
+{"srl.ob",  "X,Y,Q",	0x78000012, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"srl.ob",  "D,S,T[e]",	0x48000012, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"srl.ob",  "D,S,k",	0x4bc00012, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"srl.qh",  "X,Y,Q",	0x78200012, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
 /* ssnop is at the start of the table.  */
-{"standby", "",         0x42000021, 0xffffffff,	0,			V1	},
-{"sub",     "d,v,t",	0x00000022, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"sub",     "d,v,I",	0,    (int) M_SUB_I,	INSN_MACRO,		I1	},
-{"sub.d",   "D,V,T",	0x46200001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I1	},
-{"sub.s",   "D,V,T",	0x46000001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	I1	},
-{"sub.ob",  "X,Y,Q",	0x7800000a, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"sub.ob",  "D,S,T",	0x4ac0000a, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"sub.ob",  "D,S,T[e]",	0x4800000a, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"sub.ob",  "D,S,k",	0x4bc0000a, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"sub.ps",  "D,V,T",	0x46c00001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	I5	},
-{"sub.qh",  "X,Y,Q",	0x7820000a, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"suba.ob", "Y,Q",	0x78000036, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"suba.qh", "Y,Q",	0x78200036, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"subl.ob", "Y,Q",	0x78000436, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"subl.qh", "Y,Q",	0x78200436, 0xfc2007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"subu",    "d,v,t",	0x00000023, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"subu",    "d,v,I",	0,    (int) M_SUBU_I,	INSN_MACRO,		I1	},
-{"suspend", "",         0x42000022, 0xffffffff,	0,			V1	},
-{"suxc1",   "S,t(b)",   0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b,	I5|N55	},
-{"sw",      "t,o(b)",	0xac000000, 0xfc000000,	SM|RD_t|RD_b,		I1	},
-{"sw",      "t,A(b)",	0,    (int) M_SW_AB,	INSN_MACRO,		I1	},
-{"swc0",    "E,o(b)",	0xe0000000, 0xfc000000,	SM|RD_C0|RD_b,		I1	},
-{"swc0",    "E,A(b)",	0,    (int) M_SWC0_AB,	INSN_MACRO,		I1	},
-{"swc1",    "T,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	I1	},
-{"swc1",    "E,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	I1	},
-{"swc1",    "T,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		I1	},
-{"swc1",    "E,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		I1	},
-{"s.s",     "T,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	I1	}, /* swc1 */
-{"s.s",     "T,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		I1	},
-{"swc2",    "E,o(b)",	0xe8000000, 0xfc000000,	SM|RD_C2|RD_b,		I1	},
-{"swc2",    "E,A(b)",	0,    (int) M_SWC2_AB,	INSN_MACRO,		I1	},
-{"swc3",    "E,o(b)",	0xec000000, 0xfc000000,	SM|RD_C3|RD_b,		I1	},
-{"swc3",    "E,A(b)",	0,    (int) M_SWC3_AB,	INSN_MACRO,		I1	},
-{"swl",     "t,o(b)",	0xa8000000, 0xfc000000,	SM|RD_t|RD_b,		I1	},
-{"swl",     "t,A(b)",	0,    (int) M_SWL_AB,	INSN_MACRO,		I1	},
-{"scache",  "t,o(b)",	0xa8000000, 0xfc000000,	RD_t|RD_b,		I2	}, /* same */
-{"scache",  "t,A(b)",	0,    (int) M_SWL_AB,	INSN_MACRO,		I2	}, /* as swl */
-{"swr",     "t,o(b)",	0xb8000000, 0xfc000000,	SM|RD_t|RD_b,		I1	},
-{"swr",     "t,A(b)",	0,    (int) M_SWR_AB,	INSN_MACRO,		I1	},
-{"invalidate", "t,o(b)",0xb8000000, 0xfc000000,	RD_t|RD_b,		I2	}, /* same */
-{"invalidate", "t,A(b)",0,    (int) M_SWR_AB,	INSN_MACRO,		I2	}, /* as swr */
-{"swxc1",   "S,t(b)",   0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b,	I4	},
-{"sync",    "",		0x0000000f, 0xffffffff,	INSN_SYNC,		I2|G1	},
-{"sync.p",  "",		0x0000040f, 0xffffffff,	INSN_SYNC,		I2	},
-{"sync.l",  "",		0x0000000f, 0xffffffff,	INSN_SYNC,		I2	},
-{"synci",   "o(b)",	0x041f0000, 0xfc1f0000,	SM|RD_b,		I33	},
-{"syscall", "",		0x0000000c, 0xffffffff,	TRAP,			I1	},
-{"syscall", "B",	0x0000000c, 0xfc00003f,	TRAP,			I1	},
-{"teqi",    "s,j",	0x040c0000, 0xfc1f0000, RD_s|TRAP,		I2	},
-{"teq",	    "s,t",	0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP,		I2	},
-{"teq",	    "s,t,q",	0x00000034, 0xfc00003f, RD_s|RD_t|TRAP,		I2	},
-{"teq",     "s,j",	0x040c0000, 0xfc1f0000, RD_s|TRAP,		I2	}, /* teqi */
-{"teq",     "s,I",	0,    (int) M_TEQ_I,	INSN_MACRO,		I2	},
-{"tgei",    "s,j",	0x04080000, 0xfc1f0000, RD_s|TRAP,		I2	},
-{"tge",	    "s,t",	0x00000030, 0xfc00ffff,	RD_s|RD_t|TRAP,		I2	},
-{"tge",	    "s,t,q",	0x00000030, 0xfc00003f,	RD_s|RD_t|TRAP,		I2	},
-{"tge",     "s,j",	0x04080000, 0xfc1f0000, RD_s|TRAP,		I2	}, /* tgei */
-{"tge",	    "s,I",	0,    (int) M_TGE_I,    INSN_MACRO,		I2	},
-{"tgeiu",   "s,j",	0x04090000, 0xfc1f0000, RD_s|TRAP,		I2	},
-{"tgeu",    "s,t",	0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP,		I2	},
-{"tgeu",    "s,t,q",	0x00000031, 0xfc00003f, RD_s|RD_t|TRAP,		I2	},
-{"tgeu",    "s,j",	0x04090000, 0xfc1f0000, RD_s|TRAP,		I2	}, /* tgeiu */
-{"tgeu",    "s,I",	0,    (int) M_TGEU_I,	INSN_MACRO,		I2	},
-{"tlbp",    "",         0x42000008, 0xffffffff, INSN_TLB,       	I1   	},
-{"tlbr",    "",         0x42000001, 0xffffffff, INSN_TLB,       	I1   	},
-{"tlbwi",   "",         0x42000002, 0xffffffff, INSN_TLB,       	I1   	},
-{"tlbwr",   "",         0x42000006, 0xffffffff, INSN_TLB,       	I1   	},
-{"tlti",    "s,j",	0x040a0000, 0xfc1f0000,	RD_s|TRAP,		I2	},
-{"tlt",     "s,t",	0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP,		I2	},
-{"tlt",     "s,t,q",	0x00000032, 0xfc00003f, RD_s|RD_t|TRAP,		I2	},
-{"tlt",     "s,j",	0x040a0000, 0xfc1f0000,	RD_s|TRAP,		I2	}, /* tlti */
-{"tlt",     "s,I",	0,    (int) M_TLT_I,	INSN_MACRO,		I2	},
-{"tltiu",   "s,j",	0x040b0000, 0xfc1f0000, RD_s|TRAP,		I2	},
-{"tltu",    "s,t",	0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP,		I2	},
-{"tltu",    "s,t,q",	0x00000033, 0xfc00003f, RD_s|RD_t|TRAP,		I2	},
-{"tltu",    "s,j",	0x040b0000, 0xfc1f0000, RD_s|TRAP,		I2	}, /* tltiu */
-{"tltu",    "s,I",	0,    (int) M_TLTU_I,	INSN_MACRO,		I2	},
-{"tnei",    "s,j",	0x040e0000, 0xfc1f0000, RD_s|TRAP,		I2	},
-{"tne",     "s,t",	0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP,		I2	},
-{"tne",     "s,t,q",	0x00000036, 0xfc00003f, RD_s|RD_t|TRAP,		I2	},
-{"tne",     "s,j",	0x040e0000, 0xfc1f0000, RD_s|TRAP,		I2	}, /* tnei */
-{"tne",     "s,I",	0,    (int) M_TNE_I,	INSN_MACRO,		I2	},
-{"trunc.l.d", "D,S",	0x46200009, 0xffff003f, WR_D|RD_S|FP_D,		I3	},
-{"trunc.l.s", "D,S",	0x46000009, 0xffff003f,	WR_D|RD_S|FP_S,		I3	},
-{"trunc.w.d", "D,S",	0x4620000d, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
-{"trunc.w.d", "D,S,x",	0x4620000d, 0xffff003f, WR_D|RD_S|FP_D,		I2	},
-{"trunc.w.d", "D,S,t",	0,    (int) M_TRUNCWD,	INSN_MACRO,		I1	},
-{"trunc.w.s", "D,S",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		I2	},
-{"trunc.w.s", "D,S,x",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		I2	},
-{"trunc.w.s", "D,S,t",	0,    (int) M_TRUNCWS,	INSN_MACRO,		I1	},
-{"uld",     "t,o(b)",	0,    (int) M_ULD,	INSN_MACRO,		I3	},
-{"uld",     "t,A(b)",	0,    (int) M_ULD_A,	INSN_MACRO,		I3	},
-{"ulh",     "t,o(b)",	0,    (int) M_ULH,	INSN_MACRO,		I1	},
-{"ulh",     "t,A(b)",	0,    (int) M_ULH_A,	INSN_MACRO,		I1	},
-{"ulhu",    "t,o(b)",	0,    (int) M_ULHU,	INSN_MACRO,		I1	},
-{"ulhu",    "t,A(b)",	0,    (int) M_ULHU_A,	INSN_MACRO,		I1	},
-{"ulw",     "t,o(b)",	0,    (int) M_ULW,	INSN_MACRO,		I1	},
-{"ulw",     "t,A(b)",	0,    (int) M_ULW_A,	INSN_MACRO,		I1	},
-{"usd",     "t,o(b)",	0,    (int) M_USD,	INSN_MACRO,		I3	},
-{"usd",     "t,A(b)",	0,    (int) M_USD_A,	INSN_MACRO,		I3	},
-{"ush",     "t,o(b)",	0,    (int) M_USH,	INSN_MACRO,		I1	},
-{"ush",     "t,A(b)",	0,    (int) M_USH_A,	INSN_MACRO,		I1	},
-{"usw",     "t,o(b)",	0,    (int) M_USW,	INSN_MACRO,		I1	},
-{"usw",     "t,A(b)",	0,    (int) M_USW_A,	INSN_MACRO,		I1	},
-{"wach.ob", "Y",	0x7a00003e, 0xffff07ff,	WR_MACC|RD_S|FP_D,	MX|SB1	},
-{"wach.ob", "S",	0x4a00003e, 0xffff07ff,	RD_S,			N54	},
-{"wach.qh", "Y",	0x7a20003e, 0xffff07ff,	WR_MACC|RD_S|FP_D,	MX	},
-{"wacl.ob", "Y,Z",	0x7800003e, 0xffe007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX|SB1	},
-{"wacl.ob", "S,T",	0x4800003e, 0xffe007ff,	RD_S|RD_T,		N54	},
-{"wacl.qh", "Y,Z",	0x7820003e, 0xffe007ff,	WR_MACC|RD_S|RD_T|FP_D,	MX	},
-{"wait",    "",         0x42000020, 0xffffffff, TRAP,   		I3|I32	},
-{"wait",    "J",        0x42000020, 0xfe00003f, TRAP,   		I32|N55	},
-{"waiti",   "",		0x42000020, 0xffffffff,	TRAP,			L1	},
-{"wb", 	    "o(b)",	0xbc040000, 0xfc1f0000, SM|RD_b,		L1	},
-{"wrpgpr",  "d,w",	0x41c00000, 0xffe007ff, RD_t,			I33	},
-{"wsbh",    "d,w",	0x7c0000a0, 0xffe007ff,	WR_d|RD_t,		I33	},
-{"xor",     "d,v,t",	0x00000026, 0xfc0007ff,	WR_d|RD_s|RD_t,		I1	},
-{"xor",     "t,r,I",	0,    (int) M_XOR_I,	INSN_MACRO,		I1	},
-{"xor.ob",  "X,Y,Q",	0x7800000d, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX|SB1	},
-{"xor.ob",  "D,S,T",	0x4ac0000d, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"xor.ob",  "D,S,T[e]",	0x4800000d, 0xfe20003f,	WR_D|RD_S|RD_T,		N54	},
-{"xor.ob",  "D,S,k",	0x4bc0000d, 0xffe0003f,	WR_D|RD_S|RD_T,		N54	},
-{"xor.qh",  "X,Y,Q",	0x7820000d, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	MX	},
-{"xori",    "t,r,i",	0x38000000, 0xfc000000,	WR_t|RD_s,		I1	},
+{"standby", "",         0x42000021, 0xffffffff,	0,			0,		V1	},
+{"sub",     "d,v,t",	0x00000022, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"sub",     "d,v,I",	0,    (int) M_SUB_I,	INSN_MACRO,		0,		I1	},
+{"sub.d",   "D,V,T",	0x46200001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I1	},
+{"sub.s",   "D,V,T",	0x46000001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_S,	0,		I1	},
+{"sub.ob",  "X,Y,Q",	0x7800000a, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"sub.ob",  "D,S,T",	0x4ac0000a, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sub.ob",  "D,S,T[e]",	0x4800000a, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sub.ob",  "D,S,k",	0x4bc0000a, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"sub.ps",  "D,V,T",	0x46c00001, 0xffe0003f,	WR_D|RD_S|RD_T|FP_D,	0,		I5|I33	},
+{"sub.qh",  "X,Y,Q",	0x7820000a, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"suba.ob", "Y,Q",	0x78000036, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"suba.qh", "Y,Q",	0x78200036, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"subl.ob", "Y,Q",	0x78000436, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"subl.qh", "Y,Q",	0x78200436, 0xfc2007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"subu",    "d,v,t",	0x00000023, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"subu",    "d,v,I",	0,    (int) M_SUBU_I,	INSN_MACRO,		0,		I1	},
+{"suspend", "",         0x42000022, 0xffffffff,	0,			0,		V1	},
+{"suxc1",   "S,t(b)",   0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b,	0,		I5|I33|N55},
+{"sw",      "t,o(b)",	0xac000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"sw",      "t,A(b)",	0,    (int) M_SW_AB,	INSN_MACRO,		0,		I1	},
+{"swc0",    "E,o(b)",	0xe0000000, 0xfc000000,	SM|RD_C0|RD_b,		0,		I1	},
+{"swc0",    "E,A(b)",	0,    (int) M_SWC0_AB,	INSN_MACRO,		0,		I1	},
+{"swc1",    "T,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	0,		I1	},
+{"swc1",    "E,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	0,		I1	},
+{"swc1",    "T,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		0,		I1	},
+{"swc1",    "E,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		0,		I1	},
+{"s.s",     "T,o(b)",	0xe4000000, 0xfc000000,	SM|RD_T|RD_b|FP_S,	0,		I1	}, /* swc1 */
+{"s.s",     "T,A(b)",	0,    (int) M_SWC1_AB,	INSN_MACRO,		0,		I1	},
+{"swc2",    "E,o(b)",	0xe8000000, 0xfc000000,	SM|RD_C2|RD_b,		0,		I1	},
+{"swc2",    "E,A(b)",	0,    (int) M_SWC2_AB,	INSN_MACRO,		0,		I1	},
+{"swc3",    "E,o(b)",	0xec000000, 0xfc000000,	SM|RD_C3|RD_b,		0,		I1	},
+{"swc3",    "E,A(b)",	0,    (int) M_SWC3_AB,	INSN_MACRO,		0,		I1	},
+{"swl",     "t,o(b)",	0xa8000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"swl",     "t,A(b)",	0,    (int) M_SWL_AB,	INSN_MACRO,		0,		I1	},
+{"scache",  "t,o(b)",	0xa8000000, 0xfc000000,	RD_t|RD_b,		0,		I2	}, /* same */
+{"scache",  "t,A(b)",	0,    (int) M_SWL_AB,	INSN_MACRO,		0,		I2	}, /* as swl */
+{"swr",     "t,o(b)",	0xb8000000, 0xfc000000,	SM|RD_t|RD_b,		0,		I1	},
+{"swr",     "t,A(b)",	0,    (int) M_SWR_AB,	INSN_MACRO,		0,		I1	},
+{"invalidate", "t,o(b)",0xb8000000, 0xfc000000,	RD_t|RD_b,		0,		I2	}, /* same */
+{"invalidate", "t,A(b)",0,    (int) M_SWR_AB,	INSN_MACRO,		0,		I2	}, /* as swr */
+{"swxc1",   "S,t(b)",   0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b|FP_S,	0,		I4|I33	},
+{"sync",    "",		0x0000000f, 0xffffffff,	INSN_SYNC,		0,		I2|G1	},
+{"sync.p",  "",		0x0000040f, 0xffffffff,	INSN_SYNC,		0,		I2	},
+{"sync.l",  "",		0x0000000f, 0xffffffff,	INSN_SYNC,		0,		I2	},
+{"synci",   "o(b)",	0x041f0000, 0xfc1f0000,	SM|RD_b,		0,		I33	},
+{"syscall", "",		0x0000000c, 0xffffffff,	TRAP,			0,		I1	},
+{"syscall", "B",	0x0000000c, 0xfc00003f,	TRAP,			0,		I1	},
+{"teqi",    "s,j",	0x040c0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"teq",	    "s,t",	0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"teq",	    "s,t,q",	0x00000034, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"teq",     "s,j",	0x040c0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* teqi */
+{"teq",     "s,I",	0,    (int) M_TEQ_I,	INSN_MACRO,		0,		I2	},
+{"tgei",    "s,j",	0x04080000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"tge",	    "s,t",	0x00000030, 0xfc00ffff,	RD_s|RD_t|TRAP,		0,		I2	},
+{"tge",	    "s,t,q",	0x00000030, 0xfc00003f,	RD_s|RD_t|TRAP,		0,		I2	},
+{"tge",     "s,j",	0x04080000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* tgei */
+{"tge",	    "s,I",	0,    (int) M_TGE_I,    INSN_MACRO,		0,		I2	},
+{"tgeiu",   "s,j",	0x04090000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"tgeu",    "s,t",	0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"tgeu",    "s,t,q",	0x00000031, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"tgeu",    "s,j",	0x04090000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* tgeiu */
+{"tgeu",    "s,I",	0,    (int) M_TGEU_I,	INSN_MACRO,		0,		I2	},
+{"tlbp",    "",         0x42000008, 0xffffffff, INSN_TLB,       	0,		I1   	},
+{"tlbr",    "",         0x42000001, 0xffffffff, INSN_TLB,       	0,		I1   	},
+{"tlbwi",   "",         0x42000002, 0xffffffff, INSN_TLB,       	0,		I1   	},
+{"tlbwr",   "",         0x42000006, 0xffffffff, INSN_TLB,       	0,		I1   	},
+{"tlti",    "s,j",	0x040a0000, 0xfc1f0000,	RD_s|TRAP,		0,		I2	},
+{"tlt",     "s,t",	0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"tlt",     "s,t,q",	0x00000032, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"tlt",     "s,j",	0x040a0000, 0xfc1f0000,	RD_s|TRAP,		0,		I2	}, /* tlti */
+{"tlt",     "s,I",	0,    (int) M_TLT_I,	INSN_MACRO,		0,		I2	},
+{"tltiu",   "s,j",	0x040b0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"tltu",    "s,t",	0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"tltu",    "s,t,q",	0x00000033, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"tltu",    "s,j",	0x040b0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* tltiu */
+{"tltu",    "s,I",	0,    (int) M_TLTU_I,	INSN_MACRO,		0,		I2	},
+{"tnei",    "s,j",	0x040e0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	},
+{"tne",     "s,t",	0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP,		0,		I2	},
+{"tne",     "s,t,q",	0x00000036, 0xfc00003f, RD_s|RD_t|TRAP,		0,		I2	},
+{"tne",     "s,j",	0x040e0000, 0xfc1f0000, RD_s|TRAP,		0,		I2	}, /* tnei */
+{"tne",     "s,I",	0,    (int) M_TNE_I,	INSN_MACRO,		0,		I2	},
+{"trunc.l.d", "D,S",	0x46200009, 0xffff003f, WR_D|RD_S|FP_D,		0,		I3|I33	},
+{"trunc.l.s", "D,S",	0x46000009, 0xffff003f,	WR_D|RD_S|FP_S|FP_D,	0,		I3|I33	},
+{"trunc.w.d", "D,S",	0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"trunc.w.d", "D,S,x",	0x4620000d, 0xffff003f, WR_D|RD_S|FP_S|FP_D,	0,		I2	},
+{"trunc.w.d", "D,S,t",	0,    (int) M_TRUNCWD,	INSN_MACRO,		0,		I1	},
+{"trunc.w.s", "D,S",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I2	},
+{"trunc.w.s", "D,S,x",	0x4600000d, 0xffff003f,	WR_D|RD_S|FP_S,		0,		I2	},
+{"trunc.w.s", "D,S,t",	0,    (int) M_TRUNCWS,	INSN_MACRO,		0,		I1	},
+{"uld",     "t,o(b)",	0,    (int) M_ULD,	INSN_MACRO,		0,		I3	},
+{"uld",     "t,A(b)",	0,    (int) M_ULD_A,	INSN_MACRO,		0,		I3	},
+{"ulh",     "t,o(b)",	0,    (int) M_ULH,	INSN_MACRO,		0,		I1	},
+{"ulh",     "t,A(b)",	0,    (int) M_ULH_A,	INSN_MACRO,		0,		I1	},
+{"ulhu",    "t,o(b)",	0,    (int) M_ULHU,	INSN_MACRO,		0,		I1	},
+{"ulhu",    "t,A(b)",	0,    (int) M_ULHU_A,	INSN_MACRO,		0,		I1	},
+{"ulw",     "t,o(b)",	0,    (int) M_ULW,	INSN_MACRO,		0,		I1	},
+{"ulw",     "t,A(b)",	0,    (int) M_ULW_A,	INSN_MACRO,		0,		I1	},
+{"usd",     "t,o(b)",	0,    (int) M_USD,	INSN_MACRO,		0,		I3	},
+{"usd",     "t,A(b)",	0,    (int) M_USD_A,	INSN_MACRO,		0,		I3	},
+{"ush",     "t,o(b)",	0,    (int) M_USH,	INSN_MACRO,		0,		I1	},
+{"ush",     "t,A(b)",	0,    (int) M_USH_A,	INSN_MACRO,		0,		I1	},
+{"usw",     "t,o(b)",	0,    (int) M_USW,	INSN_MACRO,		0,		I1	},
+{"usw",     "t,A(b)",	0,    (int) M_USW_A,	INSN_MACRO,		0,		I1	},
+{"wach.ob", "Y",	0x7a00003e, 0xffff07ff,	RD_S|FP_D,		WR_MACC,	MX|SB1	},
+{"wach.ob", "S",	0x4a00003e, 0xffff07ff,	RD_S,			0,		N54	},
+{"wach.qh", "Y",	0x7a20003e, 0xffff07ff,	RD_S|FP_D,		WR_MACC,	MX	},
+{"wacl.ob", "Y,Z",	0x7800003e, 0xffe007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX|SB1	},
+{"wacl.ob", "S,T",	0x4800003e, 0xffe007ff,	RD_S|RD_T,		0,		N54	},
+{"wacl.qh", "Y,Z",	0x7820003e, 0xffe007ff,	RD_S|RD_T|FP_D,		WR_MACC,	MX	},
+{"wait",    "",         0x42000020, 0xffffffff, TRAP,   		0,		I3|I32	},
+{"wait",    "J",        0x42000020, 0xfe00003f, TRAP,   		0,		I32|N55	},
+{"waiti",   "",		0x42000020, 0xffffffff,	TRAP,			0,		L1	},
+{"wrpgpr",  "d,w",	0x41c00000, 0xffe007ff, RD_t,			0,		I33	},
+{"wsbh",    "d,w",	0x7c0000a0, 0xffe007ff,	WR_d|RD_t,		0,		I33	},
+{"xor",     "d,v,t",	0x00000026, 0xfc0007ff,	WR_d|RD_s|RD_t,		0,		I1	},
+{"xor",     "t,r,I",	0,    (int) M_XOR_I,	INSN_MACRO,		0,		I1	},
+{"xor.ob",  "X,Y,Q",	0x7800000d, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX|SB1	},
+{"xor.ob",  "D,S,T",	0x4ac0000d, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"xor.ob",  "D,S,T[e]",	0x4800000d, 0xfe20003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"xor.ob",  "D,S,k",	0x4bc0000d, 0xffe0003f,	WR_D|RD_S|RD_T,		0,		N54	},
+{"xor.qh",  "X,Y,Q",	0x7820000d, 0xfc20003f,	WR_D|RD_S|RD_T|FP_D,	0,		MX	},
+{"xori",    "t,r,i",	0x38000000, 0xfc000000,	WR_t|RD_s,		0,		I1	},
+{"yield",   "s",	0x7c000009, 0xfc1fffff, TRAP|RD_s,		0,		MT32	},
+{"yield",   "d,s",	0x7c000009, 0xfc1f07ff, TRAP|WR_d|RD_s,		0,		MT32	},
+
+/* User Defined Instruction.  */
+{"udi0",     "s,t,d,+1",0x70000010, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi0",     "s,t,+2",	0x70000010, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi0",     "s,+3",	0x70000010, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi0",     "+4",	0x70000010, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi1",     "s,t,d,+1",0x70000011, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi1",     "s,t,+2",	0x70000011, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi1",     "s,+3",	0x70000011, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi1",     "+4",	0x70000011, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi2",     "s,t,d,+1",0x70000012, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi2",     "s,t,+2",	0x70000012, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi2",     "s,+3",	0x70000012, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi2",     "+4",	0x70000012, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi3",     "s,t,d,+1",0x70000013, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi3",     "s,t,+2",	0x70000013, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi3",     "s,+3",	0x70000013, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi3",     "+4",	0x70000013, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi4",     "s,t,d,+1",0x70000014, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi4",     "s,t,+2",	0x70000014, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi4",     "s,+3",	0x70000014, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi4",     "+4",	0x70000014, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi5",     "s,t,d,+1",0x70000015, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi5",     "s,t,+2",	0x70000015, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi5",     "s,+3",	0x70000015, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi5",     "+4",	0x70000015, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi6",     "s,t,d,+1",0x70000016, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi6",     "s,t,+2",	0x70000016, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi6",     "s,+3",	0x70000016, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi6",     "+4",	0x70000016, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi7",     "s,t,d,+1",0x70000017, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi7",     "s,t,+2",	0x70000017, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi7",     "s,+3",	0x70000017, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi7",     "+4",	0x70000017, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi8",     "s,t,d,+1",0x70000018, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi8",     "s,t,+2",	0x70000018, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi8",     "s,+3",	0x70000018, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi8",     "+4",	0x70000018, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi9",     "s,t,d,+1",0x70000019, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi9",      "s,t,+2",	0x70000019, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi9",     "s,+3",	0x70000019, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi9",     "+4",	0x70000019, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi10",    "s,t,d,+1",0x7000001a, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi10",    "s,t,+2",	0x7000001a, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi10",    "s,+3",	0x7000001a, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi10",    "+4",	0x7000001a, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi11",    "s,t,d,+1",0x7000001b, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi11",    "s,t,+2",	0x7000001b, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi11",    "s,+3",	0x7000001b, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi11",    "+4",	0x7000001b, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi12",    "s,t,d,+1",0x7000001c, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi12",    "s,t,+2",	0x7000001c, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi12",    "s,+3",	0x7000001c, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi12",    "+4",	0x7000001c, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi13",    "s,t,d,+1",0x7000001d, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi13",    "s,t,+2",	0x7000001d, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi13",    "s,+3",	0x7000001d, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi13",    "+4",	0x7000001d, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi14",    "s,t,d,+1",0x7000001e, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi14",    "s,t,+2",	0x7000001e, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi14",    "s,+3",	0x7000001e, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi14",    "+4",	0x7000001e, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi15",    "s,t,d,+1",0x7000001f, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi15",    "s,t,+2",	0x7000001f, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi15",    "s,+3",	0x7000001f, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
+{"udi15",    "+4",	0x7000001f, 0xfc00003f,	WR_d|RD_s|RD_t,		0,		I33	},
 
 /* Coprocessor 2 move/branch operations overlap with VR5400 .ob format
    instructions so they are here for the latters to take precedence.  */
-{"bc2f",    "p",	0x49000000, 0xffff0000,	CBD|RD_CC,		I1	},
-{"bc2fl",   "p",	0x49020000, 0xffff0000,	CBL|RD_CC,		I2|T3	},
-{"bc2t",    "p",	0x49010000, 0xffff0000,	CBD|RD_CC,		I1	},
-{"bc2tl",   "p",	0x49030000, 0xffff0000,	CBL|RD_CC,		I2|T3	},
-{"cfc2",    "t,G",	0x48400000, 0xffe007ff,	LCD|WR_t|RD_C2,		I1	},
-{"ctc2",    "t,G",	0x48c00000, 0xffe007ff,	COD|RD_t|WR_CC,		I1	},
-{"dmfc2",   "t,G",	0x48200000, 0xffe007ff,	LCD|WR_t|RD_C2,		I3	},
-{"dmfc2",   "t,G,H",	0x48200000, 0xffe007f8,	LCD|WR_t|RD_C2,		I64	},
-{"dmtc2",   "t,G",	0x48a00000, 0xffe007ff,	COD|RD_t|WR_C2|WR_CC,	I3	},
-{"dmtc2",   "t,G,H",	0x48a00000, 0xffe007f8,	COD|RD_t|WR_C2|WR_CC,	I64	},
-{"mfc2",    "t,G",	0x48000000, 0xffe007ff,	LCD|WR_t|RD_C2,		I1	},
-{"mfc2",    "t,G,H",	0x48000000, 0xffe007f8,	LCD|WR_t|RD_C2,		I32	},
-{"mfhc2",   "t,i",	0x48600000, 0xffe00000,	LCD|WR_t|RD_C2,		I33	},
-{"mtc2",    "t,G",	0x48800000, 0xffe007ff,	COD|RD_t|WR_C2|WR_CC,	I1	},
-{"mtc2",    "t,G,H",	0x48800000, 0xffe007f8,	COD|RD_t|WR_C2|WR_CC,	I32	},
-{"mthc2",   "t,i",	0x48e00000, 0xffe00000,	COD|RD_t|WR_C2|WR_CC,	I33	},
+{"bc2f",    "p",	0x49000000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc2f",    "N,p",	0x49000000, 0xffe30000,	CBD|RD_CC,		0,		I32	},
+{"bc2fl",   "p",	0x49020000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"bc2fl",   "N,p",	0x49020000, 0xffe30000,	CBL|RD_CC,		0,		I32	},
+{"bc2t",    "p",	0x49010000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc2t",    "N,p",	0x49010000, 0xffe30000,	CBD|RD_CC,		0,		I32	},
+{"bc2tl",   "p",	0x49030000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"bc2tl",   "N,p",	0x49030000, 0xffe30000,	CBL|RD_CC,		0,		I32	},
+{"cfc2",    "t,G",	0x48400000, 0xffe007ff,	LCD|WR_t|RD_C2,		0,		I1	},
+{"ctc2",    "t,G",	0x48c00000, 0xffe007ff,	COD|RD_t|WR_CC,		0,		I1	},
+{"dmfc2",   "t,G",	0x48200000, 0xffe007ff,	LCD|WR_t|RD_C2,		0,		I3	},
+{"dmfc2",   "t,G,H",	0x48200000, 0xffe007f8,	LCD|WR_t|RD_C2,		0,		I64	},
+{"dmtc2",   "t,G",	0x48a00000, 0xffe007ff,	COD|RD_t|WR_C2|WR_CC,	0,		I3	},
+{"dmtc2",   "t,G,H",	0x48a00000, 0xffe007f8,	COD|RD_t|WR_C2|WR_CC,	0,		I64	},
+{"mfc2",    "t,G",	0x48000000, 0xffe007ff,	LCD|WR_t|RD_C2,		0,		I1	},
+{"mfc2",    "t,G,H",	0x48000000, 0xffe007f8,	LCD|WR_t|RD_C2,		0,		I32	},
+{"mfhc2",   "t,G",	0x48600000, 0xffe007ff,	LCD|WR_t|RD_C2,		0,		I33	},
+{"mfhc2",   "t,G,H",	0x48600000, 0xffe007f8,	LCD|WR_t|RD_C2,		0,		I33	},
+{"mfhc2",   "t,i",	0x48600000, 0xffe00000,	LCD|WR_t|RD_C2,		0,		I33	},
+{"mtc2",    "t,G",	0x48800000, 0xffe007ff,	COD|RD_t|WR_C2|WR_CC,	0,		I1	},
+{"mtc2",    "t,G,H",	0x48800000, 0xffe007f8,	COD|RD_t|WR_C2|WR_CC,	0,		I32	},
+{"mthc2",   "t,G",	0x48e00000, 0xffe007ff,	COD|RD_t|WR_C2|WR_CC,	0,		I33	},
+{"mthc2",   "t,G,H",	0x48e00000, 0xffe007f8,	COD|RD_t|WR_C2|WR_CC,	0,		I33	},
+{"mthc2",   "t,i",	0x48e00000, 0xffe00000,	COD|RD_t|WR_C2|WR_CC,	0,		I33	},
+
+/* Coprocessor 3 move/branch operations overlap with MIPS IV COP1X
+   instructions, so they are here for the latters to take precedence.  */
+{"bc3f",    "p",	0x4d000000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc3fl",   "p",	0x4d020000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"bc3t",    "p",	0x4d010000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc3tl",   "p",	0x4d030000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"cfc3",    "t,G",	0x4c400000, 0xffe007ff,	LCD|WR_t|RD_C3,		0,		I1	},
+{"ctc3",    "t,G",	0x4cc00000, 0xffe007ff,	COD|RD_t|WR_CC,		0,		I1	},
+{"dmfc3",   "t,G",	0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, 	0,		I3	},
+{"dmtc3",   "t,G",	0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC,	0,		I3	},
+{"mfc3",    "t,G",	0x4c000000, 0xffe007ff,	LCD|WR_t|RD_C3,		0,		I1	},
+{"mfc3",    "t,G,H",    0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, 	0,		I32     },
+{"mtc3",    "t,G",	0x4c800000, 0xffe007ff,	COD|RD_t|WR_C3|WR_CC,	0,		I1	},
+{"mtc3",    "t,G,H",    0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC,   0,		I32     },
 
 /* No hazard protection on coprocessor instructions--they shouldn't
    change the state of the processor and if they do it's up to the
    user to put in nops as necessary.  These are at the end so that the
    disassembler recognizes more specific versions first.  */
-{"c0",      "C",	0x42000000, 0xfe000000,	0,			I1	},
-{"c1",      "C",	0x46000000, 0xfe000000,	0,			I1	},
-{"c2",      "C",	0x4a000000, 0xfe000000,	0,			I1	},
-{"c3",      "C",	0x4e000000, 0xfe000000,	0,			I1	},
-{"cop0",     "C",	0,    (int) M_COP0,	INSN_MACRO,		I1	},
-{"cop1",     "C",	0,    (int) M_COP1,	INSN_MACRO,		I1	},
-{"cop2",     "C",	0,    (int) M_COP2,	INSN_MACRO,		I1	},
-{"cop3",     "C",	0,    (int) M_COP3,	INSN_MACRO,		I1	},
-
+{"c0",      "C",	0x42000000, 0xfe000000,	0,			0,		I1	},
+{"c1",      "C",	0x46000000, 0xfe000000,	0,			0,		I1	},
+{"c2",      "C",	0x4a000000, 0xfe000000,	0,			0,		I1	},
+{"c3",      "C",	0x4e000000, 0xfe000000,	0,			0,		I1	},
+{"cop0",     "C",	0,    (int) M_COP0,	INSN_MACRO,		0,		I1	},
+{"cop1",     "C",	0,    (int) M_COP1,	INSN_MACRO,		0,		I1	},
+{"cop2",     "C",	0,    (int) M_COP2,	INSN_MACRO,		0,		I1	},
+{"cop3",     "C",	0,    (int) M_COP3,	INSN_MACRO,		0,		I1	},
   /* Conflicts with the 4650's "mul" instruction.  Nobody's using the
      4010 any more, so move this insn out of the way.  If the object
      format gave us more info, we could do this right.  */
-{"addciu",  "t,r,j",	0x70000000, 0xfc000000,	WR_t|RD_s,		L1	},
+{"addciu",  "t,r,j",	0x70000000, 0xfc000000,	WR_t|RD_s,		0,		L1	},
+/* MIPS DSP ASE */
+{"absq_s.ph", "d,t",	0x7c000252, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"absq_s.pw", "d,t",	0x7c000456, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"absq_s.qh", "d,t",	0x7c000256, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"absq_s.w", "d,t",	0x7c000452, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"addq.ph", "d,s,t",	0x7c000290, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addq.pw", "d,s,t",	0x7c000494, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addq.qh", "d,s,t",	0x7c000294, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addq_s.ph", "d,s,t",	0x7c000390, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addq_s.pw", "d,s,t",	0x7c000594, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addq_s.qh", "d,s,t",	0x7c000394, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addq_s.w", "d,s,t",	0x7c000590, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addsc",   "d,s,t",	0x7c000410, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addu.ob", "d,s,t",	0x7c000014, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addu.qb", "d,s,t",	0x7c000010, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addu_s.ob", "d,s,t",	0x7c000114, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"addu_s.qb", "d,s,t",	0x7c000110, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"addwc",   "d,s,t",	0x7c000450, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"bitrev",  "d,t",	0x7c0006d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"bposge32", "p",	0x041c0000, 0xffff0000, CBD,			0,		D32	},
+{"bposge64", "p",	0x041d0000, 0xffff0000, CBD,			0,		D64	},
+{"cmp.eq.ph", "s,t",	0x7c000211, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmp.eq.pw", "s,t",	0x7c000415, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmp.eq.qh", "s,t",	0x7c000215, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpgu.eq.ob", "d,s,t", 0x7c000115, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"cmpgu.eq.qb", "d,s,t", 0x7c000111, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"cmpgu.le.ob", "d,s,t", 0x7c000195, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"cmpgu.le.qb", "d,s,t", 0x7c000191, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"cmpgu.lt.ob", "d,s,t", 0x7c000155, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"cmpgu.lt.qb", "d,s,t", 0x7c000151, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"cmp.le.ph", "s,t",	0x7c000291, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmp.le.pw", "s,t",	0x7c000495, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmp.le.qh", "s,t",	0x7c000295, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmp.lt.ph", "s,t",	0x7c000251, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmp.lt.pw", "s,t",	0x7c000455, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmp.lt.qh", "s,t",	0x7c000255, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpu.eq.ob", "s,t",	0x7c000015, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpu.eq.qb", "s,t",	0x7c000011, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmpu.le.ob", "s,t",	0x7c000095, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpu.le.qb", "s,t",	0x7c000091, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"cmpu.lt.ob", "s,t",	0x7c000055, 0xfc00ffff, RD_s|RD_t,		0,		D64	},
+{"cmpu.lt.qb", "s,t",	0x7c000051, 0xfc00ffff, RD_s|RD_t,		0,		D32	},
+{"dextpdp", "t,7,6",	0x7c0002bc, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA,	0,		D64	},
+{"dextpdpv", "t,7,s",	0x7c0002fc, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0,		D64	},
+{"dextp",   "t,7,6",	0x7c0000bc, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextpv",  "t,7,s",	0x7c0000fc, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextr.l", "t,7,6",	0x7c00043c, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_r.l", "t,7,6",	0x7c00053c, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_rs.l", "t,7,6",	0x7c0005bc, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_rs.w", "t,7,6",	0x7c0001bc, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_r.w", "t,7,6",	0x7c00013c, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextr_s.h", "t,7,6",	0x7c0003bc, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dextrv.l", "t,7,s",	0x7c00047c, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextrv_r.l", "t,7,s",	0x7c00057c, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextrv_rs.l", "t,7,s", 0x7c0005fc, 0xfc00e7ff, WR_t|RD_a|RD_s,	0,		D64	},
+{"dextrv_rs.w", "t,7,s", 0x7c0001fc, 0xfc00e7ff, WR_t|RD_a|RD_s,	0,		D64	},
+{"dextrv_r.w", "t,7,s",	0x7c00017c, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextrv_s.h", "t,7,s",	0x7c0003fc, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextrv.w", "t,7,s",	0x7c00007c, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D64	},
+{"dextr.w", "t,7,6",	0x7c00003c, 0xfc00e7ff, WR_t|RD_a,		0,		D64	},
+{"dinsv",   "t,s",	0x7c00000d, 0xfc00ffff, WR_t|RD_s,		0,		D64	},
+{"dmadd",   "7,s,t",	0x7c000674, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dmaddu",  "7,s,t",	0x7c000774, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dmsub",   "7,s,t",	0x7c0006f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dmsubu",  "7,s,t",	0x7c0007f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dmthlip", "s,7",	0x7c0007fc, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA,	0,		D64	},
+{"dpaq_sa.l.pw", "7,s,t", 0x7c000334, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpaq_sa.l.w", "7,s,t", 0x7c000330, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpaq_s.w.ph", "7,s,t", 0x7c000130, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpaq_s.w.qh", "7,s,t", 0x7c000134, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpau.h.obl", "7,s,t",	0x7c0000f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpau.h.obr", "7,s,t",	0x7c0001f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpau.h.qbl", "7,s,t",	0x7c0000f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpau.h.qbr", "7,s,t",	0x7c0001f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpsq_sa.l.pw", "7,s,t", 0x7c000374, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpsq_sa.l.w", "7,s,t", 0x7c000370, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpsq_s.w.ph", "7,s,t", 0x7c000170, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpsq_s.w.qh", "7,s,t", 0x7c000174, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpsu.h.obl", "7,s,t",	0x7c0002f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpsu.h.obr", "7,s,t",	0x7c0003f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"dpsu.h.qbl", "7,s,t",	0x7c0002f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dpsu.h.qbr", "7,s,t",	0x7c0003f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"dshilo",  "7,:",	0x7c0006bc, 0xfc07e7ff, MOD_a,			0,		D64	},
+{"dshilov", "7,s",	0x7c0006fc, 0xfc1fe7ff, MOD_a|RD_s,		0,		D64	},
+{"extpdp",  "t,7,6",	0x7c0002b8, 0xfc00e7ff, WR_t|RD_a|DSP_VOLA,	0,		D32	},
+{"extpdpv", "t,7,s",	0x7c0002f8, 0xfc00e7ff, WR_t|RD_a|RD_s|DSP_VOLA, 0,		D32	},
+{"extp",    "t,7,6",	0x7c0000b8, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"extpv",   "t,7,s",	0x7c0000f8, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extr_rs.w", "t,7,6",	0x7c0001b8, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"extr_r.w", "t,7,6",	0x7c000138, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"extr_s.h", "t,7,6",	0x7c0003b8, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"extrv_rs.w", "t,7,s",	0x7c0001f8, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extrv_r.w", "t,7,s",	0x7c000178, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extrv_s.h", "t,7,s",	0x7c0003f8, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extrv.w", "t,7,s",	0x7c000078, 0xfc00e7ff, WR_t|RD_a|RD_s,		0,		D32	},
+{"extr.w",  "t,7,6",	0x7c000038, 0xfc00e7ff, WR_t|RD_a,		0,		D32	},
+{"insv",    "t,s",	0x7c00000c, 0xfc00ffff, WR_t|RD_s,		0,		D32	},
+{"lbux",    "d,t(b)",	0x7c00018a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		D32	},
+{"ldx",     "d,t(b)",	0x7c00020a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		D64	},
+{"lhx",     "d,t(b)",	0x7c00010a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		D32	},
+{"lwx",     "d,t(b)",	0x7c00000a, 0xfc0007ff, LDD|WR_d|RD_t|RD_b,	0,		D32	},
+{"maq_sa.w.phl", "7,s,t", 0x7c000430, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"maq_sa.w.phr", "7,s,t", 0x7c0004b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"maq_sa.w.qhll", "7,s,t", 0x7c000434, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_sa.w.qhlr", "7,s,t", 0x7c000474, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_sa.w.qhrl", "7,s,t", 0x7c0004b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_sa.w.qhrr", "7,s,t", 0x7c0004f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.l.pwl", "7,s,t", 0x7c000734, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.l.pwr", "7,s,t", 0x7c0007b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.w.phl", "7,s,t", 0x7c000530, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"maq_s.w.phr", "7,s,t", 0x7c0005b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"maq_s.w.qhll", "7,s,t", 0x7c000534, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.w.qhlr", "7,s,t", 0x7c000574, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.w.qhrl", "7,s,t", 0x7c0005b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"maq_s.w.qhrr", "7,s,t", 0x7c0005f4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"modsub",  "d,s,t",	0x7c000490, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"mthlip",  "s,7",	0x7c0007f8, 0xfc1fe7ff, RD_s|MOD_a|DSP_VOLA,	0,		D32	},
+{"muleq_s.pw.qhl", "d,s,t", 0x7c000714, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D64	},
+{"muleq_s.pw.qhr", "d,s,t", 0x7c000754, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D64	},
+{"muleq_s.w.phl", "d,s,t", 0x7c000710, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D32	},
+{"muleq_s.w.phr", "d,s,t", 0x7c000750, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D32	},
+{"muleu_s.ph.qbl", "d,s,t", 0x7c000190, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D32	},
+{"muleu_s.ph.qbr", "d,s,t", 0x7c0001d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D32	},
+{"muleu_s.qh.obl", "d,s,t", 0x7c000194, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D64	},
+{"muleu_s.qh.obr", "d,s,t", 0x7c0001d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,		D64	},
+{"mulq_rs.ph", "d,s,t",	0x7c0007d0, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO,	0,		D32	},
+{"mulq_rs.qh", "d,s,t",	0x7c0007d4, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO,	0,		D64	},
+{"mulsaq_s.l.pw", "7,s,t", 0x7c0003b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"mulsaq_s.w.ph", "7,s,t", 0x7c0001b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D32	},
+{"mulsaq_s.w.qh", "7,s,t", 0x7c0001b4, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,		D64	},
+{"packrl.ph", "d,s,t",	0x7c000391, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"packrl.pw", "d,s,t",	0x7c000395, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"pick.ob", "d,s,t",	0x7c0000d5, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"pick.ph", "d,s,t",	0x7c0002d1, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"pick.pw", "d,s,t",	0x7c0004d5, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"pick.qb", "d,s,t",	0x7c0000d1, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"pick.qh", "d,s,t",	0x7c0002d5, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"preceq.pw.qhla", "d,t", 0x7c000396, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.pw.qhl", "d,t", 0x7c000316, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.pw.qhra", "d,t", 0x7c0003d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.pw.qhr", "d,t", 0x7c000356, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.s.l.pwl", "d,t", 0x7c000516, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.s.l.pwr", "d,t", 0x7c000556, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precequ.ph.qbla", "d,t", 0x7c000192, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"precequ.ph.qbl", "d,t", 0x7c000112, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"precequ.ph.qbra", "d,t", 0x7c0001d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"precequ.ph.qbr", "d,t", 0x7c000152, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"precequ.pw.qhla", "d,t", 0x7c000196, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precequ.pw.qhl", "d,t", 0x7c000116, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precequ.pw.qhra", "d,t", 0x7c0001d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precequ.pw.qhr", "d,t", 0x7c000156, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceq.w.phl", "d,t",	0x7c000312, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceq.w.phr", "d,t",	0x7c000352, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.ph.qbla", "d,t", 0x7c000792, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.ph.qbl", "d,t", 0x7c000712, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.ph.qbra", "d,t", 0x7c0007d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.ph.qbr", "d,t", 0x7c000752, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"preceu.qh.obla", "d,t", 0x7c000796, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceu.qh.obl", "d,t", 0x7c000716, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceu.qh.obra", "d,t", 0x7c0007d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"preceu.qh.obr", "d,t", 0x7c000756, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"precrq.ob.qh", "d,s,t", 0x7c000315, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrq.ph.w", "d,s,t", 0x7c000511, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"precrq.pw.l", "d,s,t", 0x7c000715, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrq.qb.ph", "d,s,t", 0x7c000311, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"precrq.qh.pw", "d,s,t", 0x7c000515, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrq_rs.ph.w", "d,s,t", 0x7c000551, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"precrq_rs.qh.pw", "d,s,t", 0x7c000555, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrqu_s.ob.qh", "d,s,t", 0x7c0003d5, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D64	},
+{"precrqu_s.qb.ph", "d,s,t", 0x7c0003d1, 0xfc0007ff, WR_d|RD_s|RD_t,	0,		D32	},
+{"raddu.l.ob", "d,s",	0x7c000514, 0xfc1f07ff, WR_d|RD_s,		0,		D64	},
+{"raddu.w.qb", "d,s",	0x7c000510, 0xfc1f07ff, WR_d|RD_s,		0,		D32	},
+{"rddsp",   "d",	0x7fff04b8, 0xffff07ff, WR_d,			0,		D32	},
+{"rddsp",   "d,'",	0x7c0004b8, 0xffc007ff, WR_d,			0,		D32	},
+{"repl.ob", "d,5",	0x7c000096, 0xff0007ff, WR_d,			0,		D64	},
+{"repl.ph", "d,@",	0x7c000292, 0xfc0007ff, WR_d,			0,		D32	},
+{"repl.pw", "d,@",	0x7c000496, 0xfc0007ff, WR_d,			0,		D64	},
+{"repl.qb", "d,5",	0x7c000092, 0xff0007ff, WR_d,			0,		D32	},
+{"repl.qh", "d,@",	0x7c000296, 0xfc0007ff, WR_d,			0,		D64	},
+{"replv.ob", "d,t",	0x7c0000d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"replv.ph", "d,t",	0x7c0002d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"replv.pw", "d,t",	0x7c0004d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"replv.qb", "d,t",	0x7c0000d2, 0xffe007ff, WR_d|RD_t,		0,		D32	},
+{"replv.qh", "d,t",	0x7c0002d6, 0xffe007ff, WR_d|RD_t,		0,		D64	},
+{"shilo",   "7,0",	0x7c0006b8, 0xfc0fe7ff, MOD_a,			0,		D32	},
+{"shilov",  "7,s",	0x7c0006f8, 0xfc1fe7ff, MOD_a|RD_s,		0,		D32	},
+{"shll.ob", "d,t,3",	0x7c000017, 0xff0007ff, WR_d|RD_t,		0,		D64	},
+{"shll.ph", "d,t,4",	0x7c000213, 0xfe0007ff, WR_d|RD_t,		0,		D32	},
+{"shll.pw", "d,t,6",	0x7c000417, 0xfc0007ff, WR_d|RD_t,		0,		D64	},
+{"shll.qb", "d,t,3",	0x7c000013, 0xff0007ff, WR_d|RD_t,		0,		D32	},
+{"shll.qh", "d,t,4",	0x7c000217, 0xfe0007ff, WR_d|RD_t,		0,		D64	},
+{"shll_s.ph", "d,t,4",	0x7c000313, 0xfe0007ff, WR_d|RD_t,		0,		D32	},
+{"shll_s.pw", "d,t,6",	0x7c000517, 0xfc0007ff, WR_d|RD_t,		0,		D64	},
+{"shll_s.qh", "d,t,4",	0x7c000317, 0xfe0007ff, WR_d|RD_t,		0,		D64	},
+{"shll_s.w", "d,t,6",	0x7c000513, 0xfc0007ff, WR_d|RD_t,		0,		D32	},
+{"shllv.ob", "d,t,s",	0x7c000097, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv.ph", "d,t,s",	0x7c000293, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shllv.pw", "d,t,s",	0x7c000497, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv.qb", "d,t,s",	0x7c000093, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shllv.qh", "d,t,s",	0x7c000297, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv_s.ph", "d,t,s",	0x7c000393, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shllv_s.pw", "d,t,s",	0x7c000597, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv_s.qh", "d,t,s",	0x7c000397, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shllv_s.w", "d,t,s",	0x7c000593, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shra.ph", "d,t,4",	0x7c000253, 0xfe0007ff, WR_d|RD_t,		0,		D32	},
+{"shra.pw", "d,t,6",	0x7c000457, 0xfc0007ff, WR_d|RD_t,		0,		D64	},
+{"shra.qh", "d,t,4",	0x7c000257, 0xfe0007ff, WR_d|RD_t,		0,		D64	},
+{"shra_r.ph", "d,t,4",	0x7c000353, 0xfe0007ff, WR_d|RD_t,		0,		D32	},
+{"shra_r.pw", "d,t,6",	0x7c000557, 0xfc0007ff, WR_d|RD_t,		0,		D64	},
+{"shra_r.qh", "d,t,4",	0x7c000357, 0xfe0007ff, WR_d|RD_t,		0,		D64	},
+{"shra_r.w", "d,t,6",	0x7c000553, 0xfc0007ff, WR_d|RD_t,		0,		D32	},
+{"shrav.ph", "d,t,s",	0x7c0002d3, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shrav.pw", "d,t,s",	0x7c0004d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrav.qh", "d,t,s",	0x7c0002d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrav_r.ph", "d,t,s",	0x7c0003d3, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shrav_r.pw", "d,t,s",	0x7c0005d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrav_r.qh", "d,t,s",	0x7c0003d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrav_r.w", "d,t,s",	0x7c0005d3, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"shrl.ob", "d,t,3",	0x7c000057, 0xff0007ff, WR_d|RD_t,		0,		D64	},
+{"shrl.qb", "d,t,3",	0x7c000053, 0xff0007ff, WR_d|RD_t,		0,		D32	},
+{"shrlv.ob", "d,t,s",	0x7c0000d7, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"shrlv.qb", "d,t,s",	0x7c0000d3, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subq.ph", "d,s,t",	0x7c0002d0, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subq.pw", "d,s,t",	0x7c0004d4, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subq.qh", "d,s,t",	0x7c0002d4, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subq_s.ph", "d,s,t",	0x7c0003d0, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subq_s.pw", "d,s,t",	0x7c0005d4, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subq_s.qh", "d,s,t",	0x7c0003d4, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subq_s.w", "d,s,t",	0x7c0005d0, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subu.ob", "d,s,t",	0x7c000054, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subu.qb", "d,s,t",	0x7c000050, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"subu_s.ob", "d,s,t",	0x7c000154, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D64	},
+{"subu_s.qb", "d,s,t",	0x7c000150, 0xfc0007ff, WR_d|RD_s|RD_t,		0,		D32	},
+{"wrdsp",   "s",	0x7c1ffcf8, 0xfc1fffff, RD_s|DSP_VOLA,		0,		D32	},
+{"wrdsp",   "s,8",	0x7c0004f8, 0xfc1e07ff, RD_s|DSP_VOLA,		0,		D32	},
+/* MIPS DSP ASE Rev2 */
+{"absq_s.qb", "d,t",	0x7c000052, 0xffe007ff, WR_d|RD_t,              0,              D33	},
+{"addu.ph", "d,s,t",	0x7c000210, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"addu_s.ph", "d,s,t",	0x7c000310, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"adduh.qb", "d,s,t",	0x7c000018, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"adduh_r.qb", "d,s,t",	0x7c000098, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"append",  "t,s,h",	0x7c000031, 0xfc0007ff, WR_t|RD_t|RD_s,         0,              D33	},
+{"balign",  "t,s,I",	0,    (int) M_BALIGN,	INSN_MACRO,             0,              D33	},
+{"balign",  "t,s,2",	0x7c000431, 0xfc00e7ff, WR_t|RD_t|RD_s,         0,              D33	},
+{"cmpgdu.eq.qb", "d,s,t", 0x7c000611, 0xfc0007ff, WR_d|RD_s|RD_t,       0,              D33	},
+{"cmpgdu.lt.qb", "d,s,t", 0x7c000651, 0xfc0007ff, WR_d|RD_s|RD_t,       0,              D33	},
+{"cmpgdu.le.qb", "d,s,t", 0x7c000691, 0xfc0007ff, WR_d|RD_s|RD_t,       0,              D33	},
+{"dpa.w.ph", "7,s,t",	0x7c000030, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"dps.w.ph", "7,s,t",	0x7c000070, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"mul.ph",  "d,s,t",	0x7c000318, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mul_s.ph", "d,s,t",	0x7c000398, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mulq_rs.w", "d,s,t",	0x7c0005d8, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mulq_s.ph", "d,s,t",	0x7c000790, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mulq_s.w", "d,s,t",	0x7c000598, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, 0,              D33	},
+{"mulsa.w.ph", "7,s,t",	0x7c0000b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,        0,              D33	},
+{"precr.qb.ph", "d,s,t", 0x7c000351, 0xfc0007ff, WR_d|RD_s|RD_t,        0,              D33	},
+{"precr_sra.ph.w", "t,s,h", 0x7c000791, 0xfc0007ff, WR_t|RD_t|RD_s,     0,              D33	},
+{"precr_sra_r.ph.w", "t,s,h", 0x7c0007d1, 0xfc0007ff, WR_t|RD_t|RD_s,   0,              D33	},
+{"prepend", "t,s,h",	0x7c000071, 0xfc0007ff, WR_t|RD_t|RD_s,         0,              D33	},
+{"shra.qb", "d,t,3",	0x7c000113, 0xff0007ff, WR_d|RD_t,              0,              D33	},
+{"shra_r.qb", "d,t,3",	0x7c000153, 0xff0007ff, WR_d|RD_t,              0,              D33	},
+{"shrav.qb", "d,t,s",	0x7c000193, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"shrav_r.qb", "d,t,s",	0x7c0001d3, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"shrl.ph", "d,t,4",	0x7c000653, 0xfe0007ff, WR_d|RD_t,              0,              D33	},
+{"shrlv.ph", "d,t,s",	0x7c0006d3, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"subu.ph", "d,s,t",	0x7c000250, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"subu_s.ph", "d,s,t",	0x7c000350, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"subuh.qb", "d,s,t",	0x7c000058, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"subuh_r.qb", "d,s,t",	0x7c0000d8, 0xfc0007ff, WR_d|RD_s|RD_t,         0,              D33	},
+{"addqh.ph", "d,s,t",	0x7c000218, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"addqh_r.ph", "d,s,t",	0x7c000298, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"addqh.w", "d,s,t",	0x7c000418, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"addqh_r.w", "d,s,t",	0x7c000498, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"subqh.ph", "d,s,t",	0x7c000258, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"subqh_r.ph", "d,s,t",	0x7c0002d8, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"subqh.w", "d,s,t",	0x7c000458, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"subqh_r.w", "d,s,t",	0x7c0004d8, 0xfc0007ff, WR_d|RD_s|RD_t,		0,              D33	},
+{"dpax.w.ph", "7,s,t",	0x7c000230, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpsx.w.ph", "7,s,t",	0x7c000270, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpaqx_s.w.ph", "7,s,t", 0x7c000630, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpaqx_sa.w.ph", "7,s,t", 0x7c0006b0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpsqx_s.w.ph", "7,s,t", 0x7c000670, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+{"dpsqx_sa.w.ph", "7,s,t", 0x7c0006f0, 0xfc00e7ff, MOD_a|RD_s|RD_t,	0,              D33	},
+/* Move bc0* after mftr and mttr to avoid opcode collision.  */
+{"bc0f",    "p",	0x41000000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc0fl",   "p",	0x41020000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
+{"bc0t",    "p",	0x41010000, 0xffff0000,	CBD|RD_CC,		0,		I1	},
+{"bc0tl",   "p",	0x41030000, 0xffff0000,	CBL|RD_CC,		0,		I2|T3	},
 };
 
 #define MIPS_NUM_OPCODES \
@@ -2163,102 +2758,91 @@
 /* Mips instructions are at maximum this many bytes long.  */
 #define INSNLEN 4
 
-static void set_default_mips_dis_options
-  PARAMS ((struct disassemble_info *));
-static void parse_mips_dis_option
-  PARAMS ((const char *, unsigned int));
-static void parse_mips_dis_options
-  PARAMS ((const char *));
-static int _print_insn_mips
-  PARAMS ((bfd_vma, struct disassemble_info *, enum bfd_endian));
-static int print_insn_mips
-  PARAMS ((bfd_vma, unsigned long int, struct disassemble_info *));
-static void print_insn_args
-  PARAMS ((const char *, unsigned long, bfd_vma, struct disassemble_info *));
-#if 0
-static int print_insn_mips16
-  PARAMS ((bfd_vma, struct disassemble_info *));
-#endif
-#if 0
-static int is_newabi
-  PARAMS ((Elf32_Ehdr *));
-#endif
-#if 0
-static void print_mips16_insn_arg
-  PARAMS ((int, const struct mips_opcode *, int, bfd_boolean, int, bfd_vma,
-	   struct disassemble_info *));
-#endif
 
 /* FIXME: These should be shared with gdb somehow.  */
 
-struct mips_cp0sel_name {
-	unsigned int cp0reg;
-	unsigned int sel;
-	const char * const name;
+struct mips_cp0sel_name
+{
+  unsigned int cp0reg;
+  unsigned int sel;
+  const char * const name;
 };
 
-/* The mips16 register names.  */
-static const char * const mips16_reg_names[] = {
-  "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
+/* The mips16 registers.  */
+static const unsigned int mips16_to_32_reg_map[] =
+{
+  16, 17, 2, 3, 4, 5, 6, 7
 };
 
-static const char * const mips_gpr_names_numeric[32] = {
+#define mips16_reg_names(rn)	mips_gpr_names[mips16_to_32_reg_map[rn]]
+
+
+static const char * const mips_gpr_names_numeric[32] =
+{
   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
 };
 
-static const char * const mips_gpr_names_oldabi[32] = {
+static const char * const mips_gpr_names_oldabi[32] =
+{
   "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
   "t0",   "t1",   "t2",   "t3",   "t4",   "t5",   "t6",   "t7",
   "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
   "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
 };
 
-static const char * const mips_gpr_names_newabi[32] = {
+static const char * const mips_gpr_names_newabi[32] =
+{
   "zero", "at",   "v0",   "v1",   "a0",   "a1",   "a2",   "a3",
   "a4",   "a5",   "a6",   "a7",   "t0",   "t1",   "t2",   "t3",
   "s0",   "s1",   "s2",   "s3",   "s4",   "s5",   "s6",   "s7",
   "t8",   "t9",   "k0",   "k1",   "gp",   "sp",   "s8",   "ra"
 };
 
-static const char * const mips_fpr_names_numeric[32] = {
+static const char * const mips_fpr_names_numeric[32] =
+{
   "$f0",  "$f1",  "$f2",  "$f3",  "$f4",  "$f5",  "$f6",  "$f7",
   "$f8",  "$f9",  "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
   "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
   "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
 };
 
-static const char * const mips_fpr_names_32[32] = {
+static const char * const mips_fpr_names_32[32] =
+{
   "fv0",  "fv0f", "fv1",  "fv1f", "ft0",  "ft0f", "ft1",  "ft1f",
   "ft2",  "ft2f", "ft3",  "ft3f", "fa0",  "fa0f", "fa1",  "fa1f",
   "ft4",  "ft4f", "ft5",  "ft5f", "fs0",  "fs0f", "fs1",  "fs1f",
   "fs2",  "fs2f", "fs3",  "fs3f", "fs4",  "fs4f", "fs5",  "fs5f"
 };
 
-static const char * const mips_fpr_names_n32[32] = {
+static const char * const mips_fpr_names_n32[32] =
+{
   "fv0",  "ft14", "fv1",  "ft15", "ft0",  "ft1",  "ft2",  "ft3",
   "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
   "fa4",  "fa5",  "fa6",  "fa7",  "fs0",  "ft8",  "fs1",  "ft9",
   "fs2",  "ft10", "fs3",  "ft11", "fs4",  "ft12", "fs5",  "ft13"
 };
 
-static const char * const mips_fpr_names_64[32] = {
+static const char * const mips_fpr_names_64[32] =
+{
   "fv0",  "ft12", "fv1",  "ft13", "ft0",  "ft1",  "ft2",  "ft3",
   "ft4",  "ft5",  "ft6",  "ft7",  "fa0",  "fa1",  "fa2",  "fa3",
   "fa4",  "fa5",  "fa6",  "fa7",  "ft8",  "ft9",  "ft10", "ft11",
   "fs0",  "fs1",  "fs2",  "fs3",  "fs4",  "fs5",  "fs6",  "fs7"
 };
 
-static const char * const mips_cp0_names_numeric[32] = {
+static const char * const mips_cp0_names_numeric[32] =
+{
   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
 };
 
-static const char * const mips_cp0_names_mips3264[32] = {
+static const char * const mips_cp0_names_mips3264[32] =
+{
   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
   "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
@@ -2269,7 +2853,35 @@
   "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
 };
 
-static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = {
+static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] =
+{
+  {  4, 1, "c0_contextconfig"	},
+  {  0, 1, "c0_mvpcontrol"	},
+  {  0, 2, "c0_mvpconf0"	},
+  {  0, 3, "c0_mvpconf1"	},
+  {  1, 1, "c0_vpecontrol"	},
+  {  1, 2, "c0_vpeconf0"	},
+  {  1, 3, "c0_vpeconf1"	},
+  {  1, 4, "c0_yqmask"		},
+  {  1, 5, "c0_vpeschedule"	},
+  {  1, 6, "c0_vpeschefback"	},
+  {  2, 1, "c0_tcstatus"	},
+  {  2, 2, "c0_tcbind"		},
+  {  2, 3, "c0_tcrestart"	},
+  {  2, 4, "c0_tchalt"		},
+  {  2, 5, "c0_tccontext"	},
+  {  2, 6, "c0_tcschedule"	},
+  {  2, 7, "c0_tcschefback"	},
+  {  5, 1, "c0_pagegrain"	},
+  {  6, 1, "c0_srsconf0"	},
+  {  6, 2, "c0_srsconf1"	},
+  {  6, 3, "c0_srsconf2"	},
+  {  6, 4, "c0_srsconf3"	},
+  {  6, 5, "c0_srsconf4"	},
+  { 12, 1, "c0_intctl"		},
+  { 12, 2, "c0_srsctl"		},
+  { 12, 3, "c0_srsmap"		},
+  { 15, 1, "c0_ebase"		},
   { 16, 1, "c0_config1"		},
   { 16, 2, "c0_config2"		},
   { 16, 3, "c0_config3"		},
@@ -2287,6 +2899,10 @@
   { 19, 5, "c0_watchhi,5"	},
   { 19, 6, "c0_watchhi,6"	},
   { 19, 7, "c0_watchhi,7"	},
+  { 23, 1, "c0_tracecontrol"	},
+  { 23, 2, "c0_tracecontrol2"	},
+  { 23, 3, "c0_usertracedata"	},
+  { 23, 4, "c0_tracebpc"	},
   { 25, 1, "c0_perfcnt,1"	},
   { 25, 2, "c0_perfcnt,2"	},
   { 25, 3, "c0_perfcnt,3"	},
@@ -2298,10 +2914,23 @@
   { 27, 2, "c0_cacheerr,2"	},
   { 27, 3, "c0_cacheerr,3"	},
   { 28, 1, "c0_datalo"		},
-  { 29, 1, "c0_datahi"		}
+  { 28, 2, "c0_taglo1"		},
+  { 28, 3, "c0_datalo1"		},
+  { 28, 4, "c0_taglo2"		},
+  { 28, 5, "c0_datalo2"		},
+  { 28, 6, "c0_taglo3"		},
+  { 28, 7, "c0_datalo3"		},
+  { 29, 1, "c0_datahi"		},
+  { 29, 2, "c0_taghi1"		},
+  { 29, 3, "c0_datahi1"		},
+  { 29, 4, "c0_taghi2"		},
+  { 29, 5, "c0_datahi2"		},
+  { 29, 6, "c0_taghi3"		},
+  { 29, 7, "c0_datahi3"		},
 };
 
-static const char * const mips_cp0_names_mips3264r2[32] = {
+static const char * const mips_cp0_names_mips3264r2[32] =
+{
   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
   "c0_context",   "c0_pagemask",  "c0_wired",     "c0_hwrena",
   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
@@ -2312,7 +2941,8 @@
   "c0_taglo",     "c0_taghi",     "c0_errorepc",  "c0_desave",
 };
 
-static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = {
+static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] =
+{
   {  4, 1, "c0_contextconfig"	},
   {  5, 1, "c0_pagegrain"	},
   { 12, 1, "c0_intctl"		},
@@ -2367,7 +2997,8 @@
 };
 
 /* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods.  */
-static const char * const mips_cp0_names_sb1[32] = {
+static const char * const mips_cp0_names_sb1[32] =
+{
   "c0_index",     "c0_random",    "c0_entrylo0",  "c0_entrylo1",
   "c0_context",   "c0_pagemask",  "c0_wired",     "$7",
   "c0_badvaddr",  "c0_count",     "c0_entryhi",   "c0_compare",
@@ -2378,7 +3009,8 @@
   "c0_taglo_i",   "c0_taghi_i",   "c0_errorepc",  "c0_desave",
 };
 
-static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = {
+static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] =
+{
   { 16, 1, "c0_config1"		},
   { 18, 1, "c0_watchlo,1"	},
   { 19, 1, "c0_watchhi,1"	},
@@ -2402,14 +3034,16 @@
   { 29, 3, "c0_datahi_d"	},
 };
 
-static const char * const mips_hwr_names_numeric[32] = {
+static const char * const mips_hwr_names_numeric[32] =
+{
   "$0",   "$1",   "$2",   "$3",   "$4",   "$5",   "$6",   "$7",
   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
   "$16",  "$17",  "$18",  "$19",  "$20",  "$21",  "$22",  "$23",
   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
 };
 
-static const char * const mips_hwr_names_mips3264r2[32] = {
+static const char * const mips_hwr_names_mips3264r2[32] =
+{
   "hwr_cpunum",   "hwr_synci_step", "hwr_cc",     "hwr_ccres",
   "$4",          "$5",            "$6",           "$7",
   "$8",   "$9",   "$10",  "$11",  "$12",  "$13",  "$14",  "$15",
@@ -2417,20 +3051,23 @@
   "$24",  "$25",  "$26",  "$27",  "$28",  "$29",  "$30",  "$31"
 };
 
-struct mips_abi_choice {
+struct mips_abi_choice
+{
   const char *name;
   const char * const *gpr_names;
   const char * const *fpr_names;
 };
 
-struct mips_abi_choice mips_abi_choices[] = {
+struct mips_abi_choice mips_abi_choices[] =
+{
   { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
   { "32", mips_gpr_names_oldabi, mips_fpr_names_32 },
   { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 },
   { "64", mips_gpr_names_newabi, mips_fpr_names_64 },
 };
 
-struct mips_arch_choice {
+struct mips_arch_choice
+{
   const char *name;
   int bfd_mach_valid;
   unsigned long bfd_mach;
@@ -2459,6 +3096,7 @@
 #define bfd_mach_mips6000              6000
 #define bfd_mach_mips7000              7000
 #define bfd_mach_mips8000              8000
+#define bfd_mach_mips9000              9000
 #define bfd_mach_mips10000             10000
 #define bfd_mach_mips12000             12000
 #define bfd_mach_mips16                16
@@ -2471,7 +3109,8 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
 
-const struct mips_arch_choice mips_arch_choices[] = {
+const struct mips_arch_choice mips_arch_choices[] =
+{
   { "numeric",	0, 0, 0, 0,
     mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
 
@@ -2524,13 +3163,14 @@
      MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
      page 1.  */
   { "mips32",	1, bfd_mach_mipsisa32, CPU_MIPS32,
-    ISA_MIPS32 | INSN_MIPS16,
+    ISA_MIPS32 | INSN_MIPS16 | INSN_SMARTMIPS,
     mips_cp0_names_mips3264,
     mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
     mips_hwr_names_numeric },
 
   { "mips32r2",	1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
-    ISA_MIPS32R2 | INSN_MIPS16,
+    (ISA_MIPS32R2 | INSN_MIPS16 | INSN_SMARTMIPS | INSN_DSP | INSN_DSPR2
+     | INSN_MIPS3D | INSN_MT),
     mips_cp0_names_mips3264r2,
     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
     mips_hwr_names_mips3264r2 },
@@ -2543,7 +3183,8 @@
     mips_hwr_names_numeric },
 
   { "mips64r2",	1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
-    ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
+    (ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_DSP | INSN_DSPR2
+     | INSN_DSP64 | INSN_MT | INSN_MDMX),
     mips_cp0_names_mips3264r2,
     mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
     mips_hwr_names_mips3264r2 },
@@ -2572,53 +3213,39 @@
 static int mips_cp0sel_names_len;
 static const char * const *mips_hwr_names;
 
-static const struct mips_abi_choice *choose_abi_by_name
-  PARAMS ((const char *, unsigned int));
-static const struct mips_arch_choice *choose_arch_by_name
-  PARAMS ((const char *, unsigned int));
-static const struct mips_arch_choice *choose_arch_by_number
-  PARAMS ((unsigned long));
-static const struct mips_cp0sel_name *lookup_mips_cp0sel_name
-  PARAMS ((const struct mips_cp0sel_name *, unsigned int, unsigned int,
-	   unsigned int));
+/* Other options */
+static int no_aliases;	/* If set disassemble as most general inst.  */
 
 static const struct mips_abi_choice *
-choose_abi_by_name (name, namelen)
-     const char *name;
-     unsigned int namelen;
+choose_abi_by_name (const char *name, unsigned int namelen)
 {
   const struct mips_abi_choice *c;
   unsigned int i;
 
   for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
-    {
-      if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
-	  && strlen (mips_abi_choices[i].name) == namelen)
-	c = &mips_abi_choices[i];
-    }
+    if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
+	&& strlen (mips_abi_choices[i].name) == namelen)
+      c = &mips_abi_choices[i];
+
   return c;
 }
 
 static const struct mips_arch_choice *
-choose_arch_by_name (name, namelen)
-     const char *name;
-     unsigned int namelen;
+choose_arch_by_name (const char *name, unsigned int namelen)
 {
   const struct mips_arch_choice *c = NULL;
   unsigned int i;
 
   for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
-    {
-      if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
-	  && strlen (mips_arch_choices[i].name) == namelen)
-	c = &mips_arch_choices[i];
-    }
+    if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
+	&& strlen (mips_arch_choices[i].name) == namelen)
+      c = &mips_arch_choices[i];
+
   return c;
 }
 
 static const struct mips_arch_choice *
-choose_arch_by_number (mach)
-     unsigned long mach;
+choose_arch_by_number (unsigned long mach)
 {
   static unsigned long hint_bfd_mach;
   static const struct mips_arch_choice *hint_arch_choice;
@@ -2646,8 +3273,7 @@
 }
 
 void
-set_default_mips_dis_options (info)
-     struct disassemble_info *info;
+set_default_mips_dis_options (struct disassemble_info *info)
 {
   const struct mips_arch_choice *chosen_arch;
 
@@ -2661,6 +3287,7 @@
   mips_cp0sel_names = NULL;
   mips_cp0sel_names_len = 0;
   mips_hwr_names = mips_hwr_names_numeric;
+  no_aliases = 0;
 
   /* If an ELF "newabi" binary, use the n32/(n)64 GPR names.  */
 #if 0
@@ -2788,9 +3415,8 @@
   /* Invalid option.  */
 }
 
-void
-parse_mips_dis_options (options)
-     const char *options;
+static void
+parse_mips_dis_options (const char *options)
 {
   const char *option_end;
 
@@ -2820,9 +3446,10 @@
 }
 
 static const struct mips_cp0sel_name *
-lookup_mips_cp0sel_name(names, len, cp0reg, sel)
-	const struct mips_cp0sel_name *names;
-	unsigned int len, cp0reg, sel;
+lookup_mips_cp0sel_name (const struct mips_cp0sel_name *names,
+			 unsigned int len,
+			 unsigned int cp0reg,
+			 unsigned int sel)
 {
   unsigned int i;
 
@@ -2835,11 +3462,11 @@
 /* Print insn arguments for 32/64-bit code.  */
 
 static void
-print_insn_args (d, l, pc, info)
-     const char *d;
-     register unsigned long int l;
-     bfd_vma pc;
-     struct disassemble_info *info;
+print_insn_args (const char *d,
+		 register unsigned long int l,
+		 bfd_vma pc,
+		 struct disassemble_info *info,
+		 const struct mips_opcode *opp)
 {
   int op, delta;
   unsigned int lsb, msb, msbd;
@@ -2873,12 +3500,32 @@
 	      lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT;
 	      (*info->fprintf_func) (info->stream, "0x%x", lsb);
 	      break;
-	
+
 	    case 'B':
 	      msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB;
 	      (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
 	      break;
 
+	    case '1':
+	      (*info->fprintf_func) (info->stream, "0x%lx",
+				     (l >> OP_SH_UDI1) & OP_MASK_UDI1);
+	      break;
+
+	    case '2':
+	      (*info->fprintf_func) (info->stream, "0x%lx",
+				     (l >> OP_SH_UDI2) & OP_MASK_UDI2);
+	      break;
+
+	    case '3':
+	      (*info->fprintf_func) (info->stream, "0x%lx",
+				     (l >> OP_SH_UDI3) & OP_MASK_UDI3);
+	      break;
+
+	    case '4':
+	      (*info->fprintf_func) (info->stream, "0x%lx",
+				     (l >> OP_SH_UDI4) & OP_MASK_UDI4);
+	      break;
+
 	    case 'C':
 	    case 'H':
 	      msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
@@ -2911,7 +3558,7 @@
 	      lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32;
 	      (*info->fprintf_func) (info->stream, "0x%x", lsb);
 	      break;
-	
+
 	    case 'F':
 	      msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32;
 	      (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
@@ -2922,6 +3569,34 @@
 	      (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
 	      break;
 
+	    case 't': /* Coprocessor 0 reg name */
+	      (*info->fprintf_func) (info->stream, "%s",
+				     mips_cp0_names[(l >> OP_SH_RT) &
+						     OP_MASK_RT]);
+	      break;
+
+	    case 'T': /* Coprocessor 0 reg name */
+	      {
+		const struct mips_cp0sel_name *n;
+		unsigned int cp0reg, sel;
+
+		cp0reg = (l >> OP_SH_RT) & OP_MASK_RT;
+		sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
+
+		/* CP0 register including 'sel' code for mftc0, to be
+		   printed textually if known.  If not known, print both
+		   CP0 register name and sel numerically since CP0 register
+		   with sel 0 may have a name unrelated to register being
+		   printed.  */
+		n = lookup_mips_cp0sel_name(mips_cp0sel_names,
+					    mips_cp0sel_names_len, cp0reg, sel);
+		if (n != NULL)
+		  (*info->fprintf_func) (info->stream, "%s", n->name);
+		else
+		  (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
+		break;
+	      }
+
 	    default:
 	      /* xgettext:c-format */
 	      (*info->fprintf_func) (info->stream,
@@ -2931,6 +3606,98 @@
 	    }
 	  break;
 
+	case '2':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_BP) & OP_MASK_BP);
+	  break;
+
+	case '3':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_SA3) & OP_MASK_SA3);
+	  break;
+
+	case '4':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_SA4) & OP_MASK_SA4);
+	  break;
+
+	case '5':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_IMM8) & OP_MASK_IMM8);
+	  break;
+
+	case '6':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_RS) & OP_MASK_RS);
+	  break;
+
+	case '7':
+	  (*info->fprintf_func) (info->stream, "$ac%ld",
+				 (l >> OP_SH_DSPACC) & OP_MASK_DSPACC);
+	  break;
+
+	case '8':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_WRDSP) & OP_MASK_WRDSP);
+	  break;
+
+	case '9':
+	  (*info->fprintf_func) (info->stream, "$ac%ld",
+				 (l >> OP_SH_DSPACC_S) & OP_MASK_DSPACC_S);
+	  break;
+
+	case '0': /* dsp 6-bit signed immediate in bit 20 */
+	  delta = ((l >> OP_SH_DSPSFT) & OP_MASK_DSPSFT);
+	  if (delta & 0x20) /* test sign bit */
+	    delta |= ~OP_MASK_DSPSFT;
+	  (*info->fprintf_func) (info->stream, "%d", delta);
+	  break;
+
+	case ':': /* dsp 7-bit signed immediate in bit 19 */
+	  delta = ((l >> OP_SH_DSPSFT_7) & OP_MASK_DSPSFT_7);
+	  if (delta & 0x40) /* test sign bit */
+	    delta |= ~OP_MASK_DSPSFT_7;
+	  (*info->fprintf_func) (info->stream, "%d", delta);
+	  break;
+
+	case '\'':
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+				 (l >> OP_SH_RDDSP) & OP_MASK_RDDSP);
+	  break;
+
+	case '@': /* dsp 10-bit signed immediate in bit 16 */
+	  delta = ((l >> OP_SH_IMM10) & OP_MASK_IMM10);
+	  if (delta & 0x200) /* test sign bit */
+	    delta |= ~OP_MASK_IMM10;
+	  (*info->fprintf_func) (info->stream, "%d", delta);
+	  break;
+
+	case '!':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_MT_U) & OP_MASK_MT_U);
+	  break;
+
+	case '$':
+	  (*info->fprintf_func) (info->stream, "%ld",
+				 (l >> OP_SH_MT_H) & OP_MASK_MT_H);
+	  break;
+
+	case '*':
+	  (*info->fprintf_func) (info->stream, "$ac%ld",
+				 (l >> OP_SH_MTACC_T) & OP_MASK_MTACC_T);
+	  break;
+
+	case '&':
+	  (*info->fprintf_func) (info->stream, "$ac%ld",
+				 (l >> OP_SH_MTACC_D) & OP_MASK_MTACC_D);
+	  break;
+
+	case 'g':
+	  /* Coprocessor register for CTTC1, MTTC2, MTHC2, CTTC2.  */
+	  (*info->fprintf_func) (info->stream, "$%ld",
+				 (l >> OP_SH_RD) & OP_MASK_RD);
+	  break;
+
 	case 's':
 	case 'b':
 	case 'r':
@@ -2947,7 +3714,7 @@
 
 	case 'i':
 	case 'u':
-	  (*info->fprintf_func) (info->stream, "0x%x",
+	  (*info->fprintf_func) (info->stream, "0x%lx",
 				 (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
 	  break;
 
@@ -2975,6 +3742,10 @@
 	case 'a':
 	  info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
 			  | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
+	  /* For gdb disassembler, force odd address on jalx.  */
+	  if (info->flavour == bfd_target_unknown_flavour
+	      && strcmp (opp->name, "jalx") == 0)
+	    info->target |= 1;
 	  (*info->print_address_func) (info->target, info);
 	  break;
 
@@ -3021,32 +3792,33 @@
 	  break;
 
 	case '<':
-	  (*info->fprintf_func) (info->stream, "0x%x",
+	  (*info->fprintf_func) (info->stream, "0x%lx",
 				 (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
 	  break;
 
 	case 'c':
-	  (*info->fprintf_func) (info->stream, "0x%x",
+	  (*info->fprintf_func) (info->stream, "0x%lx",
 				 (l >> OP_SH_CODE) & OP_MASK_CODE);
 	  break;
 
 	case 'q':
-	  (*info->fprintf_func) (info->stream, "0x%x",
+	  (*info->fprintf_func) (info->stream, "0x%lx",
 				 (l >> OP_SH_CODE2) & OP_MASK_CODE2);
 	  break;
 
 	case 'C':
-	  (*info->fprintf_func) (info->stream, "0x%x",
+	  (*info->fprintf_func) (info->stream, "0x%lx",
 				 (l >> OP_SH_COPZ) & OP_MASK_COPZ);
 	  break;
 
 	case 'B':
-	  (*info->fprintf_func) (info->stream, "0x%x",
+	  (*info->fprintf_func) (info->stream, "0x%lx",
+
 				 (l >> OP_SH_CODE20) & OP_MASK_CODE20);
 	  break;
 
 	case 'J':
-	  (*info->fprintf_func) (info->stream, "0x%x",
+	  (*info->fprintf_func) (info->stream, "0x%lx",
 				 (l >> OP_SH_CODE19) & OP_MASK_CODE19);
 	  break;
 
@@ -3080,7 +3852,7 @@
 	     'T' format.  Therefore, until we gain understanding of
 	     cp2 register names, we can simply print the register
 	     numbers.  */
-	  (*info->fprintf_func) (info->stream, "$%d",
+	  (*info->fprintf_func) (info->stream, "$%ld",
 				 (l >> OP_SH_RT) & OP_MASK_RT);
 	  break;
 
@@ -3094,7 +3866,7 @@
 	    (*info->fprintf_func) (info->stream, "%s",
 				   mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
 	  else
-	    (*info->fprintf_func) (info->stream, "$%d",
+	    (*info->fprintf_func) (info->stream, "$%ld",
 				   (l >> OP_SH_RD) & OP_MASK_RD);
 	  break;
 
@@ -3104,79 +3876,83 @@
 	  break;
 
 	case 'N':
-	  (*info->fprintf_func) (info->stream, "$fcc%d",
+	  (*info->fprintf_func) (info->stream,
+				 ((opp->pinfo & (FP_D | FP_S)) != 0
+				  ? "$fcc%ld" : "$cc%ld"),
 				 (l >> OP_SH_BCC) & OP_MASK_BCC);
 	  break;
 
 	case 'M':
-	  (*info->fprintf_func) (info->stream, "$fcc%d",
+	  (*info->fprintf_func) (info->stream, "$fcc%ld",
 				 (l >> OP_SH_CCC) & OP_MASK_CCC);
 	  break;
 
 	case 'P':
-	  (*info->fprintf_func) (info->stream, "%d",
+	  (*info->fprintf_func) (info->stream, "%ld",
 				 (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
 	  break;
 
 	case 'e':
-	  (*info->fprintf_func) (info->stream, "%d",
+	  (*info->fprintf_func) (info->stream, "%ld",
 				 (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
 	  break;
 
 	case '%':
-	  (*info->fprintf_func) (info->stream, "%d",
+	  (*info->fprintf_func) (info->stream, "%ld",
 				 (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
 	  break;
 
 	case 'H':
-	  (*info->fprintf_func) (info->stream, "%d",
+	  (*info->fprintf_func) (info->stream, "%ld",
 				 (l >> OP_SH_SEL) & OP_MASK_SEL);
 	  break;
 
 	case 'O':
-	  (*info->fprintf_func) (info->stream, "%d",
+	  (*info->fprintf_func) (info->stream, "%ld",
 				 (l >> OP_SH_ALN) & OP_MASK_ALN);
 	  break;
 
 	case 'Q':
 	  {
 	    unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
+
 	    if ((vsel & 0x10) == 0)
 	      {
 		int fmt;
+
 		vsel &= 0x0f;
 		for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
 		  if ((vsel & 1) == 0)
 		    break;
-		(*info->fprintf_func) (info->stream, "$v%d[%d]",
+		(*info->fprintf_func) (info->stream, "$v%ld[%d]",
 				       (l >> OP_SH_FT) & OP_MASK_FT,
 				       vsel >> 1);
 	      }
 	    else if ((vsel & 0x08) == 0)
 	      {
-		(*info->fprintf_func) (info->stream, "$v%d",
+		(*info->fprintf_func) (info->stream, "$v%ld",
 				       (l >> OP_SH_FT) & OP_MASK_FT);
 	      }
 	    else
 	      {
-		(*info->fprintf_func) (info->stream, "0x%x",
+		(*info->fprintf_func) (info->stream, "0x%lx",
 				       (l >> OP_SH_FT) & OP_MASK_FT);
 	      }
 	  }
 	  break;
 
 	case 'X':
-	  (*info->fprintf_func) (info->stream, "$v%d",
+	  (*info->fprintf_func) (info->stream, "$v%ld",
 				 (l >> OP_SH_FD) & OP_MASK_FD);
 	  break;
 
 	case 'Y':
-	  (*info->fprintf_func) (info->stream, "$v%d",
+	  (*info->fprintf_func) (info->stream, "$v%ld",
 				 (l >> OP_SH_FS) & OP_MASK_FS);
 	  break;
 
 	case 'Z':
-	  (*info->fprintf_func) (info->stream, "$v%d",
+	  (*info->fprintf_func) (info->stream, "$v%ld",
 				 (l >> OP_SH_FT) & OP_MASK_FT);
 	  break;
 
@@ -3214,12 +3990,11 @@
    this is little-endian code.  */
 
 static int
-print_insn_mips (memaddr, word, info)
-     bfd_vma memaddr;
-     unsigned long int word;
-     struct disassemble_info *info;
+print_insn_mips (bfd_vma memaddr,
+		 unsigned long int word,
+		 struct disassemble_info *info)
 {
-  register const struct mips_opcode *op;
+  const struct mips_opcode *op;
   static bfd_boolean init = 0;
   static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
 
@@ -3232,7 +4007,8 @@
 	{
 	  for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
 	    {
-	      if (op->pinfo == INSN_MACRO)
+	      if (op->pinfo == INSN_MACRO
+		  || (no_aliases && (op->pinfo2 & INSN2_ALIAS)))
 		continue;
 	      if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
 		{
@@ -3259,9 +4035,11 @@
     {
       for (; op < &mips_opcodes[NUMOPCODES]; op++)
 	{
-	  if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match)
+	  if (op->pinfo != INSN_MACRO
+	      && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
+	      && (word & op->mask) == op->match)
 	    {
-	      register const char *d;
+	      const char *d;
 
 	      /* We always allow to disassemble the jalx instruction.  */
 	      if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor)
@@ -3296,7 +4074,7 @@
 	      if (d != NULL && *d != '\0')
 		{
 		  (*info->fprintf_func) (info->stream, "\t");
-		  print_insn_args (d, word, memaddr, info);
+		  print_insn_args (d, word, memaddr, info, op);
 		}
 
 	      return INSNLEN;
@@ -3306,7 +4084,7 @@
 
   /* Handle undefined instructions.  */
   info->insn_type = dis_noninsn;
-  (*info->fprintf_func) (info->stream, "0x%x", word);
+  (*info->fprintf_func) (info->stream, "0x%lx", word);
   return INSNLEN;
 }
 
@@ -3317,10 +4095,9 @@
    this works.  Otherwise, we need a clue.  Sometimes.  */
 
 static int
-_print_insn_mips (memaddr, info, endianness)
-     bfd_vma memaddr;
-     struct disassemble_info *info;
-     enum bfd_endian endianness;
+_print_insn_mips (bfd_vma memaddr,
+		  struct disassemble_info *info,
+		  enum bfd_endian endianness)
 {
   bfd_byte buffer[INSNLEN];
   int status;
@@ -3366,17 +4143,13 @@
 }
 
 int
-print_insn_big_mips (memaddr, info)
-     bfd_vma memaddr;
-     struct disassemble_info *info;
+print_insn_big_mips (bfd_vma memaddr, struct disassemble_info *info)
 {
   return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
 }
 
 int
-print_insn_little_mips (memaddr, info)
-     bfd_vma memaddr;
-     struct disassemble_info *info;
+print_insn_little_mips (bfd_vma memaddr, struct disassemble_info *info)
 {
   return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
 }
@@ -3384,9 +4157,7 @@
 /* Disassemble mips16 instructions.  */
 #if 0
 static int
-print_insn_mips16 (memaddr, info)
-     bfd_vma memaddr;
-     struct disassemble_info *info;
+print_insn_mips16 (bfd_vma memaddr, struct disassemble_info *info)
 {
   int status;
   bfd_byte buffer[2];
@@ -3459,7 +4230,9 @@
   opend = mips16_opcodes + bfd_mips16_num_opcodes;
   for (op = mips16_opcodes; op < opend; op++)
     {
-      if (op->pinfo != INSN_MACRO && (insn & op->mask) == op->match)
+      if (op->pinfo != INSN_MACRO
+	  && !(no_aliases && (op->pinfo2 & INSN2_ALIAS))
+	  && (insn & op->mask) == op->match)
 	{
 	  const char *s;
 
@@ -3540,14 +4313,13 @@
 /* Disassemble an operand for a mips16 instruction.  */
 
 static void
-print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info)
-     char type;
-     const struct mips_opcode *op;
-     int l;
-     bfd_boolean use_extend;
-     int extend;
-     bfd_vma memaddr;
-     struct disassemble_info *info;
+print_mips16_insn_arg (char type,
+		       const struct mips_opcode *op,
+		       int l,
+		       bfd_boolean use_extend,
+		       int extend,
+		       bfd_vma memaddr,
+		       struct disassemble_info *info)
 {
   switch (type)
     {
@@ -3560,27 +4332,27 @@
     case 'y':
     case 'w':
       (*info->fprintf_func) (info->stream, "%s",
-			     mips16_reg_names[((l >> MIPS16OP_SH_RY)
-					       & MIPS16OP_MASK_RY)]);
+			     mips16_reg_names(((l >> MIPS16OP_SH_RY)
+					       & MIPS16OP_MASK_RY)));
       break;
 
     case 'x':
     case 'v':
       (*info->fprintf_func) (info->stream, "%s",
-			     mips16_reg_names[((l >> MIPS16OP_SH_RX)
-					       & MIPS16OP_MASK_RX)]);
+			     mips16_reg_names(((l >> MIPS16OP_SH_RX)
+					       & MIPS16OP_MASK_RX)));
       break;
 
     case 'z':
       (*info->fprintf_func) (info->stream, "%s",
-			     mips16_reg_names[((l >> MIPS16OP_SH_RZ)
-					       & MIPS16OP_MASK_RZ)]);
+			     mips16_reg_names(((l >> MIPS16OP_SH_RZ)
+					       & MIPS16OP_MASK_RZ)));
       break;
 
     case 'Z':
       (*info->fprintf_func) (info->stream, "%s",
-			     mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z)
-					       & MIPS16OP_MASK_MOVE32Z)]);
+			     mips16_reg_names(((l >> MIPS16OP_SH_MOVE32Z)
+					       & MIPS16OP_MASK_MOVE32Z)));
       break;
 
     case '0':
@@ -3862,15 +4634,26 @@
 		  }
 	      }
 	    info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
+	    if (pcrel && branch
+		&& info->flavour == bfd_target_unknown_flavour)
+	      /* For gdb disassembler, maintain odd address.  */
+	      info->target |= 1;
 	    (*info->print_address_func) (info->target, info);
 	  }
       }
       break;
 
     case 'a':
-      if (! use_extend)
-	extend = 0;
-      l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
+      {
+	int jalx = l & 0x400;
+
+	if (! use_extend)
+	  extend = 0;
+	l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
+	if (!jalx && info->flavour == bfd_target_unknown_flavour)
+	  /* For gdb disassembler, maintain odd address.  */
+	  l |= 1;
+      }
       info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
       (*info->print_address_func) (info->target, info);
       info->insn_type = dis_jsr;
@@ -3933,6 +4716,92 @@
       }
       break;
 
+    case 'm':
+    case 'M':
+      /* MIPS16e save/restore.  */
+      {
+      int need_comma = 0;
+      int amask, args, statics;
+      int nsreg, smask;
+      int framesz;
+      int i, j;
+
+      l = l & 0x7f;
+      if (use_extend)
+        l |= extend << 16;
+
+      amask = (l >> 16) & 0xf;
+      if (amask == MIPS16_ALL_ARGS)
+        {
+          args = 4;
+          statics = 0;
+        }
+      else if (amask == MIPS16_ALL_STATICS)
+        {
+          args = 0;
+          statics = 4;
+        }
+      else
+        {
+          args = amask >> 2;
+          statics = amask & 3;
+        }
+
+      if (args > 0) {
+          (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
+          if (args > 1)
+            (*info->fprintf_func) (info->stream, "-%s",
+                                   mips_gpr_names[4 + args - 1]);
+          need_comma = 1;
+      }
+
+      framesz = (((l >> 16) & 0xf0) | (l & 0x0f)) * 8;
+      if (framesz == 0 && !use_extend)
+        framesz = 128;
+
+      (*info->fprintf_func) (info->stream, "%s%d",
+                             need_comma ? "," : "",
+                             framesz);
+
+      if (l & 0x40)                   /* $ra */
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[31]);
+
+      nsreg = (l >> 24) & 0x7;
+      smask = 0;
+      if (l & 0x20)                   /* $s0 */
+        smask |= 1 << 0;
+      if (l & 0x10)                   /* $s1 */
+        smask |= 1 << 1;
+      if (nsreg > 0)                  /* $s2-$s8 */
+        smask |= ((1 << nsreg) - 1) << 2;
+
+      /* Find first set static reg bit.  */
+      for (i = 0; i < 9; i++)
+        {
+          if (smask & (1 << i))
+            {
+              (*info->fprintf_func) (info->stream, ",%s",
+                                     mips_gpr_names[i == 8 ? 30 : (16 + i)]);
+              /* Skip over string of set bits.  */
+              for (j = i; smask & (2 << j); j++)
+                continue;
+              if (j > i)
+                (*info->fprintf_func) (info->stream, "-%s",
+                                       mips_gpr_names[j == 8 ? 30 : (16 + j)]);
+              i = j + 1;
+            }
+        }
+
+      /* Statics $ax - $a3.  */
+      if (statics == 1)
+        (*info->fprintf_func) (info->stream, ",%s", mips_gpr_names[7]);
+      else if (statics > 0)
+        (*info->fprintf_func) (info->stream, ",%s-%s",
+                               mips_gpr_names[7 - statics + 1],
+                               mips_gpr_names[7]);
+      }
+      break;
+
     default:
       /* xgettext:c-format */
       (*info->fprintf_func)
@@ -3945,8 +4814,7 @@
 #endif
 
 void
-print_mips_disassembler_options (stream)
-     FILE *stream;
+print_mips_disassembler_options (FILE *stream)
 {
   unsigned int i;
 
diff --git a/mips.ld b/mips.ld
new file mode 100644
index 0000000..94fa63b
--- /dev/null
+++ b/mips.ld
@@ -0,0 +1,225 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips",
+             "elf32-tradlittlemips")
+OUTPUT_ARCH(mips)
+ENTRY(__start)
+SEARCH_DIR("/usr/mips-linux-gnu/lib");
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .reginfo        : { *(.reginfo) }
+  .dynamic        : { *(.dynamic) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data.rel.ro   : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
+  .rela.data.rel.ro   : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata     : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata    : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss      : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss     : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x47ff041f
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    _ftext = . ;
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.mips16.fn.*) *(.mips16.call.*)
+  } =0x47ff041f
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x47ff041f
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         :
+  {
+    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+  }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000);
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+     PROVIDE_HIDDEN (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE_HIDDEN (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  . = DATA_SEGMENT_RELRO_END (0, .);
+  .data           :
+  {
+    _fdata = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  . = .;
+  _gp = ALIGN(16) + 0x7ff0;
+  .got            : { *(.got.plt) *(.got) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  .lit8           : { *(.lit8) }
+  .lit4           : { *(.lit4) }
+  _edata = .; PROVIDE (edata = .);
+  __bss_start = .;
+  _fbss = .;
+  .sbss           :
+  {
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+  }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/mipsel.ld b/mipsel.ld
new file mode 100644
index 0000000..e37938c
--- /dev/null
+++ b/mipsel.ld
@@ -0,0 +1,225 @@
+/* Default linker script, for normal executables */
+OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips",
+             "elf32-tradlittlemips")
+OUTPUT_ARCH(mips)
+ENTRY(__start)
+SEARCH_DIR("/usr/mips-linux-gnu/lib");
+SECTIONS
+{
+  /* Read-only sections, merged into text segment: */
+  PROVIDE (__executable_start = 0x0400000); . = 0x0400000 + SIZEOF_HEADERS;
+  .interp         : { *(.interp) }
+  .reginfo        : { *(.reginfo) }
+  .dynamic        : { *(.dynamic) }
+  .hash           : { *(.hash) }
+  .dynsym         : { *(.dynsym) }
+  .dynstr         : { *(.dynstr) }
+  .gnu.version    : { *(.gnu.version) }
+  .gnu.version_d  : { *(.gnu.version_d) }
+  .gnu.version_r  : { *(.gnu.version_r) }
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data.rel.ro   : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
+  .rela.data.rel.ro   : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata     : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata    : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss      : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss     : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
+  {
+    KEEP (*(.init))
+  } =0x47ff041f
+  .plt            : { *(.plt) }
+  .text           :
+  {
+    _ftext = . ;
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
+    /* .gnu.warning sections are handled specially by elf32.em.  */
+    *(.gnu.warning)
+    *(.mips16.fn.*) *(.mips16.call.*)
+  } =0x47ff041f
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x47ff041f
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
+  PROVIDE (etext = .);
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         :
+  {
+    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+  }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+  /* Adjust the address for the data segment.  We want to adjust up to
+     the same address within the page on the next page up.  */
+  . = ALIGN (0x40000) - ((0x40000 - .) & (0x40000 - 1)); . = DATA_SEGMENT_ALIGN (0x40000, 0x1000);
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata         : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss                  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
+  {
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
+  }
+  .init_array     :
+  {
+     PROVIDE_HIDDEN (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE_HIDDEN (__init_array_end = .);
+  }
+  .fini_array     :
+  {
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE_HIDDEN (__fini_array_end = .);
+  }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  . = DATA_SEGMENT_RELRO_END (0, .);
+  .data           :
+  {
+    _fdata = . ;
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  . = .;
+  _gp = ALIGN(16) + 0x7ff0;
+  .got            : { *(.got.plt) *(.got) }
+  /* We want the small data sections together, so single-instruction offsets
+     can access them all, and initialized data all before uninitialized, so
+     we can shorten the on-disk segment size.  */
+  .sdata          :
+  {
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  .lit8           : { *(.lit8) }
+  .lit4           : { *(.lit4) }
+  _edata = .; PROVIDE (edata = .);
+  __bss_start = .;
+  _fbss = .;
+  .sbss           :
+  {
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+  }
+  .bss            :
+  {
+   *(.dynbss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
+   *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
+  }
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
+  /* Stabs debugging sections.  */
+  .stab          0 : { *(.stab) }
+  .stabstr       0 : { *(.stabstr) }
+  .stab.excl     0 : { *(.stab.excl) }
+  .stab.exclstr  0 : { *(.stab.exclstr) }
+  .stab.index    0 : { *(.stab.index) }
+  .stab.indexstr 0 : { *(.stab.indexstr) }
+  .comment       0 : { *(.comment) }
+  /* DWARF debug sections.
+     Symbols in the DWARF debugging sections are relative to the beginning
+     of the section so we begin them at 0.  */
+  /* DWARF 1 */
+  .debug          0 : { *(.debug) }
+  .line           0 : { *(.line) }
+  /* GNU DWARF 1 extensions */
+  .debug_srcinfo  0 : { *(.debug_srcinfo) }
+  .debug_sfnames  0 : { *(.debug_sfnames) }
+  /* DWARF 1.1 and DWARF 2 */
+  .debug_aranges  0 : { *(.debug_aranges) }
+  .debug_pubnames 0 : { *(.debug_pubnames) }
+  /* DWARF 2 */
+  .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+  .debug_abbrev   0 : { *(.debug_abbrev) }
+  .debug_line     0 : { *(.debug_line) }
+  .debug_frame    0 : { *(.debug_frame) }
+  .debug_str      0 : { *(.debug_str) }
+  .debug_loc      0 : { *(.debug_loc) }
+  .debug_macinfo  0 : { *(.debug_macinfo) }
+  /* SGI/MIPS DWARF 2 extensions */
+  .debug_weaknames 0 : { *(.debug_weaknames) }
+  .debug_funcnames 0 : { *(.debug_funcnames) }
+  .debug_typenames 0 : { *(.debug_typenames) }
+  .debug_varnames  0 : { *(.debug_varnames) }
+  .gptab.sdata : { *(.gptab.data) *(.gptab.sdata) }
+  .gptab.sbss : { *(.gptab.bss) *(.gptab.sbss) }
+  /DISCARD/ : { *(.note.GNU-stack) }
+}
diff --git a/monitor.c b/monitor.c
index de8d1ea..10e0af9 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,8 +1,8 @@
 /*
  * QEMU monitor
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -36,7 +36,7 @@
 
 /*
  * Supported types:
- * 
+ *
  * 'F'          filename
  * 'B'          block device name
  * 's'          string (accept optional quote)
@@ -56,7 +56,8 @@
     const char *help;
 } term_cmd_t;
 
-static CharDriverState *monitor_hd;
+#define MAX_MON 4
+static CharDriverState *monitor_hd[MAX_MON];
 static int hide_banner;
 
 static term_cmd_t term_cmds[];
@@ -71,8 +72,11 @@
 
 void term_flush(void)
 {
+    int i;
     if (term_outbuf_index > 0) {
-        qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index);
+        for (i = 0; i < MAX_MON; i++)
+            if (monitor_hd[i] && monitor_hd[i]->focus == 0)
+                qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index);
         term_outbuf_index = 0;
     }
 }
@@ -200,15 +204,18 @@
 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]) {
-            if (all_devices || 
+            if (all_devices ||
                 !strcmp(bdrv_get_device_name(bs_table[i]), device))
                 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)
@@ -218,7 +225,7 @@
     if (!item)
         goto help;
     for(cmd = info_cmds; cmd->name != NULL; cmd++) {
-        if (compare_cmd(item, cmd->name)) 
+        if (compare_cmd(item, cmd->name))
             goto found;
     }
  help:
@@ -233,6 +240,12 @@
   term_printf("%s\n", QEMU_VERSION);
 }
 
+static void do_info_name(void)
+{
+    if (qemu_name)
+        term_printf("%s\n", qemu_name);
+}
+
 static void do_info_block(void)
 {
     bdrv_info();
@@ -275,7 +288,7 @@
     cpu_dump_state(env, NULL, monitor_fprintf,
                    X86_DUMP_FPU);
 #else
-    cpu_dump_state(env, NULL, monitor_fprintf, 
+    cpu_dump_state(env, NULL, monitor_fprintf,
                    0);
 #endif
 }
@@ -288,7 +301,7 @@
     mon_get_cpu();
 
     for(env = first_cpu; env != NULL; env = env->next_cpu) {
-        term_printf("%c CPU #%d:", 
+        term_printf("%c CPU #%d:",
                     (env == mon_cpu) ? '*' : ' ',
                     env->cpu_index);
 #if defined(TARGET_I386)
@@ -303,6 +316,10 @@
         term_printf(" pc=0x" TARGET_FMT_lx " npc=0x" TARGET_FMT_lx, env->pc, env->npc);
         if (env->halted)
             term_printf(" (halted)");
+#elif defined(TARGET_MIPS)
+        term_printf(" PC=0x" TARGET_FMT_lx, env->PC[env->current_tc]);
+        if (env->halted)
+            term_printf(" (halted)");
 #endif
         term_printf("\n");
     }
@@ -323,7 +340,7 @@
 {
     int i;
     const char *str;
-    
+
     i = 0;
     for(;;) {
         str = readline_get_history(i);
@@ -334,6 +351,17 @@
     }
 }
 
+#if defined(TARGET_PPC)
+/* XXX: not implemented in other targets */
+static void do_info_cpu_stats (void)
+{
+    CPUState *env;
+
+    env = mon_get_cpu();
+    cpu_dump_statistics(env, NULL, &monitor_fprintf, 0);
+}
+#endif
+
 static void do_quit(void)
 {
     exit(0);
@@ -422,11 +450,9 @@
     }
 }
 
-static void do_change(const char *device, const char *filename)
+static void do_change_block(const char *device, const char *filename)
 {
     BlockDriverState *bs;
-    int i;
-    char password[256];
 
     bs = bdrv_find(device);
     if (!bs) {
@@ -436,14 +462,30 @@
     if (eject_device(bs, 0) < 0)
         return;
     bdrv_open(bs, filename, 0);
-    if (bdrv_is_encrypted(bs)) {
-        term_printf("%s is encrypted.\n", device);
-        for(i = 0; i < 3; i++) {
-            monitor_readline("Password: ", 1, password, sizeof(password));
-            if (bdrv_set_key(bs, password) == 0)
-                break;
-            term_printf("invalid password\n");
-        }
+    qemu_key_check(bs, filename);
+}
+
+static void do_change_vnc(const char *target)
+{
+    if (strcmp(target, "passwd") == 0 ||
+	strcmp(target, "password") == 0) {
+	char password[9];
+	monitor_readline("Password: ", 1, password, sizeof(password)-1);
+	password[sizeof(password)-1] = '\0';
+	if (vnc_display_password(NULL, password) < 0)
+	    term_printf("could not set VNC server password\n");
+    } else {
+	if (vnc_display_open(NULL, target) < 0)
+	    term_printf("could not start VNC server on %s\n", target);
+    }
+}
+
+static void do_change(const char *device, const char *target)
+{
+    if (strcmp(device, "vnc") == 0) {
+	do_change_vnc(target);
+    } else {
+	do_change_block(device, target);
     }
 }
 
@@ -452,10 +494,15 @@
     vga_hw_screen_dump(filename);
 }
 
+static void do_logfile(const char *filename)
+{
+    cpu_set_log_filename(filename);
+}
+
 static void do_log(const char *items)
 {
     int mask;
-    
+
     if (!strcmp(items, "none")) {
         mask = 0;
     } else {
@@ -479,14 +526,14 @@
 }
 
 #ifdef CONFIG_GDBSTUB
-static void do_gdbserver(int has_port, int port)
+static void do_gdbserver(const char *port)
 {
-    if (!has_port)
+    if (!port)
         port = DEFAULT_GDBSTUB_PORT;
-    if (gdbserver_start_port(port) < 0) {
-        qemu_printf("Could not open gdbserver socket on port %d\n", port);
+    if (gdbserver_start(port) < 0) {
+        qemu_printf("Could not open gdbserver socket on port '%s'\n", port);
     } else {
-        qemu_printf("Waiting gdb connection on port %d\n", port);
+        qemu_printf("Waiting gdb connection on port '%s'\n", port);
     }
 }
 #endif
@@ -518,8 +565,8 @@
     term_printf("'");
 }
 
-static void memory_dump(int count, int format, int wsize, 
-                        target_ulong addr, int is_physical)
+static void memory_dump(int count, int format, int wsize,
+                        target_phys_addr_t addr, int is_physical)
 {
     CPUState *env;
     int nb_per_line, l, line_size, i, max_digits, len;
@@ -542,7 +589,7 @@
             flags = 0;
             if (env) {
 #ifdef TARGET_X86_64
-                if ((env->efer & MSR_EFER_LMA) && 
+                if ((env->efer & MSR_EFER_LMA) &&
                     (env->segs[R_CS].flags & DESC_L_MASK))
                     flags = 2;
                 else
@@ -582,7 +629,10 @@
     }
 
     while (len > 0) {
-        term_printf(TARGET_FMT_lx ":", addr);
+        if (is_physical)
+            term_printf(TARGET_FMT_plx ":", addr);
+        else
+            term_printf(TARGET_FMT_lx ":", (target_ulong)addr);
         l = len;
         if (l > line_size)
             l = line_size;
@@ -594,7 +644,7 @@
                 break;
             cpu_memory_rw_debug(env, addr, buf, l, 0);
         }
-        i = 0; 
+        i = 0;
         while (i < l) {
             switch(wsize) {
             default:
@@ -643,25 +693,31 @@
 #define GET_TLONG(h, l) (l)
 #endif
 
-static void do_memory_dump(int count, int format, int size, 
+static void do_memory_dump(int count, int format, int size,
                            uint32_t addrh, uint32_t addrl)
 {
     target_long addr = GET_TLONG(addrh, addrl);
     memory_dump(count, format, size, addr, 0);
 }
 
+#if TARGET_PHYS_ADDR_BITS > 32
+#define GET_TPHYSADDR(h, l) (((uint64_t)(h) << 32) | (l))
+#else
+#define GET_TPHYSADDR(h, l) (l)
+#endif
+
 static void do_physical_memory_dump(int count, int format, int size,
                                     uint32_t addrh, uint32_t addrl)
 
 {
-    target_long addr = GET_TLONG(addrh, addrl);
+    target_phys_addr_t addr = GET_TPHYSADDR(addrh, addrl);
     memory_dump(count, format, size, addr, 1);
 }
 
 static void do_print(int count, int format, int size, unsigned int valh, unsigned int vall)
 {
-    target_long val = GET_TLONG(valh, vall);
-#if TARGET_LONG_BITS == 32
+    target_phys_addr_t val = GET_TPHYSADDR(valh, vall);
+#if TARGET_PHYS_ADDR_BITS == 32
     switch(format) {
     case 'o':
         term_printf("%#o", val);
@@ -703,7 +759,7 @@
     term_printf("\n");
 }
 
-static void do_memory_save(unsigned int valh, unsigned int vall, 
+static void do_memory_save(unsigned int valh, unsigned int vall,
                            uint32_t size, const char *filename)
 {
     FILE *f;
@@ -757,7 +813,7 @@
 static const KeyDef key_defs[] = {
     { 0x2a, "shift" },
     { 0x36, "shift_r" },
-    
+
     { 0x38, "alt" },
     { 0xb8, "alt_r" },
     { 0x1d, "ctrl" },
@@ -812,7 +868,7 @@
     { 0x30, "b" },
     { 0x31, "n" },
     { 0x32, "m" },
-    
+
     { 0x39, "spc" },
     { 0x3a, "caps_lock" },
     { 0x3b, "f1" },
@@ -830,7 +886,7 @@
 
     { 0xb5, "kp_divide" },
     { 0x37, "kp_multiply" },
-    { 0x4a, "kp_substract" },
+    { 0x4a, "kp_subtract" },
     { 0x4e, "kp_add" },
     { 0x9c, "kp_enter" },
     { 0x53, "kp_decimal" },
@@ -845,7 +901,7 @@
     { 0x47, "kp_7" },
     { 0x48, "kp_8" },
     { 0x49, "kp_9" },
-    
+
     { 0x56, "<" },
 
     { 0x57, "f11" },
@@ -892,7 +948,7 @@
     uint8_t keycodes[16];
     const char *p;
     int nb_keycodes, keycode, i;
-    
+
     nb_keycodes = 0;
     p = string;
     while (*p != '\0') {
@@ -932,14 +988,14 @@
 
 static int mouse_button_state;
 
-static void do_mouse_move(const char *dx_str, const char *dy_str, 
+static void do_mouse_move(const char *dx_str, const char *dy_str,
                           const char *dz_str)
 {
     int dx, dy, dz;
     dx = strtol(dx_str, NULL, 0);
     dy = strtol(dy_str, NULL, 0);
     dz = 0;
-    if (dz_str) 
+    if (dz_str)
         dz = strtol(dz_str, NULL, 0);
     kbd_mouse_event(dx, dy, dz, mouse_button_state);
 }
@@ -993,7 +1049,7 @@
 #if defined(TARGET_I386)
 static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
 {
-    term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n", 
+    term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n",
                 addr,
                 pte & mask,
                 pte & PG_GLOBAL_MASK ? 'G' : '-',
@@ -1029,12 +1085,12 @@
                 print_pte((l1 << 22), pde, ~((1 << 20) - 1));
             } else {
                 for(l2 = 0; l2 < 1024; l2++) {
-                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, 
+                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
                                              (uint8_t *)&pte, 4);
                     pte = le32_to_cpu(pte);
                     if (pte & PG_PRESENT_MASK) {
-                        print_pte((l1 << 22) + (l2 << 12), 
-                                  pte & ~PG_PSE_MASK, 
+                        print_pte((l1 << 22) + (l2 << 12),
+                                  pte & ~PG_PSE_MASK,
                                   ~0xfff);
                     }
                 }
@@ -1043,7 +1099,7 @@
     }
 }
 
-static void mem_print(uint32_t *pstart, int *plast_prot, 
+static void mem_print(uint32_t *pstart, int *plast_prot,
                       uint32_t end, int prot)
 {
     int prot1;
@@ -1051,7 +1107,7 @@
     if (prot != prot1) {
         if (*pstart != -1) {
             term_printf("%08x-%08x %08x %c%c%c\n",
-                        *pstart, end, end - *pstart, 
+                        *pstart, end, end - *pstart,
                         prot1 & PG_USER_MASK ? 'u' : '-',
                         'r',
                         prot1 & PG_RW_MASK ? 'w' : '-');
@@ -1091,7 +1147,7 @@
                 mem_print(&start, &last_prot, end, prot);
             } else {
                 for(l2 = 0; l2 < 1024; l2++) {
-                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, 
+                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
                                              (uint8_t *)&pte, 4);
                     pte = le32_to_cpu(pte);
                     end = (l1 << 22) + (l2 << 12);
@@ -1139,7 +1195,7 @@
 #else
     term_printf("kqemu support: not compiled\n");
 #endif
-} 
+}
 
 #ifdef CONFIG_PROFILER
 
@@ -1245,62 +1301,64 @@
 #endif
 
 static term_cmd_t term_cmds[] = {
-    { "help|?", "s?", do_help, 
+    { "help|?", "s?", do_help,
       "[cmd]", "show the help" },
-    { "commit", "s", do_commit, 
+    { "commit", "s", do_commit,
       "device|all", "commit changes to the disk images (if -snapshot is used) or backing files" },
     { "info", "s?", do_info,
       "subcommand", "show various information about the system state" },
     { "q|quit", "", do_quit,
       "", "quit the emulator" },
     { "eject", "-fB", do_eject,
-      "[-f] device", "eject a removable media (use -f to force it)" },
+      "[-f] device", "eject a removable medium (use -f to force it)" },
     { "change", "BF", do_change,
-      "device filename", "change a removable media" },
-    { "screendump", "F", do_screen_dump, 
+      "device filename", "change a removable medium" },
+    { "screendump", "F", do_screen_dump,
       "filename", "save screen into PPM image 'filename'" },
+    { "logfile", "s", do_logfile,
+      "filename", "output logs to 'filename'" },
     { "log", "s", do_log,
-      "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" }, 
+      "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
     { "savevm", "s?", do_savevm,
-      "tag|id", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" }, 
+      "tag|id", "save a VM snapshot. If no tag or id are provided, a new snapshot is created" },
     { "loadvm", "s", do_loadvm,
-      "tag|id", "restore a VM snapshot from its tag or id" }, 
+      "tag|id", "restore a VM snapshot from its tag or id" },
     { "delvm", "s", do_delvm,
-      "tag|id", "delete a VM snapshot from its tag or id" }, 
-    { "stop", "", do_stop, 
+      "tag|id", "delete a VM snapshot from its tag or id" },
+    { "stop", "", do_stop,
       "", "stop emulation", },
-    { "c|cont", "", do_cont, 
+    { "c|cont", "", do_cont,
       "", "resume emulation", },
 #ifdef CONFIG_GDBSTUB
-    { "gdbserver", "i?", do_gdbserver, 
+    { "gdbserver", "s?", do_gdbserver,
       "[port]", "start gdbserver session (default port=1234)", },
 #endif
-    { "x", "/l", do_memory_dump, 
+    { "x", "/l", do_memory_dump,
       "/fmt addr", "virtual memory dump starting at 'addr'", },
-    { "xp", "/l", do_physical_memory_dump, 
+    { "xp", "/l", do_physical_memory_dump,
       "/fmt addr", "physical memory dump starting at 'addr'", },
-    { "p|print", "/l", do_print, 
+    { "p|print", "/l", do_print,
       "/fmt expr", "print expression value (use $reg for CPU register access)", },
-    { "i", "/ii.", do_ioport_read, 
+    { "i", "/ii.", do_ioport_read,
       "/fmt addr", "I/O port read" },
 
-    { "sendkey", "s", do_send_key, 
+    { "sendkey", "s", do_send_key,
       "keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" },
-    { "system_reset", "", do_system_reset, 
+    { "system_reset", "", do_system_reset,
       "", "reset the system" },
-    { "system_powerdown", "", do_system_powerdown, 
+    { "system_powerdown", "", do_system_powerdown,
       "", "send system power down event" },
-    { "sum", "ii", do_sum, 
+    { "sum", "ii", do_sum,
       "addr size", "compute the checksum of a memory region" },
     { "usb_add", "s", do_usb_add,
       "device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" },
     { "usb_del", "s", do_usb_del,
       "device", "remove USB device 'bus.addr'" },
-    { "cpu", "i", do_cpu_set, 
+    { "cpu", "i", do_cpu_set,
       "index", "set the default CPU" },
-    { "mouse_move", "sss?", do_mouse_move, 
+    { "mouse_move", "sss?", do_mouse_move,
       "dx dy [dz]", "send mouse move events" },
-    { "mouse_button", "i", do_mouse_button, 
+    { "mouse_button", "i", do_mouse_button,
       "state", "change mouse button state (1=L, 2=M, 4=R)" },
     { "mouse_set", "i", do_mouse_set,
       "index", "set which mouse device receives events" },
@@ -1311,9 +1369,9 @@
 #endif
      { "stopcapture", "i", do_stop_capture,
        "capture index", "stop capture" },
-    { "memsave", "lis", do_memory_save, 
-      "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'" },
-    { "read_disk_io", "s", do_io_statistics, 
+    { "memsave", "lis", do_memory_save,
+      "addr size file", "save to disk virtual memory dump starting at 'addr' of size 'size'", },
+    { "read_disk_io", "s", do_io_statistics,
       "hdx", "read disk I/O statistics (VMDK format)" },
     { "migrate", "-ds", do_migrate,
       "[-d] command", "migrate the VM using command (use -d to not wait for command to complete)" },
@@ -1321,7 +1379,7 @@
       "", "cancel the current VM migration" },
     { "migrate_set_speed", "s", do_migrate_set_speed,
       "value", "set maximum speed (in bytes) for migrations" },
-    { NULL, NULL, }, 
+    { NULL, NULL, },
 };
 
 static term_cmd_t info_cmds[] = {
@@ -1363,10 +1421,18 @@
       "", "show capture information" },
     { "snapshots", "", do_info_snapshots,
       "", "show the currently saved VM snapshots" },
+    { "pcmcia", "", pcmcia_info,
+      "", "show guest PCMCIA status" },
     { "mice", "", do_info_mice,
       "", "show which guest mouse is receiving events" },
     { "vnc", "", do_info_vnc,
       "", "show the vnc server status"},
+    { "name", "", do_info_name,
+      "", "show the current VM name" },
+#if defined(TARGET_PPC)
+    { "cpustats", "", do_info_cpu_stats,
+      "", "show CPU statistics", },
+#endif
     { "migration", "", do_info_migration,
       "", "show migration information" },
     { NULL, NULL, },
@@ -1419,21 +1485,7 @@
     CPUState *env = mon_get_cpu();
     if (!env)
         return 0;
-    return (env->msr[MSR_POW] << MSR_POW) |
-        (env->msr[MSR_ILE] << MSR_ILE) |
-        (env->msr[MSR_EE] << MSR_EE) |
-        (env->msr[MSR_PR] << MSR_PR) |
-        (env->msr[MSR_FP] << MSR_FP) |
-        (env->msr[MSR_ME] << MSR_ME) |
-        (env->msr[MSR_FE0] << MSR_FE0) |
-        (env->msr[MSR_SE] << MSR_SE) |
-        (env->msr[MSR_BE] << MSR_BE) |
-        (env->msr[MSR_FE1] << MSR_FE1) |
-        (env->msr[MSR_IP] << MSR_IP) |
-        (env->msr[MSR_IR] << MSR_IR) |
-        (env->msr[MSR_DR] << MSR_DR) |
-        (env->msr[MSR_RI] << MSR_RI) |
-        (env->msr[MSR_LE] << MSR_LE);
+    return do_load_msr(env);
 }
 
 static target_long monitor_get_xer (struct MonitorDef *md, int val)
@@ -1441,10 +1493,7 @@
     CPUState *env = mon_get_cpu();
     if (!env)
         return 0;
-    return (env->xer[XER_SO] << XER_SO) |
-        (env->xer[XER_OV] << XER_OV) |
-        (env->xer[XER_CA] << XER_CA) |
-        (env->xer[XER_BC] << XER_BC);
+    return ppc_load_xer(env);
 }
 
 static target_long monitor_get_decr (struct MonitorDef *md, int val)
@@ -1528,6 +1577,7 @@
     SEG("gs", R_GS)
     { "pc", 0, monitor_get_pc, },
 #elif defined(TARGET_PPC)
+    /* General purpose registers */
     { "r0", offsetof(CPUState, gpr[0]) },
     { "r1", offsetof(CPUState, gpr[1]) },
     { "r2", offsetof(CPUState, gpr[2]) },
@@ -1560,15 +1610,56 @@
     { "r29", offsetof(CPUState, gpr[29]) },
     { "r30", offsetof(CPUState, gpr[30]) },
     { "r31", offsetof(CPUState, gpr[31]) },
+    /* Floating point registers */
+    { "f0", offsetof(CPUState, fpr[0]) },
+    { "f1", offsetof(CPUState, fpr[1]) },
+    { "f2", offsetof(CPUState, fpr[2]) },
+    { "f3", offsetof(CPUState, fpr[3]) },
+    { "f4", offsetof(CPUState, fpr[4]) },
+    { "f5", offsetof(CPUState, fpr[5]) },
+    { "f6", offsetof(CPUState, fpr[6]) },
+    { "f7", offsetof(CPUState, fpr[7]) },
+    { "f8", offsetof(CPUState, fpr[8]) },
+    { "f9", offsetof(CPUState, fpr[9]) },
+    { "f10", offsetof(CPUState, fpr[10]) },
+    { "f11", offsetof(CPUState, fpr[11]) },
+    { "f12", offsetof(CPUState, fpr[12]) },
+    { "f13", offsetof(CPUState, fpr[13]) },
+    { "f14", offsetof(CPUState, fpr[14]) },
+    { "f15", offsetof(CPUState, fpr[15]) },
+    { "f16", offsetof(CPUState, fpr[16]) },
+    { "f17", offsetof(CPUState, fpr[17]) },
+    { "f18", offsetof(CPUState, fpr[18]) },
+    { "f19", offsetof(CPUState, fpr[19]) },
+    { "f20", offsetof(CPUState, fpr[20]) },
+    { "f21", offsetof(CPUState, fpr[21]) },
+    { "f22", offsetof(CPUState, fpr[22]) },
+    { "f23", offsetof(CPUState, fpr[23]) },
+    { "f24", offsetof(CPUState, fpr[24]) },
+    { "f25", offsetof(CPUState, fpr[25]) },
+    { "f26", offsetof(CPUState, fpr[26]) },
+    { "f27", offsetof(CPUState, fpr[27]) },
+    { "f28", offsetof(CPUState, fpr[28]) },
+    { "f29", offsetof(CPUState, fpr[29]) },
+    { "f30", offsetof(CPUState, fpr[30]) },
+    { "f31", offsetof(CPUState, fpr[31]) },
+    { "fpscr", offsetof(CPUState, fpscr) },
+    /* Next instruction pointer */
     { "nip|pc", offsetof(CPUState, nip) },
     { "lr", offsetof(CPUState, lr) },
     { "ctr", offsetof(CPUState, ctr) },
     { "decr", 0, &monitor_get_decr, },
     { "ccr", 0, &monitor_get_ccr, },
+    /* Machine state register */
     { "msr", 0, &monitor_get_msr, },
     { "xer", 0, &monitor_get_xer, },
     { "tbu", 0, &monitor_get_tbu, },
     { "tbl", 0, &monitor_get_tbl, },
+#if defined(TARGET_PPC64)
+    /* Address space register */
+    { "asr", offsetof(CPUState, asr) },
+#endif
+    /* Segment registers */
     { "sdr1", offsetof(CPUState, sdr1) },
     { "sr0", offsetof(CPUState, sr[0]) },
     { "sr1", offsetof(CPUState, sr[1]) },
@@ -1691,7 +1782,7 @@
     { NULL },
 };
 
-static void expr_error(const char *fmt) 
+static void expr_error(const char *fmt)
 {
     term_printf(fmt);
     term_printf("\n");
@@ -1740,11 +1831,11 @@
     }
 }
 
-static target_long expr_sum(void);
+static int64_t expr_sum(void);
 
-static target_long expr_unary(void)
+static int64_t expr_unary(void)
 {
-    target_long n;
+    int64_t n;
     char *p;
     int ret;
 
@@ -1782,7 +1873,8 @@
     case '$':
         {
             char buf[128], *q;
-            
+            target_long reg;
+
             pch++;
             q = buf;
             while ((*pch >= 'a' && *pch <= 'z') ||
@@ -1796,11 +1888,12 @@
             while (isspace(*pch))
                 pch++;
             *q = 0;
-            ret = get_monitor_def(&n, buf);
+            ret = get_monitor_def(&reg, buf);
             if (ret == -1)
                 expr_error("unknown register");
-            else if (ret == -2) 
+            else if (ret == -2)
                 expr_error("no cpu defined");
+            n = reg;
         }
         break;
     case '\0':
@@ -1808,7 +1901,7 @@
         n = 0;
         break;
     default:
-#if TARGET_LONG_BITS == 64
+#if TARGET_PHYS_ADDR_BITS > 32
         n = strtoull(pch, &p, 0);
 #else
         n = strtoul(pch, &p, 0);
@@ -1825,11 +1918,11 @@
 }
 
 
-static target_long expr_prod(void)
+static int64_t expr_prod(void)
 {
-    target_long val, val2;
+    int64_t val, val2;
     int op;
-    
+
     val = expr_unary();
     for(;;) {
         op = *pch;
@@ -1844,7 +1937,7 @@
             break;
         case '/':
         case '%':
-            if (val2 == 0) 
+            if (val2 == 0)
                 expr_error("division by zero");
             if (op == '/')
                 val /= val2;
@@ -1856,9 +1949,9 @@
     return val;
 }
 
-static target_long expr_logic(void)
+static int64_t expr_logic(void)
 {
-    target_long val, val2;
+    int64_t val, val2;
     int op;
 
     val = expr_prod();
@@ -1884,9 +1977,9 @@
     return val;
 }
 
-static target_long expr_sum(void)
+static int64_t expr_sum(void)
 {
-    target_long val, val2;
+    int64_t val, val2;
     int op;
 
     val = expr_logic();
@@ -1904,7 +1997,7 @@
     return val;
 }
 
-static int get_expr(target_long *pval, const char **pp)
+static int get_expr(int64_t *pval, const char **pp)
 {
     pch = *pp;
     if (setjmp(expr_env)) {
@@ -2002,7 +2095,7 @@
 #ifdef DEBUG
     term_printf("command='%s'\n", cmdline);
 #endif
-    
+
     /* extract the command name */
     p = cmdline;
     q = cmdname;
@@ -2018,10 +2111,10 @@
         len = sizeof(cmdname) - 1;
     memcpy(cmdname, pstart, len);
     cmdname[len] = '\0';
-    
+
     /* find the command */
     for(cmd = term_cmds; cmd->name != NULL; cmd++) {
-        if (compare_cmd(cmdname, cmd->name)) 
+        if (compare_cmd(cmdname, cmd->name))
             goto found;
     }
     term_printf("unknown command: '%s'\n", cmdname);
@@ -2030,7 +2123,7 @@
 
     for(i = 0; i < MAX_ARGS; i++)
         str_allocated[i] = NULL;
-    
+
     /* parse the parameters */
     typestr = cmd->args_type;
     nb_args = 0;
@@ -2046,8 +2139,8 @@
             {
                 int ret;
                 char *str;
-                
-                while (isspace(*p)) 
+
+                while (isspace(*p))
                     p++;
                 if (*typestr == '?') {
                     typestr++;
@@ -2087,7 +2180,7 @@
         case '/':
             {
                 int count, format, size;
-                
+
                 while (isspace(*p))
                     p++;
                 if (*p == '/') {
@@ -2159,16 +2252,17 @@
                 }
                 if (nb_args + 3 > MAX_ARGS)
                     goto error_args;
-                args[nb_args++] = (void*)count;
-                args[nb_args++] = (void*)format;
-                args[nb_args++] = (void*)size;
+                args[nb_args++] = (void*)(long)count;
+                args[nb_args++] = (void*)(long)format;
+                args[nb_args++] = (void*)(long)size;
             }
             break;
         case 'i':
         case 'l':
             {
-                target_long val;
-                while (isspace(*p)) 
+                int64_t val;
+
+                while (isspace(*p))
                     p++;
                 if (*typestr == '?' || *typestr == '.') {
                     if (*typestr == '?') {
@@ -2179,7 +2273,7 @@
                     } else {
                         if (*p == '.') {
                             p++;
-                            while (isspace(*p)) 
+                            while (isspace(*p))
                                 p++;
                             has_arg = 1;
                         } else {
@@ -2189,7 +2283,7 @@
                     typestr++;
                     if (nb_args >= MAX_ARGS)
                         goto error_args;
-                    args[nb_args++] = (void *)has_arg;
+                    args[nb_args++] = (void *)(long)has_arg;
                     if (!has_arg) {
                         if (nb_args >= MAX_ARGS)
                             goto error_args;
@@ -2203,16 +2297,16 @@
                 if (c == 'i') {
                     if (nb_args >= MAX_ARGS)
                         goto error_args;
-                    args[nb_args++] = (void *)(int)val;
+                    args[nb_args++] = (void *)(long)val;
                 } else {
                     if ((nb_args + 1) >= MAX_ARGS)
                         goto error_args;
-#if TARGET_LONG_BITS == 64
-                    args[nb_args++] = (void *)(int)((val >> 32) & 0xffffffff);
+#if TARGET_PHYS_ADDR_BITS > 32
+                    args[nb_args++] = (void *)(long)((val >> 32) & 0xffffffff);
 #else
                     args[nb_args++] = (void *)0;
 #endif
-                    args[nb_args++] = (void *)(int)(val & 0xffffffff);
+                    args[nb_args++] = (void *)(long)(val & 0xffffffff);
                 }
             }
             break;
@@ -2220,17 +2314,17 @@
             {
                 int has_option;
                 /* option */
-                
+
                 c = *typestr++;
                 if (c == '\0')
                     goto bad_type;
-                while (isspace(*p)) 
+                while (isspace(*p))
                     p++;
                 has_option = 0;
                 if (*p == '-') {
                     p++;
                     if (*p != c) {
-                        term_printf("%s: unsupported option -%c\n", 
+                        term_printf("%s: unsupported option -%c\n",
                                     cmdname, *p);
                         goto fail;
                     }
@@ -2239,7 +2333,7 @@
                 }
                 if (nb_args >= MAX_ARGS)
                     goto error_args;
-                args[nb_args++] = (void *)has_option;
+                args[nb_args++] = (void *)(long)has_option;
             }
             break;
         default:
@@ -2252,7 +2346,7 @@
     while (isspace(*p))
         p++;
     if (*p != '\0') {
-        term_printf("%s: extraneous characters at the end of line\n", 
+        term_printf("%s: extraneous characters at the end of line\n",
                     cmdname);
         goto fail;
     }
@@ -2327,7 +2421,7 @@
     int input_path_len;
     const char *p;
 
-    p = strrchr(input, '/'); 
+    p = strrchr(input, '/');
     if (!p) {
         input_path_len = 0;
         pstrcpy(file_prefix, sizeof(file_prefix), input);
@@ -2536,9 +2630,25 @@
     monitor_start_input();
 }
 
+static int is_first_init = 1;
+
 void monitor_init(CharDriverState *hd, int show_banner)
 {
-    monitor_hd = hd;
+    int i;
+
+    if (is_first_init) {
+        for (i = 0; i < MAX_MON; i++) {
+            monitor_hd[i] = NULL;
+        }
+        is_first_init = 0;
+    }
+    for (i = 0; i < MAX_MON; i++) {
+        if (monitor_hd[i] == NULL) {
+            monitor_hd[i] = hd;
+            break;
+        }
+    }
+
     hide_banner = !show_banner;
 
     qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL);
@@ -2559,8 +2669,12 @@
 void monitor_readline(const char *prompt, int is_password,
                       char *buf, int buf_size)
 {
+    int i;
+
     if (is_password) {
-        qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS);
+        for (i = 0; i < MAX_MON; i++)
+            if (monitor_hd[i] && monitor_hd[i]->focus == 0)
+                qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS);
     }
     readline_start(prompt, is_password, monitor_readline_cb, NULL);
     monitor_readline_buf = buf;
diff --git a/osdep.c b/osdep.c
index d1eff8d..0eaf2ba 100644
--- a/osdep.c
+++ b/osdep.c
@@ -1,8 +1,8 @@
 /*
  * QEMU low level functions
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#include <fcntl.h>
 #ifdef HOST_SOLARIS
 #include <sys/types.h>
 #include <sys/statvfs.h>
@@ -113,7 +114,7 @@
             free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
             if ((ram_size + 8192 * 1024) >= free_space) {
                 ram_mb = (ram_size / (1024 * 1024));
-                fprintf(stderr, 
+                fprintf(stderr,
                         "You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",
                         tmpdir, ram_mb);
                 if (strcmp(tmpdir, "/dev/shm") == 0) {
@@ -122,7 +123,7 @@
                             "mount -t tmpfs -o size=%dm none /dev/shm\n",
                             ram_mb + 16);
                 } else {
-                    fprintf(stderr, 
+                    fprintf(stderr,
                             "Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"
                             "QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
                             "temporary RAM file will be opened.\n");
@@ -131,20 +132,20 @@
                 exit(1);
             }
         }
-        snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", 
+        snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
                  tmpdir);
         phys_ram_fd = mkstemp(phys_ram_file);
         if (phys_ram_fd < 0) {
-            fprintf(stderr, 
+            fprintf(stderr,
                     "warning: could not create temporary file in '%s'.\n"
                     "Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"
                     "Using '/tmp' as fallback.\n",
                     tmpdir);
-            snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX", 
+            snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
                      "/tmp");
             phys_ram_fd = mkstemp(phys_ram_file);
             if (phys_ram_fd < 0) {
-                fprintf(stderr, "Could not create temporary memory file '%s'\n", 
+                fprintf(stderr, "Could not create temporary memory file '%s'\n",
                         phys_ram_file);
                 exit(1);
             }
@@ -153,9 +154,9 @@
     }
     size = (size + 4095) & ~4095;
     ftruncate(phys_ram_fd, phys_ram_size + size);
-    ptr = mmap(NULL, 
-               size, 
-               PROT_WRITE | PROT_READ, MAP_SHARED, 
+    ptr = mmap(NULL,
+               size,
+               PROT_WRITE | PROT_READ, MAP_SHARED,
                phys_ram_fd, phys_ram_size);
     if (ptr == MAP_FAILED) {
         fprintf(stderr, "Could not map physical memory\n");
@@ -216,3 +217,74 @@
     strcpy(ptr, str);
     return ptr;
 }
+
+int qemu_create_pidfile(const char *filename)
+{
+    char buffer[128];
+    int len;
+#ifndef _WIN32
+    int fd;
+
+    fd = open(filename, O_RDWR | O_CREAT, 0600);
+    if (fd == -1)
+        return -1;
+
+    if (lockf(fd, F_TLOCK, 0) == -1)
+        return -1;
+
+    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+    if (write(fd, buffer, len) != len)
+        return -1;
+#else
+    HANDLE file;
+    DWORD flags;
+    OVERLAPPED overlap;
+    BOOL ret;
+
+    /* Open for writing with no sharing. */
+    file = CreateFile(filename, GENERIC_WRITE, 0, NULL,
+		      OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+    if (file == INVALID_HANDLE_VALUE)
+      return -1;
+
+    flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY;
+    overlap.hEvent = 0;
+    /* Lock 1 byte. */
+    ret = LockFileEx(file, flags, 0, 0, 1, &overlap);
+    if (ret == 0)
+      return -1;
+
+    /* Write PID to file. */
+    len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+    ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len,
+		      &overlap, NULL);
+    if (ret == 0)
+      return -1;
+#endif
+    return 0;
+}
+
+#ifdef _WIN32
+
+/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
+#define _W32_FT_OFFSET (116444736000000000ULL)
+
+int qemu_gettimeofday(qemu_timeval *tp)
+{
+  union {
+    unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
+    FILETIME ft;
+  }  _now;
+
+  if(tp)
+    {
+      GetSystemTimeAsFileTime (&_now.ft);
+      tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
+      tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
+    }
+  /* Always return 0 as per Open Group Base Specifications Issue 6.
+     Do not set errno on error.  */
+  return 0;
+}
+#endif /* _WIN32 */
diff --git a/osdep.h b/osdep.h
index 325baf1..50686d5 100644
--- a/osdep.h
+++ b/osdep.h
@@ -15,4 +15,17 @@
 
 void *get_mmap_addr(unsigned long size);
 
+int qemu_create_pidfile(const char *filename);
+
+#ifdef _WIN32
+typedef struct {
+    long tv_sec;
+    long tv_usec;
+} qemu_timeval;
+int qemu_gettimeofday(qemu_timeval *tp);
+#else
+typedef struct timeval qemu_timeval;
+#define qemu_gettimeofday(tp) gettimeofday(tp, NULL);
+#endif /* !_WIN32 */
+
 #endif
diff --git a/pc-bios/Makefile b/pc-bios/Makefile
index 7ae0ff0..c817e85 100644
--- a/pc-bios/Makefile
+++ b/pc-bios/Makefile
@@ -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 $@ $<
 
diff --git a/pc-bios/README b/pc-bios/README
index 45e4b7c..9839fac 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -14,6 +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 and Sparc64 images are built from SVN revision 169.
 
 - The PXE roms come from Rom-o-Matic etherboot 5.4.2.
   pcnet32:pcnet32 -- [0x1022,0x2000]
diff --git a/pc-bios/linux_boot.S b/pc-bios/linux_boot.S
deleted file mode 100644
index 22fcd4b..0000000
--- a/pc-bios/linux_boot.S
+++ /dev/null
@@ -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
diff --git a/pc-bios/linux_boot.bin b/pc-bios/linux_boot.bin
deleted file mode 100644
index 80f7b5f..0000000
--- a/pc-bios/linux_boot.bin
+++ /dev/null
Binary files differ
diff --git a/pc-bios/openbios-sparc b/pc-bios/openbios-sparc
new file mode 100644
index 0000000..7a729aa
--- /dev/null
+++ b/pc-bios/openbios-sparc
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
new file mode 100644
index 0000000..57b129f
--- /dev/null
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/pc-bios/ppc_rom.bin b/pc-bios/ppc_rom.bin
index f7cd8a8..0ad0282 100644
--- a/pc-bios/ppc_rom.bin
+++ b/pc-bios/ppc_rom.bin
Binary files differ
diff --git a/ppc-dis.c b/ppc-dis.c
index f6fad88..f9ae53e 100644
--- a/ppc-dis.c
+++ b/ppc-dis.c
@@ -646,7 +646,7 @@
    same.  */
 
 /*ARGSUSED*/
-static unsigned long 
+static unsigned long
 insert_bat (insn, value, errmsg)
      uint32_t insn;
      int32_t value;
@@ -1122,7 +1122,7 @@
    extraction function just checks that the fields are the same.  */
 
 /*ARGSUSED*/
-static unsigned long 
+static unsigned long
 insert_rbs (insn, value, errmsg)
      uint32_t insn;
      int32_t value;
diff --git a/ppc.ld b/ppc.ld
index d0a0dcb..1e6bbe9 100644
--- a/ppc.ld
+++ b/ppc.ld
@@ -2,8 +2,8 @@
  * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
  */
 OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
-OUTPUT_ARCH(powerpc)
-SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
+OUTPUT_ARCH(powerpc:common)
+SEARCH_DIR(/usr/powerpc-linux-gnu/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib)
 ENTRY(_start)
 SECTIONS
 {
@@ -16,93 +16,179 @@
   .gnu.version   : { *(.gnu.version)	}
   .gnu.version_d   : { *(.gnu.version_d)	}
   .gnu.version_r   : { *(.gnu.version_r)	}
-  .rel.text      :
-    { *(.rel.text) *(.rel.gnu.linkonce.t*) }
-  .rela.text     :
-    { *(.rela.text) *(.rela.gnu.linkonce.t*) }
-  .rel.data      :
-    { *(.rel.data) *(.rel.gnu.linkonce.d*) }
-  .rela.data     :
-    { *(.rela.data) *(.rela.gnu.linkonce.d*) }
-  .rel.rodata    :
-    { *(.rel.rodata) *(.rel.gnu.linkonce.r*) }
-  .rela.rodata   :
-    { *(.rela.rodata) *(.rela.gnu.linkonce.r*) }
-  .rel.got       : { *(.rel.got)		}
-  .rela.got      : { *(.rela.got)		}
-  .rel.ctors     : { *(.rel.ctors)	}
-  .rela.ctors    : { *(.rela.ctors)	}
-  .rel.dtors     : { *(.rel.dtors)	}
-  .rela.dtors    : { *(.rela.dtors)	}
-  .rel.init      : { *(.rel.init)	}
-  .rela.init     : { *(.rela.init)	}
-  .rel.fini      : { *(.rel.fini)	}
-  .rela.fini     : { *(.rela.fini)	}
-  .rel.bss       : { *(.rel.bss)		}
-  .rela.bss      : { *(.rela.bss)		}
-  .rel.plt       : { *(.rel.plt)		}
-  .rela.plt      : { *(.rela.plt)		}
-  .init          : { *(.init)	} =0x47ff041f
-  .text      :
+  .rel.init       : { *(.rel.init) }
+  .rela.init      : { *(.rela.init) }
+  .rel.text       : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) }
+  .rela.text      : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
+  .rel.fini       : { *(.rel.fini) }
+  .rela.fini      : { *(.rela.fini) }
+  .rel.rodata     : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) }
+  .rela.rodata    : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
+  .rel.data.rel.ro   : { *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) }
+  .rela.data.rel.ro   : { *(.rela.data.rel.ro* .rela.gnu.linkonce.d.rel.ro.*) }
+  .rel.data       : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) }
+  .rela.data      : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
+  .rel.tdata	  : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) }
+  .rela.tdata	  : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
+  .rel.tbss	  : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) }
+  .rela.tbss	  : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
+  .rel.ctors      : { *(.rel.ctors) }
+  .rela.ctors     : { *(.rela.ctors) }
+  .rel.dtors      : { *(.rel.dtors) }
+  .rela.dtors     : { *(.rela.dtors) }
+  .rel.got        : { *(.rel.got) }
+  .rela.got       : { *(.rela.got) }
+  .rela.got1           : { *(.rela.got1) }
+  .rela.got2           : { *(.rela.got2) }
+  .rel.sdata      : { *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*) }
+  .rela.sdata     : { *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*) }
+  .rel.sbss       : { *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*) }
+  .rela.sbss      : { *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*) }
+  .rel.sdata2     : { *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*) }
+  .rela.sdata2    : { *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*) }
+  .rel.sbss2      : { *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*) }
+  .rela.sbss2     : { *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*) }
+  .rel.bss        : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) }
+  .rela.bss       : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
+  .rel.plt        : { *(.rel.plt) }
+  .rela.plt       : { *(.rela.plt) }
+  .init           :
   {
-    *(.text)
+    KEEP (*(.init))
+  } =0
+  .text           :
+  {
+    *(.text .stub .text.* .gnu.linkonce.t.*)
+    KEEP (*(.text.*personality*))
     /* .gnu.warning sections are handled specially by elf32.em.  */
     *(.gnu.warning)
-    *(.gnu.linkonce.t*)
+    *(.glink)
   } =0x47ff041f
-  _etext = .;
+  .fini           :
+  {
+    KEEP (*(.fini))
+  } =0x47ff041f
+  PROVIDE (__etext = .);
+  PROVIDE (_etext = .);
   PROVIDE (etext = .);
-  .fini      : { *(.fini)    } =0x47ff041f
-  . = ALIGN(32 / 8);
-  PROVIDE (__preinit_array_start = .);
-  .preinit_array     : { *(.preinit_array) }
-  PROVIDE (__preinit_array_end = .);
-  PROVIDE (__init_array_start = .);
-  .init_array     : { *(.init_array) }
-  PROVIDE (__init_array_end = .);
-  PROVIDE (__fini_array_start = .);
-  .fini_array     : { *(.fini_array) }
-  PROVIDE (__fini_array_end = .);
-  .rodata    : { *(.rodata) *(.gnu.linkonce.r*) }
-  .rodata1   : { *(.rodata1) }
-  .reginfo : { *(.reginfo) }
+  .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+  .rodata1        : { *(.rodata1) }
+  .sdata2         :
+  {
+    PROVIDE (_SDA2_BASE_ = 32768);
+    *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+  }
+  .sbss2          : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
+  .eh_frame_hdr : { *(.eh_frame_hdr) }
+  .eh_frame       : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
   /* Adjust the address for the data segment.  We want to adjust up to
      the same address within the page on the next page up.  */
-  . = ALIGN(0x100000) + (. & (0x100000 - 1));
-  .data    :
+  . = ALIGN (0x10000) - ((0x10000 - .) & (0x10000 - 1)); . = DATA_SEGMENT_ALIGN (0x10000, 0x1000);
+  /* Exception handling  */
+  .eh_frame       : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+  .gcc_except_table   : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+  /* Thread Local Storage sections  */
+  .tdata	  : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+  .tbss		  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+  .preinit_array     :
   {
-    *(.data)
-    *(.gnu.linkonce.d*)
-    CONSTRUCTORS
+    PROVIDE_HIDDEN (__preinit_array_start = .);
+    KEEP (*(.preinit_array))
+    PROVIDE_HIDDEN (__preinit_array_end = .);
   }
-  .data1   : { *(.data1) }
-  .ctors         :
+  .init_array     :
   {
-    *(.ctors)
+     PROVIDE_HIDDEN (__init_array_start = .);
+     KEEP (*(SORT(.init_array.*)))
+     KEEP (*(.init_array))
+     PROVIDE_HIDDEN (__init_array_end = .);
   }
-  .dtors         :
+  .fini_array     :
   {
-    *(.dtors)
+    PROVIDE_HIDDEN (__fini_array_start = .);
+    KEEP (*(.fini_array))
+    KEEP (*(SORT(.fini_array.*)))
+    PROVIDE_HIDDEN (__fini_array_end = .);
   }
-  .plt      : { *(.plt)	}
-  .got           : { *(.got.plt) *(.got) }
-  .dynamic       : { *(.dynamic) }
+  .ctors          :
+  {
+    /* gcc uses crtbegin.o to find the start of
+       the constructors, so we make sure it is
+       first.  Because this is a wildcard, it
+       doesn't matter if the user does not
+       actually link against crtbegin.o; the
+       linker won't look for a file to match a
+       wildcard.  The wildcard also means that it
+       doesn't matter which directory crtbegin.o
+       is in.  */
+    KEEP (*crtbegin*.o(.ctors))
+    /* We don't want to include the .ctor section from
+       the crtend.o file until after the sorted ctors.
+       The .ctor section from the crtend file contains the
+       end of ctors marker and it must be last */
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .ctors))
+    KEEP (*(SORT(.ctors.*)))
+    KEEP (*(.ctors))
+  }
+  .dtors          :
+  {
+    KEEP (*crtbegin*.o(.dtors))
+    KEEP (*(EXCLUDE_FILE (*crtend*.o ) .dtors))
+    KEEP (*(SORT(.dtors.*)))
+    KEEP (*(.dtors))
+  }
+  .jcr            : { KEEP (*(.jcr)) }
+  .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+  .got1           : { *(.got1) }
+  .got2           : { *(.got2) }
+  .dynamic        : { *(.dynamic) }
+  .got            : SPECIAL { *(.got) }
+  . = DATA_SEGMENT_RELRO_END (0, .);
+  .plt            : SPECIAL { *(.plt) }
+  .data           :
+  {
+    *(.data .data.* .gnu.linkonce.d.*)
+    KEEP (*(.gnu.linkonce.d.*personality*))
+    SORT(CONSTRUCTORS)
+  }
+  .data1          : { *(.data1) }
+  .got            : SPECIAL { *(.got) }
   /* We want the small data sections together, so single-instruction offsets
      can access them all, and initialized data all before uninitialized, so
      we can shorten the on-disk segment size.  */
-  .sdata     : { *(.sdata) }
-  _edata  =  .;
-  PROVIDE (edata = .);
+  .sdata          :
+  {
+    PROVIDE (_SDA_BASE_ = 32768);
+    *(.sdata .sdata.* .gnu.linkonce.s.*)
+  }
+  _edata = .; PROVIDE (edata = .);
   __bss_start = .;
-  .sbss      : { *(.sbss) *(.scommon) }
-  .bss       :
+  .sbss           :
+  {
+    PROVIDE (__sbss_start = .); PROVIDE (___sbss_start = .);
+    *(.dynsbss)
+    *(.sbss .sbss.* .gnu.linkonce.sb.*)
+    *(.scommon)
+    PROVIDE (__sbss_end = .); PROVIDE (___sbss_end = .);
+  }
+  .plt            : SPECIAL { *(.plt) }
+  .bss            :
   {
    *(.dynbss)
-   *(.bss)
+   *(.bss .bss.* .gnu.linkonce.b.*)
    *(COMMON)
+   /* Align here to ensure that the .bss section occupies space up to
+      _end.  Align after .bss to ensure correct alignment even if the
+      .bss section disappears because there are no input sections.
+      FIXME: Why do we need it? When there is no .bss section, we don't
+      pad the .data section.  */
+   . = ALIGN(. != 0 ? 32 / 8 : 1);
   }
-  _end = . ;
-  PROVIDE (end = .);
+  . = ALIGN(32 / 8);
+  . = ALIGN(32 / 8);
+  _end = .; PROVIDE (end = .);
+  . = DATA_SEGMENT_END (.);
   /* Stabs debugging sections.  */
   .stab 0 : { *(.stab) }
   .stabstr 0 : { *(.stabstr) }
@@ -137,4 +223,6 @@
   .debug_typenames 0 : { *(.debug_typenames) }
   .debug_varnames  0 : { *(.debug_varnames) }
   /* These must appear regardless of  .  */
+  /DISCARD/    : { *(.fixup) }
+  /DISCARD/ : { *(.note.GNU-stack) }
 }
diff --git a/qemu-binfmt-conf.sh b/qemu-binfmt-conf.sh
index bd278d9..941f0cf 100644
--- a/qemu-binfmt-conf.sh
+++ b/qemu-binfmt-conf.sh
@@ -1,8 +1,13 @@
 #!/bin/sh
-# enable automatic i386/ARM/SPARC/PPC program execution by the kernel
+# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC program execution by the kernel
 
 # load the binfmt_misc module
-/sbin/modprobe binfmt_misc
+if [ ! -d /proc/sys/fs/binfmt_misc ]; then
+  /sbin/modprobe binfmt_misc
+fi
+if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then
+  mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
+fi
 
 # probe cpu type
 cpu=`uname -m`
@@ -10,6 +15,12 @@
   i386|i486|i586|i686|i86pc|BePC)
     cpu="i386"
   ;;
+  m68k)
+    cpu="m68k"
+  ;;
+  mips*)
+    cpu="mips"
+  ;;
   "Power Macintosh"|ppc|ppc64)
     cpu="ppc"
   ;;
@@ -33,7 +44,16 @@
 if [ $cpu != "ppc" ] ; then
     echo   ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register
 fi
+if [ $cpu != "m68k" ] ; then
+    echo   'Please check cpu value and header information for m68k!'
+    echo   ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x04:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register
+fi
 if [ $cpu != "mips" ] ; then
+    # FIXME: We could use the other endianness on a MIPS host.
     echo   ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register
     echo   ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mipsn32:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mipsn32:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mipsn32el:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsn32el:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mips64:M::\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips64:' > /proc/sys/fs/binfmt_misc/register
+    echo   ':mips64el:M::\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mips64el:' > /proc/sys/fs/binfmt_misc/register
 fi
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 834c778..c3a529b 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -50,13 +50,13 @@
 
 @itemize @minus
 
-@item 
+@item
 Full system emulation. In this mode, QEMU emulates a full system (for
 example a PC), including one or several processors and various
 peripherals. It can be used to launch different Operating Systems
 without rebooting the PC or to debug system code.
 
-@item 
+@item
 User mode emulation. In this mode, QEMU can launch
 processes compiled for one CPU on another CPU. It can be used to
 launch the Wine Windows API emulator (@url{http://www.winehq.org}) or
@@ -65,7 +65,7 @@
 @end itemize
 
 QEMU can run without an host kernel driver and yet gives acceptable
-performance. 
+performance.
 
 For system emulation, the following hardware targets are supported:
 @itemize
@@ -77,8 +77,12 @@
 @item Sun4m (32-bit Sparc processor)
 @item Sun4u (64-bit Sparc processor, in progress)
 @item Malta board (32-bit MIPS processor)
-@item ARM Integrator/CP (ARM926E or 1026E processor)
+@item ARM Integrator/CP (ARM926E, 1026E or 946E processor)
 @item ARM Versatile baseboard (ARM926E)
+@item ARM RealView Emulation baseboard (ARM926EJ-S)
+@item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor)
+@item Freescale MCF5208EVB (ColdFire V2).
+@item Arnewsh MCF5206 evaluation board (ColdFire V2).
 @end itemize
 
 For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported.
@@ -125,6 +129,7 @@
 * pcsys_network::      Network emulation
 * direct_linux_boot::  Direct Linux Boot
 * pcsys_usb::          USB emulation
+* vnc_security::       VNC security
 * gdb_usage::          GDB usage
 * pcsys_os_specific::  Target OS specific information
 @end menu
@@ -138,19 +143,19 @@
 following peripherals:
 
 @itemize @minus
-@item 
+@item
 i440FX host PCI bridge and PIIX3 PCI to ISA bridge
 @item
 Cirrus CLGD 5446 PCI VGA card or dummy VGA card with Bochs VESA
 extensions (hardware level, including all non standard modes).
 @item
 PS/2 mouse and keyboard
-@item 
+@item
 2 PCI IDE interfaces with hard disk and CD-ROM support
 @item
 Floppy disk
-@item 
-NE2000 PCI network adapters
+@item
+PCI/ISA PCI network adapters
 @item
 Serial ports
 @item
@@ -239,47 +244,6 @@
 Simulate an SMP system with @var{n} CPUs. On the PC target, up to 255
 CPUs are supported.
 
-@item -nographic
-
-Normally, QEMU uses SDL to display the VGA output. With this option,
-you can totally disable graphical output so that QEMU is a simple
-command line application. The emulated serial port is redirected on
-the console. Therefore, you can still use QEMU to debug a Linux kernel
-with a serial console.
-
-@item -vnc display
-
-Normally, QEMU uses SDL to display the VGA output.  With this option,
-you can have QEMU listen on VNC display @var{display} and redirect the VGA
-display over the VNC session.  It is very useful to enable the usb
-tablet device when using this option (option @option{-usbdevice
-tablet}). When using the VNC display, you must use the @option{-k}
-option to set the keyboard layout if you are not using en-us.
-
-@var{display} may be in the form @var{interface:d}, in which case connections
-will only be allowed from @var{interface} on display @var{d}. Optionally,
-@var{interface} can be omitted.  @var{display} can also be in the form
-@var{unix:path} where @var{path} is the location of a unix socket to listen for
-connections on.
-
-
-@item -k language
-
-Use keyboard layout @var{language} (for example @code{fr} for
-French). This option is only needed where it is not easy to get raw PC
-keycodes (e.g. on Macs, with some X11 servers or with a VNC
-display). You don't normally need to use it on PC/Linux or PC/Windows
-hosts.
-
-The available layouts are:
-@example
-ar  de-ch  es  fo     fr-ca  hu  ja  mk     no  pt-br  sv
-da  en-gb  et  fr     fr-ch  is  lt  nl     pl  ru     th
-de  en-us  fi  fr-be  hr     it  lv  nl-be  pt  sl     tr
-@end example
-
-The default is @code{en-us}.
-
 @item -audio-help
 
 Will show the audio subsystem help: list of drivers, tunable
@@ -302,9 +266,6 @@
 time). This option is needed to have correct date in MS-DOS or
 Windows.
 
-@item -full-screen
-Start in full screen.
-
 @item -pidfile file
 Store the QEMU process PID in @var{file}. It is useful if you launch QEMU
 from a script.
@@ -324,6 +285,121 @@
 Load the contents of file as an option ROM.  This option is useful to load
 things like EtherBoot.
 
+@item -name string
+Sets the name of the guest.  This name will be display in the SDL window
+caption.  The name will also be used for the VNC server.
+
+@end table
+
+Display options:
+@table @option
+
+@item -nographic
+
+Normally, QEMU uses SDL to display the VGA output. With this option,
+you can totally disable graphical output so that QEMU is a simple
+command line application. The emulated serial port is redirected on
+the console. Therefore, you can still use QEMU to debug a Linux kernel
+with a serial console.
+
+@item -no-frame
+
+Do not use decorations for SDL windows and start them using the whole
+available screen space. This makes the using QEMU in a dedicated desktop
+workspace more convenient.
+
+@item -full-screen
+Start in full screen.
+
+@item -vnc display[,option[,option[,...]]]
+
+Normally, QEMU uses SDL to display the VGA output.  With this option,
+you can have QEMU listen on VNC display @var{display} and redirect the VGA
+display over the VNC session.  It is very useful to enable the usb
+tablet device when using this option (option @option{-usbdevice
+tablet}). When using the VNC display, you must use the @option{-k}
+parameter to set the keyboard layout if you are not using en-us. Valid
+syntax for the @var{display} is
+
+@table @code
+
+@item @var{interface:d}
+
+TCP connections will only be allowed from @var{interface} on display @var{d}.
+By convention the TCP port is 5900+@var{d}. Optionally, @var{interface} can
+be omitted in which case the server will bind to all interfaces.
+
+@item @var{unix:path}
+
+Connections will be allowed over UNIX domain sockets where @var{path} is the
+location of a unix socket to listen for connections on.
+
+@item @var{none}
+
+VNC is initialized by not started. The monitor @code{change} command can be used
+to later start the VNC server.
+
+@end table
+
+Following the @var{display} value there may be one or more @var{option} flags
+separated by commas. Valid options are
+
+@table @code
+
+@item @var{password}
+
+Require that password based authentication is used for client connections.
+The password must be set separately using the @code{change} command in the
+@ref{pcsys_monitor}
+
+@item @var{tls}
+
+Require that client use TLS when communicating with the VNC server. This
+uses anonymous TLS credentials so is susceptible to a man-in-the-middle
+attack. It is recommended that this option be combined with either the
+@var{x509} or @var{x509verify} options.
+
+@item @var{x509=/path/to/certificate/dir}
+
+Valid if @var{tls} is specified. Require that x509 credentials are used
+for negotiating the TLS session. The server will send its x509 certificate
+to the client. It is recommended that a password be set on the VNC server
+to provide authentication of the client when this is used. The path following
+this option specifies where the x509 certificates are to be loaded from.
+See the @ref{vnc_security} section for details on generating certificates.
+
+@item @var{x509verify=/path/to/certificate/dir}
+
+Valid if @var{tls} is specified. Require that x509 credentials are used
+for negotiating the TLS session. The server will send its x509 certificate
+to the client, and request that the client send its own x509 certificate.
+The server will validate the client's certificate against the CA certificate,
+and reject clients when validation fails. If the certificate authority is
+trusted, this is a sufficient authentication mechanism. You may still wish
+to set a password on the VNC server as a second authentication layer. The
+path following this option specifies where the x509 certificates are to
+be loaded from. See the @ref{vnc_security} section for details on generating
+certificates.
+
+@end table
+
+@item -k language
+
+Use keyboard layout @var{language} (for example @code{fr} for
+French). This option is only needed where it is not easy to get raw PC
+keycodes (e.g. on Macs, with some X11 servers or with a VNC
+display). You don't normally need to use it on PC/Linux or PC/Windows
+hosts.
+
+The available layouts are:
+@example
+ar  de-ch  es  fo     fr-ca  hu  ja  mk     no  pt-br  sv
+da  en-gb  et  fr     fr-ch  is  lt  nl     pl  ru     th
+de  en-us  fi  fr-be  hr     it  lv  nl-be  pt  sl     tr
+@end example
+
+The default is @code{en-us}.
+
 @end table
 
 USB options:
@@ -342,17 +418,20 @@
 
 @item -net nic[,vlan=n][,macaddr=addr][,model=type]
 Create a new Network Interface Card and connect it to VLAN @var{n} (@var{n}
-= 0 is the default). The NIC is currently an NE2000 on the PC
+= 0 is the default). The NIC is an ne2k_pci by default on the PC
 target. Optionally, the MAC address can be changed. If no
 @option{-net} option is specified, a single NIC is created.
-Qemu can emulate several different models of network card.  Valid values for
-@var{type} are @code{ne2k_pci}, @code{ne2k_isa}, @code{rtl8139},
-@code{smc91c111} and @code{lance}.  Not all devices are supported on all
-targets.
+Qemu can emulate several different models of network card.
+Valid values for @var{type} are
+@code{i82551}, @code{i82557b}, @code{i82559er},
+@code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139},
+@code{smc91c111}, @code{lance} and @code{mcf_fec}.
+Not all devices are supported on all targets.  Use -net nic,model=?
+for a list of available devices for your target.
 
 @item -net user[,vlan=n][,hostname=name]
 Use the user mode network stack which requires no administrator
-priviledge to run.  @option{hostname=name} can be used to specify the client
+privilege to run.  @option{hostname=name} can be used to specify the client
 hostname reported by the builtin DHCP server.
 
 @item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file]
@@ -397,17 +476,18 @@
 @item -net socket[,vlan=n][,fd=h][,mcast=maddr:port]
 
 Create a VLAN @var{n} shared with another QEMU virtual
-machines using a UDP multicast socket, effectively making a bus for 
+machines using a UDP multicast socket, effectively making a bus for
 every QEMU with same multicast address @var{maddr} and @var{port}.
 NOTES:
 @enumerate
-@item 
-Several QEMU can be running on different hosts and share same bus (assuming 
+@item
+Several QEMU can be running on different hosts and share same bus (assuming
 correct multicast setup for these hosts).
 @item
 mcast support is compatible with User Mode Linux (argument @option{eth@var{N}=mcast}), see
 @url{http://user-mode-linux.sf.net}.
-@item Use @option{fd=h} to specify an already opened UDP multicast socket.
+@item
+Use @option{fd=h} to specify an already opened UDP multicast socket.
 @end enumerate
 
 Example:
@@ -438,13 +518,22 @@
 override the default configuration (@option{-net nic -net user}) which
 is activated if no @option{-net} options are provided.
 
-@item -tftp prefix
+@item -tftp dir
 When using the user mode network stack, activate a built-in TFTP
-server. All filenames beginning with @var{prefix} can be downloaded
-from the host to the guest using a TFTP client. The TFTP client on the
-guest must be configured in binary mode (use the command @code{bin} of
-the Unix TFTP client). The host IP address on the guest is as usual
-10.0.2.2.
+server. The files in @var{dir} will be exposed as the root of a TFTP server.
+The TFTP client on the guest must be configured in binary mode (use the command
+@code{bin} of the Unix TFTP client). The host IP address on the guest is as
+usual 10.0.2.2.
+
+@item -bootp file
+When using the user mode network stack, broadcast @var{file} as the BOOTP
+filename.  In conjunction with @option{-tftp}, this can be used to network boot
+a guest from a local directory.
+
+Example (using pxelinux):
+@example
+qemu -hda linux.img -boot n -tftp /path/to/tftp/files -bootp /pxelinux.0
+@end example
 
 @item -smb dir
 When using the user mode network stack, activate a built-in SMB
@@ -502,10 +591,10 @@
 
 @table @option
 
-@item -kernel bzImage 
+@item -kernel bzImage
 Use @var{bzImage} as kernel image.
 
-@item -append cmdline 
+@item -append cmdline
 Use @var{cmdline} as kernel command line
 
 @item -initrd file
@@ -528,8 +617,15 @@
 
 Available character devices are:
 @table @code
-@item vc
-Virtual console
+@item vc[:WxH]
+Virtual console. Optionally, a width and height can be given in pixel with
+@example
+vc:800x600
+@end example
+It is also possible to specify width or height in characters:
+@example
+vc:80Cx24C
+@end example
 @item pty
 [Linux only] Pseudo TTY (a new PTY is automatically allocated)
 @item none
@@ -541,7 +637,7 @@
 parameters are set according to the emulated ones.
 @item /dev/parportN
 [Linux only, parallel port only] Use host parallel port
-@var{N}. Currently only SPP parallel port features can be used.
+@var{N}. Currently SPP and EPP parallel port features can be used.
 @item file:filename
 Write output to filename. No character can be read.
 @item stdio
@@ -551,7 +647,7 @@
 @item COMn
 [Windows only] Use host serial port @var{n}
 @item udp:[remote_host]:remote_port[@@[src_ip]:src_port]
-This implements UDP Net Console.  When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}.  When not using a specifed @var{src_port} a random port is automatically chosen.
+This implements UDP Net Console.  When @var{remote_host} or @var{src_ip} are not specified they default to @code{0.0.0.0}.  When not using a specified @var{src_port} a random port is automatically chosen.
 
 If you just want a simple readonly console you can use @code{netcat} or
 @code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as:
@@ -584,7 +680,7 @@
 the @var{server} option QEMU will wait for a client socket application
 to connect to the port before continuing, unless the @code{nowait}
 option was specified.  The @code{nodelay} option disables the Nagle buffering
-algoritm.  If @var{host} is omitted, 0.0.0.0 is assumed. Only
+algorithm.  If @var{host} is omitted, 0.0.0.0 is assumed. Only
 one TCP connection at a time is accepted. You can use @code{telnet} to
 connect to the corresponding character device.
 @table @code
@@ -610,6 +706,18 @@
 same as if you had specified @code{-serial tcp} except the unix domain socket
 @var{path} is used for connections.
 
+@item mon:dev_string
+This is a special option to allow the monitor to be multiplexed onto
+another serial port.  The monitor is accessed with key sequence of
+@key{Control-a} and then pressing @key{c}. See monitor access
+@ref{pcsys_keys} in the -nographic section for more keys.
+@var{dev_string} should be any one of the serial devices specified
+above.  An example to multiplex the monitor onto a telnet server
+listening on port 4444 would be:
+@table @code
+@item -serial mon:telnet::4444,server,nowait
+@end table
+
 @end table
 
 @item -parallel dev
@@ -629,20 +737,33 @@
 The default device is @code{vc} in graphical mode and @code{stdio} in
 non graphical mode.
 
+@item -echr numeric_ascii_value
+Change the escape character used for switching to the monitor when using
+monitor and serial sharing.  The default is @code{0x01} when using the
+@code{-nographic} option.  @code{0x01} is equal to pressing
+@code{Control-a}.  You can select a different character from the ascii
+control keys where 1 through 26 map to Control-a through Control-z.  For
+instance you could use the either of the following to change the escape
+character to Control-t.
+@table @code
+@item -echr 0x14
+@item -echr 20
+@end table
+
 @item -s
-Wait gdb connection to port 1234 (@pxref{gdb_usage}). 
+Wait gdb connection to port 1234 (@pxref{gdb_usage}).
 @item -p port
 Change gdb connection port.  @var{port} can be either a decimal number
 to specify a TCP port, or a host device (same devices as the serial port).
 @item -S
 Do not start CPU at startup (you must type 'c' in the monitor).
-@item -d             
+@item -d
 Output log in /tmp/qemu.log
 @item -hdachs c,h,s,[,t]
 Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
 @var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
 translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
-all thoses parameters. This option is useful for old MS-DOS disk
+all those parameters. This option is useful for old MS-DOS disk
 images.
 
 @item -L path
@@ -666,7 +787,11 @@
 Start right away with a saved state (@code{loadvm} in monitor)
 
 @item -semihosting
-Enable "Angel" semihosting interface (ARM target machines only).
+Enable semihosting syscall emulation (ARM and M68K target machines only).
+
+On ARM this implements the "Angel" interface.
+On M68K this implements the "ColdFire GDB" interface used by libgloss.
+
 Note that this allows guest direct access to the host filesystem,
 so should only be used with trusted guest OS.
 @end table
@@ -707,10 +832,12 @@
 @table @key
 @item Ctrl-a h
 Print this help
-@item Ctrl-a x    
+@item Ctrl-a x
 Exit emulator
-@item Ctrl-a s    
+@item Ctrl-a s
 Save disk data back to file (if -snapshot)
+@item Ctrl-a t
+toggle console timestamps
 @item Ctrl-a b
 Send break (magic sysrq in Linux)
 @item Ctrl-a c
@@ -742,10 +869,10 @@
 @itemize @minus
 
 @item
-Remove or insert removable medias images
+Remove or insert removable media images
 (such as CD-ROM or floppies)
 
-@item 
+@item
 Freeze/unfreeze the Virtual Machine (VM) and save or restore its state
 from a disk file.
 
@@ -762,10 +889,10 @@
 @item help or ? [cmd]
 Show the help for all commands or just for command @var{cmd}.
 
-@item commit  
+@item commit
 Commit changes to the disk images (if -snapshot is used)
 
-@item info subcommand 
+@item info subcommand
 show various information about the system state
 
 @table @option
@@ -795,10 +922,40 @@
 Quit the emulator.
 
 @item eject [-f] device
-Eject a removable media (use -f to force it).
+Eject a removable medium (use -f to force it).
 
-@item change device filename
-Change a removable media.
+@item change device setting
+
+Change the configuration of a device
+
+@table @option
+@item change @var{diskdevice} @var{filename}
+Change the medium for a removable disk device to point to @var{filename}. eg
+
+@example
+(qemu) change cdrom /path/to/some.iso
+@end example
+
+@item change vnc @var{display,options}
+Change the configuration of the VNC server. The valid syntax for @var{display}
+and @var{options} are described at @ref{sec_invocation}. eg
+
+@example
+(qemu) change vnc localhost:1
+@end example
+
+@item change vnc password
+
+Change the password associated with the VNC server. The monitor will prompt for
+the new password to be entered. VNC passwords are only significant upto 8 letters.
+eg.
+
+@example
+(qemu) change vnc password
+Password: ********
+@end example
+
+@end table
 
 @item screendump filename
 Save screen into PPM image @var{filename}.
@@ -869,11 +1026,11 @@
 data. Its syntax is: @option{/@{count@}@{format@}@{size@}}
 
 @table @var
-@item count 
+@item count
 is the number of items to be dumped.
 
 @item format
-can be x (hexa), d (signed decimal), u (unsigned decimal), o (octal),
+can be x (hex), d (signed decimal), u (unsigned decimal), o (octal),
 c (char) or i (asm instruction).
 
 @item size
@@ -883,11 +1040,11 @@
 
 @end table
 
-Examples: 
+Examples:
 @itemize
 @item
 Dump 10 instructions at the current instruction pointer:
-@example 
+@example
 (qemu) x/10i $eip
 0x90107063:  ret
 0x90107064:  sti
@@ -903,7 +1060,7 @@
 
 @item
 Dump 80 16 bit values at the start of the video memory.
-@smallexample 
+@smallexample
 (qemu) xp/80hx 0xb8000
 0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42
 0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41
@@ -1040,10 +1197,10 @@
 
 VM snapshots currently have the following known limitations:
 @itemize
-@item 
+@item
 They cannot cope with removable devices if they are removed or
 inserted after a snapshot is done.
-@item 
+@item
 A few device drivers still have incomplete snapshot support so their
 state is not saved or restored properly (in particular USB).
 @end itemize
@@ -1062,7 +1219,7 @@
 @subsubsection Linux
 
 On Linux, you can directly use the host device filename instead of a
-disk image filename provided you have enough proviledge to access
+disk image filename provided you have enough privileges to access
 it. For example, use @file{/dev/cdrom} to access to the CDROM or
 @file{/dev/fd0} for the floppy.
 
@@ -1089,11 +1246,11 @@
 
 @table @code
 @item CD
-The prefered syntax is the drive letter (e.g. @file{d:}). The
+The preferred syntax is the drive letter (e.g. @file{d:}). The
 alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is
 supported as an alias to the first CDROM drive.
 
-Currently there is no specific code to handle removable medias, so it
+Currently there is no specific code to handle removable media, so it
 is better to use the @code{change} or @code{eject} monitor commands to
 change or eject media.
 @item Hard disks
@@ -1109,9 +1266,9 @@
 
 @subsubsection Mac OS X
 
-@file{/dev/cdrom} is an alias to the first CDROM. 
+@file{/dev/cdrom} is an alias to the first CDROM.
 
-Currently there is no specific code to handle removable medias, so it
+Currently there is no specific code to handle removable media, so it
 is better to use the @code{change} or @code{eject} monitor commands to
 change or eject media.
 
@@ -1121,7 +1278,7 @@
 QEMU can automatically create a virtual FAT disk image from a
 directory tree. In order to use it, just type:
 
-@example 
+@example
 qemu linux.img -hdb fat:/my_directory
 @end example
 
@@ -1131,14 +1288,14 @@
 
 Floppies can be emulated with the @code{:floppy:} option:
 
-@example 
+@example
 qemu linux.img -fda fat:floppy:/my_directory
 @end example
 
 A read/write support is available for testing (beta stage) with the
 @code{:rw:} option:
 
-@example 
+@example
 qemu linux.img -fda fat:floppy:rw:/my_directory
 @end example
 
@@ -1153,11 +1310,11 @@
 @node pcsys_network
 @section Network emulation
 
-QEMU can simulate several networks cards (NE2000 boards on the PC
+QEMU can simulate several network cards (PCI or ISA cards on the PC
 target) and can connect them to an arbitrary number of Virtual Local
 Area Networks (VLANs). Host TAP devices can be connected to any QEMU
 VLAN. VLAN can be connected between separate instances of QEMU to
-simulate large networks. For simpler usage, a non priviledged user mode
+simulate large networks. For simpler usage, a non privileged user mode
 network stack can replace the TAP device to have a basic network
 connection.
 
@@ -1197,7 +1354,7 @@
 
 By using the option @option{-net user} (default configuration if no
 @option{-net} option is specified), QEMU uses a completely user mode
-network stack (you don't need root priviledge to use the virtual
+network stack (you don't need root privilege to use the virtual
 network). The virtual network configuration is the following:
 
 @example
@@ -1206,7 +1363,7 @@
                            |          (10.0.2.2)
                            |
                            ---->  DNS server (10.0.2.3)
-                           |     
+                           |
                            ---->  SMB server (10.0.2.4)
 @end example
 
@@ -1220,7 +1377,7 @@
 10.0.2.x from the QEMU virtual DHCP server.
 
 Note that @code{ping} is not supported reliably to the internet as it
-would require root priviledges. It means you can only ping the local
+would require root privileges. It means you can only ping the local
 router (10.0.2.2).
 
 When using the built-in TFTP server, the router is also the TFTP
@@ -1300,6 +1457,12 @@
 @item @code{host:vendor_id:product_id}
 Pass through the host device identified by @var{vendor_id:product_id}
 (Linux only)
+@item @code{wacom-tablet}
+Virtual Wacom PenPartner tablet.  This device is similar to the @code{tablet}
+above but it can be used with the tslib library because in addition to touch
+coordinates it reports touch pressure.
+@item @code{keyboard}
+Standard USB keyboard.  Will override the PS/2 keyboard (if present).
 @end table
 
 @node host_usb_devices
@@ -1310,7 +1473,7 @@
 Cameras) are not supported yet.
 
 @enumerate
-@item If you use an early Linux 2.4 kernel, verify that no Linux driver 
+@item If you use an early Linux 2.4 kernel, verify that no Linux driver
 is actually using the USB device. A simple way to do that is simply to
 disable the corresponding kernel module by renaming it from @file{mydriver.o}
 to @file{mydriver.o.disabled}.
@@ -1327,7 +1490,7 @@
 @end example
 
 @item Launch QEMU and do in the monitor:
-@example 
+@example
 info usbhost
   Device 1.2, speed 480 Mb/s
     Class 00: USB device 1234:5678, USB DISK
@@ -1336,7 +1499,7 @@
 hubs, it won't work).
 
 @item Add the device in QEMU by using:
-@example 
+@example
 usb_add host:1234:5678
 @end example
 
@@ -1350,6 +1513,213 @@
 When relaunching QEMU, you may have to unplug and plug again the USB
 device to make it work again (this is a bug).
 
+@node vnc_security
+@section VNC security
+
+The VNC server capability provides access to the graphical console
+of the guest VM across the network. This has a number of security
+considerations depending on the deployment scenarios.
+
+@menu
+* vnc_sec_none::
+* vnc_sec_password::
+* vnc_sec_certificate::
+* vnc_sec_certificate_verify::
+* vnc_sec_certificate_pw::
+* vnc_generate_cert::
+@end menu
+@node vnc_sec_none
+@subsection Without passwords
+
+The simplest VNC server setup does not include any form of authentication.
+For this setup it is recommended to restrict it to listen on a UNIX domain
+socket only. For example
+
+@example
+qemu [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc
+@end example
+
+This ensures that only users on local box with read/write access to that
+path can access the VNC server. To securely access the VNC server from a
+remote machine, a combination of netcat+ssh can be used to provide a secure
+tunnel.
+
+@node vnc_sec_password
+@subsection With passwords
+
+The VNC protocol has limited support for password based authentication. Since
+the protocol limits passwords to 8 characters it should not be considered
+to provide high security. The password can be fairly easily brute-forced by
+a client making repeat connections. For this reason, a VNC server using password
+authentication should be restricted to only listen on the loopback interface
+or UNIX domain sockets. Password ayuthentication is requested with the @code{password}
+option, and then once QEMU is running the password is set with the monitor. Until
+the monitor is used to set the password all clients will be rejected.
+
+@example
+qemu [...OPTIONS...] -vnc :1,password -monitor stdio
+(qemu) change vnc password
+Password: ********
+(qemu)
+@end example
+
+@node vnc_sec_certificate
+@subsection With x509 certificates
+
+The QEMU VNC server also implements the VeNCrypt extension allowing use of
+TLS for encryption of the session, and x509 certificates for authentication.
+The use of x509 certificates is strongly recommended, because TLS on its
+own is susceptible to man-in-the-middle attacks. Basic x509 certificate
+support provides a secure session, but no authentication. This allows any
+client to connect, and provides an encrypted session.
+
+@example
+qemu [...OPTIONS...] -vnc :1,tls,x509=/etc/pki/qemu -monitor stdio
+@end example
+
+In the above example @code{/etc/pki/qemu} should contain at least three files,
+@code{ca-cert.pem}, @code{server-cert.pem} and @code{server-key.pem}. Unprivileged
+users will want to use a private directory, for example @code{$HOME/.pki/qemu}.
+NB the @code{server-key.pem} file should be protected with file mode 0600 to
+only be readable by the user owning it.
+
+@node vnc_sec_certificate_verify
+@subsection With x509 certificates and client verification
+
+Certificates can also provide a means to authenticate the client connecting.
+The server will request that the client provide a certificate, which it will
+then validate against the CA certificate. This is a good choice if deploying
+in an environment with a private internal certificate authority.
+
+@example
+qemu [...OPTIONS...] -vnc :1,tls,x509verify=/etc/pki/qemu -monitor stdio
+@end example
+
+
+@node vnc_sec_certificate_pw
+@subsection With x509 certificates, client verification and passwords
+
+Finally, the previous method can be combined with VNC password authentication
+to provide two layers of authentication for clients.
+
+@example
+qemu [...OPTIONS...] -vnc :1,password,tls,x509verify=/etc/pki/qemu -monitor stdio
+(qemu) change vnc password
+Password: ********
+(qemu)
+@end example
+
+@node vnc_generate_cert
+@subsection Generating certificates for VNC
+
+The GNU TLS packages provides a command called @code{certtool} which can
+be used to generate certificates and keys in PEM format. At a minimum it
+is neccessary to setup a certificate authority, and issue certificates to
+each server. If using certificates for authentication, then each client
+will also need to be issued a certificate. The recommendation is for the
+server to keep its certificates in either @code{/etc/pki/qemu} or for
+unprivileged users in @code{$HOME/.pki/qemu}.
+
+@menu
+* vnc_generate_ca::
+* vnc_generate_server::
+* vnc_generate_client::
+@end menu
+@node vnc_generate_ca
+@subsubsection Setup the Certificate Authority
+
+This step only needs to be performed once per organization / organizational
+unit. First the CA needs a private key. This key must be kept VERY secret
+and secure. If this key is compromised the entire trust chain of the certificates
+issued with it is lost.
+
+@example
+# certtool --generate-privkey > ca-key.pem
+@end example
+
+A CA needs to have a public certificate. For simplicity it can be a self-signed
+certificate, or one issue by a commercial certificate issuing authority. To
+generate a self-signed certificate requires one core piece of information, the
+name of the organization.
+
+@example
+# cat > ca.info <<EOF
+cn = Name of your organization
+ca
+cert_signing_key
+EOF
+# certtool --generate-self-signed \
+           --load-privkey ca-key.pem
+           --template ca.info \
+           --outfile ca-cert.pem
+@end example
+
+The @code{ca-cert.pem} file should be copied to all servers and clients wishing to utilize
+TLS support in the VNC server. The @code{ca-key.pem} must not be disclosed/copied at all.
+
+@node vnc_generate_server
+@subsubsection Issuing server certificates
+
+Each server (or host) needs to be issued with a key and certificate. When connecting
+the certificate is sent to the client which validates it against the CA certificate.
+The core piece of information for a server certificate is the hostname. This should
+be the fully qualified hostname that the client will connect with, since the client
+will typically also verify the hostname in the certificate. On the host holding the
+secure CA private key:
+
+@example
+# cat > server.info <<EOF
+organization = Name  of your organization
+cn = server.foo.example.com
+tls_www_server
+encryption_key
+signing_key
+EOF
+# certtool --generate-privkey > server-key.pem
+# certtool --generate-certificate \
+           --load-ca-certificate ca-cert.pem \
+           --load-ca-privkey ca-key.pem \
+           --load-privkey server server-key.pem \
+           --template server.info \
+           --outfile server-cert.pem
+@end example
+
+The @code{server-key.pem} and @code{server-cert.pem} files should now be securely copied
+to the server for which they were generated. The @code{server-key.pem} is security
+sensitive and should be kept protected with file mode 0600 to prevent disclosure.
+
+@node vnc_generate_client
+@subsubsection Issuing client certificates
+
+If the QEMU VNC server is to use the @code{x509verify} option to validate client
+certificates as its authentication mechanism, each client also needs to be issued
+a certificate. The client certificate contains enough metadata to uniquely identify
+the client, typically organization, state, city, building, etc. On the host holding
+the secure CA private key:
+
+@example
+# cat > client.info <<EOF
+country = GB
+state = London
+locality = London
+organiazation = Name of your organization
+cn = client.foo.example.com
+tls_www_client
+encryption_key
+signing_key
+EOF
+# certtool --generate-privkey > client-key.pem
+# certtool --generate-certificate \
+           --load-ca-certificate ca-cert.pem \
+           --load-ca-privkey ca-key.pem \
+           --load-privkey client-key.pem \
+           --template client.info \
+           --outfile client-cert.pem
+@end example
+
+The @code{client-key.pem} and @code{client-cert.pem} files should now be securely
+copied to the client for which they were generated.
+
 @node gdb_usage
 @section GDB usage
 
@@ -1409,7 +1779,7 @@
 When using a 2.6 guest Linux kernel, verify that the 4G/4G patch is
 not activated because QEMU is slower with this patch. The QEMU
 Accelerator Module is also much slower in this case. Earlier Fedora
-Core 3 Linux kernel (< 2.6.9-1.724_FC3) were known to incorporte this
+Core 3 Linux kernel (< 2.6.9-1.724_FC3) were known to incorporate this
 patch by default. Newer kernels don't have it.
 
 @subsection Windows
@@ -1456,7 +1826,7 @@
 Add/Troubleshoot a device => Add a new device & Next => No, select the
 hardware from a list & Next => NT Apm/Legacy Support & Next => Next
 (again) a few times. Now the driver is installed and Windows 2000 now
-correctly instructs QEMU to shutdown at the appropriate moment. 
+correctly instructs QEMU to shutdown at the appropriate moment.
 
 @subsubsection Share a directory between Unix and Windows
 
@@ -1491,14 +1861,15 @@
 
 QEMU is a generic emulator and it emulates many non PC
 machines. Most of the options are similar to the PC emulator. The
-differences are mentionned in the following sections.
+differences are mentioned in the following sections.
 
 @menu
 * QEMU PowerPC System emulator::
-* Sparc32 System emulator invocation::
-* Sparc64 System emulator invocation::
-* MIPS System emulator invocation::
-* ARM System emulator invocation::
+* Sparc32 System emulator::
+* Sparc64 System emulator::
+* MIPS System emulator::
+* ARM System emulator::
+* ColdFire System emulator::
 @end menu
 
 @node QEMU PowerPC System emulator
@@ -1510,13 +1881,13 @@
 QEMU emulates the following PowerMac peripherals:
 
 @itemize @minus
-@item 
-UniNorth PCI Bridge 
+@item
+UniNorth PCI Bridge
 @item
 PCI VGA compatible card with VESA Bochs Extensions
-@item 
+@item
 2 PMAC IDE interfaces with hard disk and CD-ROM support
-@item 
+@item
 NE2000 PCI adapters
 @item
 Non Volatile RAM
@@ -1527,15 +1898,15 @@
 QEMU emulates the following PREP peripherals:
 
 @itemize @minus
-@item 
+@item
 PCI Bridge
 @item
 PCI VGA compatible card with VESA Bochs Extensions
-@item 
+@item
 2 IDE interfaces with hard disk and CD-ROM support
 @item
 Floppy disk
-@item 
+@item
 NE2000 network adapters
 @item
 Serial port
@@ -1554,23 +1925,23 @@
 
 @table @option
 
-@item -g WxH[xDEPTH]  
+@item -g WxH[xDEPTH]
 
 Set the initial VGA graphic mode. The default is 800x600x15.
 
 @end table
 
-@c man end 
+@c man end
 
 
 More information is available at
 @url{http://perso.magic.fr/l_indien/qemu-ppc/}.
 
-@node Sparc32 System emulator invocation
-@section Sparc32 System emulator invocation
+@node Sparc32 System emulator
+@section Sparc32 System emulator
 
 Use the executable @file{qemu-system-sparc} to simulate a SparcStation 5
-(sun4m architecture). The emulation is somewhat complete.
+or SparcStation 10 (sun4m architecture). The emulation is somewhat complete.
 
 QEMU emulates the following sun4m peripherals:
 
@@ -1579,7 +1950,7 @@
 IOMMU
 @item
 TCX Frame buffer
-@item 
+@item
 Lance (Am7990) Ethernet
 @item
 Non Volatile RAM M48T08
@@ -1590,6 +1961,8 @@
 ESP SCSI controller with hard disk and CD-ROM support
 @item
 Floppy drive
+@item
+CS4231 sound device (only on SS-5, not working yet)
 @end itemize
 
 The number of peripherals is fixed in the architecture.
@@ -1605,20 +1978,34 @@
 
 @c man begin OPTIONS
 
-The following options are specific to the Sparc emulation:
+The following options are specific to the Sparc32 emulation:
 
 @table @option
 
-@item -g WxH
+@item -g WxHx[xDEPTH]
 
-Set the initial TCX graphic mode. The default is 1024x768.
+Set the initial TCX graphic mode. The default is 1024x768x8, currently
+the only other possible mode is 1024x768x24.
+
+@item -prom-env string
+
+Set OpenBIOS variables in NVRAM, for example:
+
+@example
+qemu-system-sparc -prom-env 'auto-boot?=false' \
+ -prom-env 'boot-device=sd(0,2,0):d' -prom-env 'boot-args=linux single'
+@end example
+
+@item -M [SS-5|SS-10]
+
+Set the emulated machine type. Default is SS-5.
 
 @end table
 
-@c man end 
+@c man end
 
-@node Sparc64 System emulator invocation
-@section Sparc64 System emulator invocation
+@node Sparc64 System emulator
+@section Sparc64 System emulator
 
 Use the executable @file{qemu-system-sparc64} to simulate a Sun4u machine.
 The emulator is not usable for anything yet.
@@ -1627,7 +2014,7 @@
 
 @itemize @minus
 @item
-UltraSparc IIi APB PCI Bridge 
+UltraSparc IIi APB PCI Bridge
 @item
 PCI VGA compatible card with VESA Bochs Extensions
 @item
@@ -1636,26 +2023,68 @@
 PC-compatible serial ports
 @end itemize
 
-@node MIPS System emulator invocation
-@section MIPS System emulator invocation
+@node MIPS System emulator
+@section MIPS System emulator
 
 Use the executable @file{qemu-system-mips} to simulate a MIPS machine.
-The emulator is able to boot a Linux kernel and to run a Linux Debian
-installation from NFS. The following devices are emulated:
+Three different machine types are emulated:
 
 @itemize @minus
-@item 
-MIPS R4K CPU
+@item
+A generic ISA PC-like machine "mips"
+@item
+The MIPS Malta prototype board "malta"
+@item
+An ACER Pica "pica61"
+@end itemize
+
+The generic emulation is supported by Debian 'Etch' and is able to
+install Debian into a virtual disk image. The following devices are
+emulated:
+
+@itemize @minus
+@item
+MIPS 24Kf CPU
 @item
 PC style serial port
 @item
+PC style IDE disk
+@item
 NE2000 network card
 @end itemize
 
-More information is available in the QEMU mailing-list archive.
+The Malta emulation supports the following devices:
 
-@node ARM System emulator invocation
-@section ARM System emulator invocation
+@itemize @minus
+@item
+Core board with MIPS 24Kf CPU and Galileo system controller
+@item
+PIIX4 PCI/USB/SMbus controller
+@item
+The Multi-I/O chip's serial device
+@item
+PCnet32 PCI network card
+@item
+Malta FPGA serial device
+@item
+Cirrus VGA graphics card
+@end itemize
+
+The ACER Pica emulation supports:
+
+@itemize @minus
+@item
+MIPS R4000 CPU
+@item
+PC-style IRQ and DMA controllers
+@item
+PC Keyboard
+@item
+IDE controller
+@end itemize
+
+@node ARM System emulator
+@section ARM System emulator
 
 Use the executable @file{qemu-system-arm} to simulate a ARM
 machine. The ARM Integrator/CP board is emulated with the following
@@ -1663,15 +2092,17 @@
 
 @itemize @minus
 @item
-ARM926E or ARM1026E CPU
+ARM926E, ARM1026E or ARM946E CPU
 @item
 Two PL011 UARTs
-@item 
+@item
 SMC 91c111 Ethernet adapter
 @item
 PL110 LCD controller
 @item
 PL050 KMI with PS/2 keyboard and mouse.
+@item
+PL181 MultiMedia Card Interface with SD card.
 @end itemize
 
 The ARM Versatile baseboard is emulated with the following devices:
@@ -1683,7 +2114,7 @@
 PL190 Vectored Interrupt Controller
 @item
 Four PL011 UARTs
-@item 
+@item
 SMC 91c111 Ethernet adapter
 @item
 PL110 LCD controller
@@ -1692,20 +2123,103 @@
 @item
 PCI host bridge.  Note the emulated PCI bridge only provides access to
 PCI memory space.  It does not provide access to PCI IO space.
-This means some devices (eg. ne2k_pci NIC) are not useable, and others
-(eg. rtl8139 NIC) are only useable when the guest drivers use the memory
+This means some devices (eg. ne2k_pci NIC) are not usable, and others
+(eg. rtl8139 NIC) are only usable when the guest drivers use the memory
 mapped control registers.
 @item
 PCI OHCI USB controller.
 @item
 LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices.
+@item
+PL181 MultiMedia Card Interface with SD card.
+@end itemize
+
+The ARM RealView Emulation baseboard is emulated with the following devices:
+
+@itemize @minus
+@item
+ARM926E CPU
+@item
+ARM AMBA Generic/Distributed Interrupt Controller
+@item
+Four PL011 UARTs
+@item
+SMC 91c111 Ethernet adapter
+@item
+PL110 LCD controller
+@item
+PL050 KMI with PS/2 keyboard and mouse
+@item
+PCI host bridge
+@item
+PCI OHCI USB controller
+@item
+LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices
+@item
+PL181 MultiMedia Card Interface with SD card.
+@end itemize
+
+The XScale-based clamshell PDA models ("Spitz", "Akita", "Borzoi"
+and "Terrier") emulation includes the following peripherals:
+
+@itemize @minus
+@item
+Intel PXA270 System-on-chip (ARM V5TE core)
+@item
+NAND Flash memory
+@item
+IBM/Hitachi DSCM microdrive in a PXA PCMCIA slot - not in "Akita"
+@item
+On-chip OHCI USB controller
+@item
+On-chip LCD controller
+@item
+On-chip Real Time Clock
+@item
+TI ADS7846 touchscreen controller on SSP bus
+@item
+Maxim MAX1111 analog-digital converter on I@math{^2}C bus
+@item
+GPIO-connected keyboard controller and LEDs
+@item
+Secure Digital card connected to PXA MMC/SD host
+@item
+Three on-chip UARTs
+@item
+WM8750 audio CODEC on I@math{^2}C and I@math{^2}S busses
 @end itemize
 
 A Linux 2.6 test image is available on the QEMU web site. More
 information is available in the QEMU mailing-list archive.
 
-@node QEMU User space emulator 
-@chapter QEMU User space emulator 
+@node ColdFire System emulator
+@section ColdFire System emulator
+
+Use the executable @file{qemu-system-m68k} to simulate a ColdFire machine.
+The emulator is able to boot a uClinux kernel.
+
+The M5208EVB emulation includes the following devices:
+
+@itemize @minus
+@item
+MCF5208 ColdFire V2 Microprocessor (ISA A+ with EMAC).
+@item
+Three Two on-chip UARTs.
+@item
+Fast Ethernet Controller (FEC)
+@end itemize
+
+The AN5206 emulation includes the following devices:
+
+@itemize @minus
+@item
+MCF5206 ColdFire V2 Microprocessor.
+@item
+Two on-chip UARTs.
+@end itemize
+
+@node QEMU User space emulator
+@chapter QEMU User space emulator
 
 @menu
 * Supported Operating Systems ::
@@ -1720,9 +2234,9 @@
 
 @itemize @minus
 @item
-Linux (refered as qemu-linux-user)
+Linux (referred as qemu-linux-user)
 @item
-Mac OS X/Darwin (refered as qemu-darwin-user)
+Mac OS X/Darwin (referred as qemu-darwin-user)
 @end itemize
 
 @node Linux User space emulator
@@ -1739,23 +2253,24 @@
 @subsection Quick Start
 
 In order to launch a Linux process, QEMU needs the process executable
-itself and all the target (x86) dynamic libraries used by it. 
+itself and all the target (x86) dynamic libraries used by it.
 
 @itemize
 
 @item On x86, you can just try to launch any process by using the native
 libraries:
 
-@example 
+@example
 qemu-i386 -L / /bin/ls
 @end example
 
 @code{-L /} tells that the x86 dynamic linker must be searched with a
 @file{/} prefix.
 
-@item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources):
+@item Since QEMU is also a linux process, you can launch qemu with
+qemu (NOTE: you can only do that if you compiled QEMU from the sources):
 
-@example 
+@example
 qemu-i386 -L / qemu-i386 -L / /bin/ls
 @end example
 
@@ -1764,7 +2279,7 @@
 @code{LD_LIBRARY_PATH} is not set:
 
 @example
-unset LD_LIBRARY_PATH 
+unset LD_LIBRARY_PATH
 @end example
 
 Then you can launch the precompiled @file{ls} x86 executable:
@@ -1799,7 +2314,7 @@
 @end example
 
 @item Download the binary x86 Wine install
-(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page). 
+(@file{qemu-XXX-i386-wine.tar.gz} on the QEMU web page).
 
 @item Configure Wine on your account. Look at the provided script
 @file{/usr/local/qemu-i386/@/bin/wine-conf.sh}. Your previous
@@ -1824,7 +2339,7 @@
 @table @option
 @item -h
 Print the help
-@item -L path   
+@item -L path
 Set the x86 elf interpreter prefix (default=/usr/local/qemu-i386)
 @item -s size
 Set the x86 stack size in bytes (default=524288)
@@ -1870,7 +2385,7 @@
 @item
 target PowerPC on x86: Not working as the ppc commpage can't be mapped (yet!)
 @item
-target x86 on x86: Most apps (Cocoa and Carbon too) works. [1]
+target PowerPC on PowerPC: Most apps (Cocoa and Carbon too) works. [1]
 @item
 target x86 on PowerPC: most utilities work. Cocoa and Carbon apps are not yet supported.
 @end itemize
@@ -1890,21 +2405,21 @@
 @item On x86, you can just try to launch any process by using the native
 libraries:
 
-@example 
-qemu-darwin-i386 /bin/ls
+@example
+qemu-i386 /bin/ls
 @end example
 
 or to run the ppc version of the executable:
 
-@example 
-qemu-darwin-ppc /bin/ls
+@example
+qemu-ppc /bin/ls
 @end example
 
 @item On ppc, you'll have to tell qemu where your x86 libraries (and dynamic linker)
 are installed:
 
-@example 
-qemu-darwin-i386 -L /opt/x86_root/ /bin/ls
+@example
+qemu-i386 -L /opt/x86_root/ /bin/ls
 @end example
 
 @code{-L /opt/x86_root/} tells that the dynamic linker (dyld) path is in
@@ -1916,13 +2431,13 @@
 @subsection Command line options
 
 @example
-usage: qemu-darwin-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
+usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
 @end example
 
 @table @option
 @item -h
 Print the help
-@item -L path   
+@item -L path
 Set the library root path (default=/)
 @item -s size
 Set the stack size in bytes (default=524288)
@@ -1979,7 +2494,7 @@
 Linux distribution includes a gcc 4.x compiler, you can usually
 install an older version (it is invoked by @code{gcc32} or
 @code{gcc34}). The QEMU configure script automatically probes for
-these older versions so that usally you don't have to do anything.
+these older versions so that usually you don't have to do anything.
 
 @node Windows
 @section Windows
@@ -1989,7 +2504,7 @@
 @url{http://www.mingw.org/}. You can find detailed installation
 instructions in the download section and the FAQ.
 
-@item Download 
+@item Download
 the MinGW development library of SDL 1.2.x
 (@file{SDL-devel-1.2.x-@/mingw32.tar.gz}) from
 @url{http://www.libsdl.org}. Unpack it in a temporary place, and
@@ -1998,14 +2513,14 @@
 correct SDL directory when invoked.
 
 @item Extract the current version of QEMU.
- 
+
 @item Start the MSYS shell (file @file{msys.bat}).
 
-@item Change to the QEMU directory. Launch @file{./configure} and 
+@item Change to the QEMU directory. Launch @file{./configure} and
 @file{make}.  If you have problems using SDL, verify that
 @file{sdl-config} can be launched from the MSYS command line.
 
-@item You can install QEMU in @file{Program Files/Qemu} by typing 
+@item You can install QEMU in @file{Program Files/Qemu} by typing
 @file{make install}. Don't forget to copy @file{SDL.dll} in
 @file{Program Files/Qemu}.
 
@@ -2019,24 +2534,24 @@
 Install the MinGW cross compilation tools available at
 @url{http://www.mingw.org/}.
 
-@item 
+@item
 Install the Win32 version of SDL (@url{http://www.libsdl.org}) by
 unpacking @file{i386-mingw32msvc.tar.gz}. Set up the PATH environment
 variable so that @file{i386-mingw32msvc-sdl-config} can be launched by
 the QEMU configuration script.
 
-@item 
+@item
 Configure QEMU for Windows cross compilation:
 @example
 ./configure --enable-mingw32
 @end example
 If necessary, you can change the cross-prefix according to the prefix
-choosen for the MinGW tools with --cross-prefix. You can also use
+chosen for the MinGW tools with --cross-prefix. You can also use
 --prefix to set the Win32 install path.
 
-@item You can install QEMU in the installation directory by typing 
+@item You can install QEMU in the installation directory by typing
 @file{make install}. Don't forget to copy @file{SDL.dll} in the
-installation directory. 
+installation directory.
 
 @end itemize
 
diff --git a/qemu-img.c b/qemu-img.c
index a259546..d021082 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1,8 +1,8 @@
 /*
  * QEMU disk image utility
- * 
+ *
  * Copyright (c) 2003-2007 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -22,6 +22,7 @@
  * THE SOFTWARE.
  */
 #include "vl.h"
+#include "block_int.h"
 
 #ifdef _WIN32
 #include <windows.h>
@@ -75,7 +76,7 @@
     term_printf(filename);
 }
 
-void __attribute__((noreturn)) error(const char *fmt, ...) 
+void __attribute__((noreturn)) error(const char *fmt, ...)
 {
     va_list ap;
     va_start(ap, fmt);
@@ -98,9 +99,9 @@
            "QEMU disk image utility\n"
            "\n"
            "Command syntax:\n"
-           "  create [-e] [-b base_image] [-f fmt] filename [size]\n"
+           "  create [-e] [-6] [-b base_image] [-f fmt] filename [size]\n"
            "  commit [-f fmt] filename\n"
-           "  convert [-c] [-e] [-f fmt] filename [-O output_fmt] output_filename\n"
+           "  convert [-c] [-e] [-6] [-f fmt] filename [-O output_fmt] output_filename\n"
            "  info [-f fmt] filename\n"
            "\n"
            "Command parameters:\n"
@@ -114,6 +115,7 @@
            "  'output_fmt' is the destination format\n"
            "  '-c' indicates that target image must be compressed (qcow format only)\n"
            "  '-e' indicates that the target image must be encrypted (qcow format only)\n"
+           "  '-6' indicates that the target image must use compatibility level 6 (vmdk format only)\n"
            );
     printf("\nSupported format:");
     bdrv_iterate_format(format_print, NULL);
@@ -166,7 +168,7 @@
     tty.c_cflag |= CS8;
     tty.c_cc[VMIN] = 1;
     tty.c_cc[VTIME] = 0;
-    
+
     tcsetattr (0, TCSANOW, &tty);
 
     atexit(term_exit);
@@ -241,17 +243,17 @@
 
 static int img_create(int argc, char **argv)
 {
-    int c, ret, encrypted;
+    int c, ret, flags;
     const char *fmt = "raw";
     const char *filename;
     const char *base_filename = NULL;
     int64_t size;
     const char *p;
     BlockDriver *drv;
-    
-    encrypted = 0;
+
+    flags = 0;
     for(;;) {
-        c = getopt(argc, argv, "b:f:he");
+        c = getopt(argc, argv, "b:f:he6");
         if (c == -1)
             break;
         switch(c) {
@@ -265,11 +267,14 @@
             fmt = optarg;
             break;
         case 'e':
-            encrypted = 1;
+            flags |= BLOCK_FLAG_ENCRYPT;
             break;
+		case '6':
+            flags |= BLOCK_FLAG_COMPAT6;
+			break;
         }
     }
-    if (optind >= argc) 
+    if (optind >= argc)
         help();
     filename = argv[optind++];
     size = 0;
@@ -297,16 +302,18 @@
     drv = bdrv_find_format(fmt);
     if (!drv)
         error("Unknown file format '%s'", fmt);
-    printf("Formating '%s', fmt=%s",
+    printf("Formatting '%s', fmt=%s",
            filename, fmt);
-    if (encrypted)
+    if (flags & BLOCK_FLAG_ENCRYPT)
         printf(", encrypted");
+    if (flags & BLOCK_FLAG_COMPAT6)
+        printf(", compatibility level=6");
     if (base_filename) {
         printf(", backing_file=%s",
                base_filename);
     }
     printf(", size=%" PRId64 " kB\n", (int64_t) (size / 1024));
-    ret = bdrv_create(drv, filename, size / 512, base_filename, encrypted);
+    ret = bdrv_create(drv, filename, size / 512, base_filename, flags);
     if (ret < 0) {
         if (ret == -ENOTSUP) {
             error("Formatting or formatting option not supported for file format '%s'", fmt);
@@ -338,7 +345,7 @@
             break;
         }
     }
-    if (optind >= argc) 
+    if (optind >= argc)
         help();
     filename = argv[optind++];
 
@@ -411,7 +418,7 @@
 
 static int img_convert(int argc, char **argv)
 {
-    int c, ret, n, n1, compress, cluster_size, cluster_sectors, encrypt;
+    int c, ret, n, n1, flags, cluster_size, cluster_sectors;
     const char *filename, *fmt, *out_fmt, *out_filename;
     BlockDriver *drv;
     BlockDriverState *bs, *out_bs;
@@ -422,10 +429,9 @@
 
     fmt = NULL;
     out_fmt = "raw";
-    compress = 0;
-    encrypt = 0;
+    flags = 0;
     for(;;) {
-        c = getopt(argc, argv, "f:O:hce");
+        c = getopt(argc, argv, "f:O:hce6");
         if (c == -1)
             break;
         switch(c) {
@@ -439,33 +445,38 @@
             out_fmt = optarg;
             break;
         case 'c':
-            compress = 1;
+            flags |= BLOCK_FLAG_COMPRESS;
             break;
         case 'e':
-            encrypt = 1;
+            flags |= BLOCK_FLAG_ENCRYPT;
+            break;
+        case '6':
+            flags |= BLOCK_FLAG_COMPAT6;
             break;
         }
     }
-    if (optind >= argc) 
+    if (optind >= argc)
         help();
     filename = argv[optind++];
-    if (optind >= argc) 
+    if (optind >= argc)
         help();
     out_filename = argv[optind++];
-    
+
     bs = bdrv_new_open(filename, fmt);
 
     drv = bdrv_find_format(out_fmt);
     if (!drv)
-        error("Unknown file format '%s'", fmt);
-    if (compress && drv != &bdrv_qcow && drv != &bdrv_qcow2)
+        error("Unknown file format '%s'", out_fmt);
+    if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_qcow && drv != &bdrv_qcow2)
         error("Compression not supported for this file format");
-    if (encrypt && drv != &bdrv_qcow && drv != &bdrv_qcow2)
+    if (flags & BLOCK_FLAG_ENCRYPT && drv != &bdrv_qcow && drv != &bdrv_qcow2)
         error("Encryption not supported for this file format");
-    if (compress && encrypt)
+    if (flags & BLOCK_FLAG_COMPRESS && drv != &bdrv_vmdk)
+        error("Alternative compatibility level not supported for this file format");
+    if (flags & BLOCK_FLAG_ENCRYPT && flags & BLOCK_FLAG_COMPRESS)
         error("Compression and encryption not supported at the same time");
     bdrv_get_geometry(bs, &total_sectors);
-    ret = bdrv_create(drv, out_filename, total_sectors, NULL, encrypt);
+    ret = bdrv_create(drv, out_filename, total_sectors, NULL, flags);
     if (ret < 0) {
         if (ret == -ENOTSUP) {
             error("Formatting not supported for file format '%s'", fmt);
@@ -473,10 +484,10 @@
             error("Error while formatting '%s'", out_filename);
         }
     }
-    
+
     out_bs = bdrv_new_open(out_filename, out_fmt);
 
-    if (compress) {
+    if (flags && BLOCK_FLAG_COMPRESS) {
         if (bdrv_get_info(out_bs, &bdi) < 0)
             error("could not get block driver info");
         cluster_size = bdi.cluster_size;
@@ -492,12 +503,12 @@
                 n = cluster_sectors;
             else
                 n = nb_sectors;
-            if (bdrv_read(bs, sector_num, buf, n) < 0) 
+            if (bdrv_read(bs, sector_num, buf, n) < 0)
                 error("error while reading");
             if (n < cluster_sectors)
                 memset(buf + n * 512, 0, cluster_size - n * 512);
             if (is_not_zero(buf, cluster_size)) {
-                if (bdrv_write_compressed(out_bs, sector_num, buf, 
+                if (bdrv_write_compressed(out_bs, sector_num, buf,
                                           cluster_sectors) != 0)
                     error("error while compressing sector %" PRId64,
                           sector_num);
@@ -516,7 +527,7 @@
                 n = (IO_BUF_SIZE / 512);
             else
                 n = nb_sectors;
-            if (bdrv_read(bs, sector_num, buf, n) < 0) 
+            if (bdrv_read(bs, sector_num, buf, n) < 0)
                 error("error while reading");
             /* NOTE: at the same time we convert, we do not write zero
                sectors to have a chance to compress the image. Ideally, we
@@ -524,7 +535,7 @@
             buf1 = buf;
             while (n > 0) {
                 if (is_allocated_sectors(buf1, n, &n1)) {
-                    if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) 
+                    if (bdrv_write(out_bs, sector_num, buf1, n1) < 0)
                         error("error while writing");
                 }
                 sector_num += n1;
@@ -554,7 +565,7 @@
 	    return (((int64_t) high) << 32) + low;
     }
 
-    if (_stati64(filename, &st) < 0) 
+    if (_stati64(filename, &st) < 0)
         return -1;
     return st.st_size;
 }
@@ -562,7 +573,7 @@
 static int64_t get_allocated_file_size(const char *filename)
 {
     struct stat st;
-    if (stat(filename, &st) < 0) 
+    if (stat(filename, &st) < 0)
         return -1;
     return (int64_t)st.st_blocks * 512;
 }
@@ -612,7 +623,7 @@
             break;
         }
     }
-    if (optind >= argc) 
+    if (optind >= argc)
         help();
     filename = argv[optind++];
 
@@ -636,26 +647,26 @@
     if (allocated_size < 0)
 	sprintf(dsize_buf, "unavailable");
     else
-        get_human_readable_size(dsize_buf, sizeof(dsize_buf), 
+        get_human_readable_size(dsize_buf, sizeof(dsize_buf),
                                 allocated_size);
     printf("image: %s\n"
            "file format: %s\n"
            "virtual size: %s (%" PRId64 " bytes)\n"
            "disk size: %s\n",
-           filename, fmt_name, size_buf, 
+           filename, fmt_name, size_buf,
            (total_sectors * 512),
            dsize_buf);
     if (bdrv_is_encrypted(bs))
         printf("encrypted: yes\n");
     if (bdrv_get_info(bs, &bdi) >= 0) {
-        if (bdi.cluster_size != 0) 
+        if (bdi.cluster_size != 0)
             printf("cluster_size: %d\n", bdi.cluster_size);
     }
     bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
     if (backing_filename[0] != '\0') {
         path_combine(backing_filename2, sizeof(backing_filename2),
                      filename, backing_filename);
-        printf("backing file: %s (actual path: %s)\n", 
+        printf("backing file: %s (actual path: %s)\n",
                backing_filename,
                backing_filename2);
     }
diff --git a/qemu-img.texi b/qemu-img.texi
index 1f01dce..89f912d 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -8,9 +8,9 @@
 
 The following commands are supported:
 @table @option
-@item create [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}]
+@item create [-e] [-6] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}]
 @item commit [-f @var{fmt}] @var{filename}
-@item convert [-c] [-e] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename}
+@item convert [-c] [-e] [-6] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename}
 @item info [-f @var{fmt}] @var{filename}
 @end table
 
@@ -18,11 +18,11 @@
 @table @var
 @item filename
  is a disk image filename
-@item base_image 
+@item base_image
 is the read-only disk image which is used as base for a copy on
     write image; the copy on write image only stores the modified data
 
-@item fmt 
+@item fmt
 is the disk image format. It is guessed automatically in most cases. The following formats are supported:
 
 @table @code
@@ -53,29 +53,31 @@
 CD-ROM images present for example in the Knoppix CD-ROMs.
 @end table
 
-@item size 
+@item size
 is the disk image size in kilobytes. Optional suffixes @code{M}
-(megabyte) and @code{G} (gigabyte) are supported 
+(megabyte) and @code{G} (gigabyte) are supported
 
 @item output_filename
-is the destination disk image filename 
+is the destination disk image filename
 
 @item output_fmt
  is the destination format
 
 @item -c
 indicates that target image must be compressed (qcow format only)
-@item -e 
+@item -e
 indicates that the target image must be encrypted (qcow format only)
+@item -6
+indicates that the target image must use compatibility level 6 (vmdk format only)
 @end table
 
 Command description:
 
 @table @option
-@item create [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}]
+@item create [-6] [-e] [-b @var{base_image}] [-f @var{fmt}] @var{filename} [@var{size}]
 
 Create the new disk image @var{filename} of size @var{size} and format
-@var{fmt}. 
+@var{fmt}.
 
 If @var{base_image} is specified, then the image will record only the
 differences from @var{base_image}. No size needs to be specified in
@@ -89,7 +91,7 @@
 @item convert [-c] [-e] [-f @var{fmt}] @var{filename} [-O @var{output_fmt}] @var{output_filename}
 
 Convert the disk image @var{filename} to disk image @var{output_filename}
-using format @var{output_fmt}. It can be optionnaly encrypted
+using format @var{output_fmt}. It can be optionally encrypted
 (@code{-e} option) or compressed (@code{-c} option).
 
 Only the format @code{qcow} supports encryption or compression. The
diff --git a/qemu-tech.texi b/qemu-tech.texi
index 77bda86..242bbb6 100644
--- a/qemu-tech.texi
+++ b/qemu-tech.texi
@@ -35,6 +35,7 @@
 * intro_features::        Features
 * intro_x86_emulation::   x86 emulation
 * intro_arm_emulation::   ARM emulation
+* intro_mips_emulation::  MIPS emulation
 * intro_ppc_emulation::   PowerPC emulation
 * intro_sparc_emulation:: SPARC emulation
 @end menu
@@ -49,13 +50,13 @@
 
 @itemize @minus
 
-@item 
+@item
 Full system emulation. In this mode, QEMU emulates a full system
 (usually a PC), including a processor and various peripherals. It can
 be used to launch an different Operating System without rebooting the
 PC or to debug system code.
 
-@item 
+@item
 User mode emulation (Linux host only). In this mode, QEMU can launch
 Linux processes compiled for one CPU on another CPU. It can be used to
 launch the Wine Windows API emulator (@url{http://www.winehq.org}) or
@@ -68,7 +69,7 @@
 
 QEMU generic features:
 
-@itemize 
+@itemize
 
 @item User space only or full system emulation.
 
@@ -80,23 +81,23 @@
 
 @item Precise exceptions support.
 
-@item The virtual CPU is a library (@code{libqemu}) which can be used 
+@item The virtual CPU is a library (@code{libqemu}) which can be used
 in other projects (look at @file{qemu/tests/qruncom.c} to have an
 example of user mode @code{libqemu} usage).
 
 @end itemize
 
 QEMU user mode emulation features:
-@itemize 
+@itemize
 @item Generic Linux system call converter, including most ioctls.
 
 @item clone() emulation using native CPU clone() to use Linux scheduler for threads.
 
-@item Accurate signal handling by remapping host signals to target signals. 
+@item Accurate signal handling by remapping host signals to target signals.
 @end itemize
 
 QEMU full system emulation features:
-@itemize 
+@itemize
 @item QEMU can either use a full software MMU for maximum portability or use the host system call mmap() to simulate the target MMU.
 @end itemize
 
@@ -105,23 +106,23 @@
 
 QEMU x86 target features:
 
-@itemize 
+@itemize
 
-@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation. 
+@item The virtual x86 CPU supports 16 bit and 32 bit addressing with segmentation.
 LDT/GDT and IDT are emulated. VM86 mode is also supported to run DOSEMU.
 
 @item Support of host page sizes bigger than 4KB in user mode emulation.
 
 @item QEMU can emulate itself on x86.
 
-@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}. 
+@item An extensive Linux x86 CPU test program is included @file{tests/test-i386}.
 It can be used to test other x86 virtual CPUs.
 
 @end itemize
 
 Current QEMU limitations:
 
-@itemize 
+@itemize
 
 @item No SSE/MMX support (yet).
 
@@ -129,11 +130,11 @@
 
 @item IPC syscalls are missing.
 
-@item The x86 segment limits and access rights are not tested at every 
+@item The x86 segment limits and access rights are not tested at every
 memory access (yet). Hopefully, very few OSes seem to rely on that for
 normal use.
 
-@item On non x86 host CPUs, @code{double}s are used instead of the non standard 
+@item On non x86 host CPUs, @code{double}s are used instead of the non standard
 10 byte @code{long double}s of x86 for floating point emulation to get
 maximum performances.
 
@@ -152,12 +153,39 @@
 
 @end itemize
 
+@node intro_mips_emulation
+@section MIPS emulation
+
+@itemize
+
+@item The system emulation allows full MIPS32/MIPS64 Release 2 emulation,
+including privileged instructions, FPU and MMU, in both little and big
+endian modes.
+
+@item The Linux userland emulation can run many 32 bit MIPS Linux binaries.
+
+@end itemize
+
+Current QEMU limitations:
+
+@itemize
+
+@item Self-modifying code is not always handled correctly.
+
+@item 64 bit userland emulation is not implemented.
+
+@item The system emulation is not complete enough to run real firmware.
+
+@item The watchpoint debug facility is not implemented.
+
+@end itemize
+
 @node intro_ppc_emulation
 @section PowerPC emulation
 
 @itemize
 
-@item Full PowerPC 32 bit emulation, including privileged instructions, 
+@item Full PowerPC 32 bit emulation, including privileged instructions,
 FPU and MMU.
 
 @item Can run most PowerPC Linux binaries.
@@ -169,20 +197,17 @@
 
 @itemize
 
-@item Somewhat complete SPARC V8 emulation, including privileged
+@item Full SPARC V8 emulation, including privileged
 instructions, FPU and MMU. SPARC V9 emulation includes most privileged
-instructions, FPU and I/D MMU, but misses VIS instructions.
+instructions, FPU and I/D MMU, but misses most VIS instructions.
 
-@item Can run some 32-bit SPARC Linux binaries.
+@item Can run most 32-bit SPARC Linux binaries and some handcrafted 64-bit SPARC Linux binaries.
 
 @end itemize
 
 Current QEMU limitations:
 
-@itemize 
-
-@item Tagged add/subtract instructions are not supported, but they are
-probably not used.
+@itemize
 
 @item IPC syscalls are missing.
 
@@ -281,7 +306,7 @@
 instructions to build a function (see @file{op.h:dyngen_code()}).
 
 In essence, the process is similar to [1], but more work is done at
-compile time. 
+compile time.
 
 A key idea to get optimal performances is that constant parameters can
 be passed to the simple operations. For that purpose, dummy ELF
@@ -373,7 +398,7 @@
 
 Correct translated code invalidation is done efficiently by maintaining
 a linked list of every translated block contained in a given page. Other
-linked lists are also maintained to undo direct block chaining. 
+linked lists are also maintained to undo direct block chaining.
 
 Although the overhead of doing @code{mprotect()} calls is important,
 most MSDOS programs can be emulated at reasonnable speed with QEMU and
@@ -393,7 +418,7 @@
 @section Exception support
 
 longjmp() is used when an exception such as division by zero is
-encountered. 
+encountered.
 
 The host SIGSEGV and SIGBUS signal handlers are used to get invalid
 memory accesses. The exact CPU state can be retrieved because all the
@@ -421,7 +446,7 @@
 
 In order to avoid flushing the translated code each time the MMU
 mappings change, QEMU uses a physically indexed translation cache. It
-means that each basic block is indexed with its physical address. 
+means that each basic block is indexed with its physical address.
 
 When MMU mappings change, only the chaining of the basic blocks is
 reset (i.e. a basic block can no longer jump directly to another one).
@@ -500,7 +525,7 @@
 
 @table @asis
 
-@item [1] 
+@item [1]
 @url{http://citeseer.nj.nec.com/piumarta98optimizing.html}, Optimizing
 direct threaded code by selective inlining (1998) by Ian Piumarta, Fabio
 Riccardi.
@@ -527,23 +552,23 @@
 Willows Software.
 
 @item [7]
-@url{http://user-mode-linux.sourceforge.net/}, 
+@url{http://user-mode-linux.sourceforge.net/},
 The User-mode Linux Kernel.
 
 @item [8]
-@url{http://www.plex86.org/}, 
+@url{http://www.plex86.org/},
 The new Plex86 project.
 
 @item [9]
-@url{http://www.vmware.com/}, 
+@url{http://www.vmware.com/},
 The VMWare PC virtualizer.
 
 @item [10]
-@url{http://www.microsoft.com/windowsxp/virtualpc/}, 
+@url{http://www.microsoft.com/windowsxp/virtualpc/},
 The VirtualPC PC virtualizer.
 
 @item [11]
-@url{http://www.twoostwo.org/}, 
+@url{http://www.twoostwo.org/},
 The TwoOStwo PC virtualizer.
 
 @end table
@@ -552,7 +577,7 @@
 @chapter Regression Tests
 
 In the directory @file{tests/}, various interesting testing programs
-are available. There are used for regression testing.
+are available. They are used for regression testing.
 
 @menu
 * test-i386::
diff --git a/readline.c b/readline.c
index 0a02b08..de60cfc 100644
--- a/readline.c
+++ b/readline.c
@@ -1,8 +1,8 @@
 /*
  * QEMU readline utility
- * 
+ *
  * Copyright (c) 2003-2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -156,6 +156,45 @@
     }
 }
 
+static void term_backword(void)
+{
+    int start;
+
+    if (term_cmd_buf_index == 0 || term_cmd_buf_index > term_cmd_buf_size) {
+        return;
+    }
+
+    start = term_cmd_buf_index - 1;
+
+    /* find first word (backwards) */
+    while (start > 0) {
+        if (!isspace(term_cmd_buf[start])) {
+            break;
+        }
+
+        --start;
+    }
+
+    /* find first space (backwards) */
+    while (start > 0) {
+        if (isspace(term_cmd_buf[start])) {
+            ++start;
+            break;
+        }
+
+        --start;
+    }
+
+    /* remove word */
+    if (start < term_cmd_buf_index) {
+        memmove(term_cmd_buf + start,
+                term_cmd_buf + term_cmd_buf_index,
+                term_cmd_buf_size - term_cmd_buf_index);
+        term_cmd_buf_size -= term_cmd_buf_index - start;
+        term_cmd_buf_index = start;
+    }
+}
+
 static void term_bol(void)
 {
     term_cmd_buf_index = 0;
@@ -182,7 +221,7 @@
     }
     term_hist_entry--;
     if (term_hist_entry >= 0) {
-	pstrcpy(term_cmd_buf, sizeof(term_cmd_buf), 
+	pstrcpy(term_cmd_buf, sizeof(term_cmd_buf),
                 term_history[term_hist_entry]);
 	term_cmd_buf_index = term_cmd_buf_size = strlen(term_cmd_buf);
     }
@@ -261,11 +300,11 @@
 
 static void term_completion(void)
 {
-    int len, i, j, max_width, nb_cols;
+    int len, i, j, max_width, nb_cols, max_prefix;
     char *cmdline;
 
     nb_completions = 0;
-    
+
     cmdline = qemu_malloc(term_cmd_buf_index + 1);
     if (!cmdline)
         return;
@@ -288,11 +327,26 @@
     } else {
         term_printf("\n");
         max_width = 0;
+        max_prefix = 0;	
         for(i = 0; i < nb_completions; i++) {
             len = strlen(completions[i]);
+            if (i==0) {
+                max_prefix = len;
+            } else {
+                if (len < max_prefix)
+                    max_prefix = len;
+                for(j=0; j<max_prefix; j++) {
+                    if (completions[i][j] != completions[0][j])
+                        max_prefix = j;
+                }
+            }
             if (len > max_width)
                 max_width = len;
         }
+        if (max_prefix > 0) 
+            for(i = completion_index; i < max_prefix; i++) {
+                term_insert_char(completions[0][i]);
+            }
         max_width += 2;
         if (max_width < 10)
             max_width = 10;
@@ -342,6 +396,10 @@
             /* NOTE: readline_start can be called here */
             term_readline_func(term_readline_opaque, term_cmd_buf);
             break;
+        case 23:
+            /* ^W */
+            term_backword();
+            break;
         case 27:
             term_esc_state = IS_ESC;
             break;
diff --git a/s390-dis.c b/s390-dis.c
new file mode 100644
index 0000000..6e2558b
--- /dev/null
+++ b/s390-dis.c
@@ -0,0 +1,1711 @@
+/* s390-dis.c -- Disassemble S390 instructions
+   Copyright 2000, 2001, 2002, 2003, 2005, 2007 Free Software Foundation, Inc.
+   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
+
+   This file is part of the GNU opcodes library.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   It is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, write to the
+   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include <stdio.h>
+#include "dis-asm.h"
+
+/* s390.h -- Header file for S390 opcode table
+   Copyright 2000, 2001, 2003 Free Software Foundation, Inc.
+   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
+
+   This file is part of BFD, the Binary File Descriptor library.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+   02110-1301, USA.  */
+
+#ifndef S390_H
+#define S390_H
+
+/* List of instruction sets variations. */
+
+enum s390_opcode_mode_val
+  {
+    S390_OPCODE_ESA = 0,
+    S390_OPCODE_ZARCH
+  };
+
+enum s390_opcode_cpu_val
+  {
+    S390_OPCODE_G5 = 0,
+    S390_OPCODE_G6,
+    S390_OPCODE_Z900,
+    S390_OPCODE_Z990,
+    S390_OPCODE_Z9_109,
+    S390_OPCODE_Z9_EC
+  };
+
+/* The opcode table is an array of struct s390_opcode.  */
+
+struct s390_opcode
+  {
+    /* The opcode name.  */
+    const char * name;
+
+    /* The opcode itself.  Those bits which will be filled in with
+       operands are zeroes.  */
+    unsigned char opcode[6];
+
+    /* The opcode mask.  This is used by the disassembler.  This is a
+       mask containing ones indicating those bits which must match the
+       opcode field, and zeroes indicating those bits which need not
+       match (and are presumably filled in by operands).  */
+    unsigned char mask[6];
+
+    /* The opcode length in bytes. */
+    int oplen;
+
+    /* An array of operand codes.  Each code is an index into the
+       operand table.  They appear in the order which the operands must
+       appear in assembly code, and are terminated by a zero.  */
+    unsigned char operands[6];
+
+    /* Bitmask of execution modes this opcode is available for.  */
+    unsigned int modes;
+
+    /* First cpu this opcode is available for.  */
+    enum s390_opcode_cpu_val min_cpu;
+  };
+
+/* The table itself is sorted by major opcode number, and is otherwise
+   in the order in which the disassembler should consider
+   instructions.  */
+extern const struct s390_opcode s390_opcodes[];
+extern const int                s390_num_opcodes;
+
+/* A opcode format table for the .insn pseudo mnemonic.  */
+extern const struct s390_opcode s390_opformats[];
+extern const int                s390_num_opformats;
+
+/* Values defined for the flags field of a struct powerpc_opcode.  */
+
+/* The operands table is an array of struct s390_operand.  */
+
+struct s390_operand
+  {
+    /* The number of bits in the operand.  */
+    int bits;
+
+    /* How far the operand is left shifted in the instruction.  */
+    int shift;
+
+    /* One bit syntax flags.  */
+    unsigned long flags;
+  };
+
+/* Elements in the table are retrieved by indexing with values from
+   the operands field of the powerpc_opcodes table.  */
+
+extern const struct s390_operand s390_operands[];
+
+/* Values defined for the flags field of a struct s390_operand.  */
+
+/* This operand names a register.  The disassembler uses this to print
+   register names with a leading 'r'.  */
+#define S390_OPERAND_GPR 0x1
+
+/* This operand names a floating point register.  The disassembler
+   prints these with a leading 'f'. */
+#define S390_OPERAND_FPR 0x2
+
+/* This operand names an access register.  The disassembler
+   prints these with a leading 'a'.  */
+#define S390_OPERAND_AR 0x4
+
+/* This operand names a control register.  The disassembler
+   prints these with a leading 'c'.  */
+#define S390_OPERAND_CR 0x8
+
+/* This operand is a displacement.  */
+#define S390_OPERAND_DISP 0x10
+
+/* This operand names a base register.  */
+#define S390_OPERAND_BASE 0x20
+
+/* This operand names an index register, it can be skipped.  */
+#define S390_OPERAND_INDEX 0x40
+
+/* This operand is a relative branch displacement.  The disassembler
+   prints these symbolically if possible.  */
+#define S390_OPERAND_PCREL 0x80
+
+/* This operand takes signed values.  */
+#define S390_OPERAND_SIGNED 0x100
+
+/* This operand is a length.  */
+#define S390_OPERAND_LENGTH 0x200
+
+/* This operand is optional. Only a single operand at the end of
+   the instruction may be optional.  */
+#define S390_OPERAND_OPTIONAL 0x400
+
+	#endif /* S390_H */
+
+
+static int init_flag = 0;
+static int opc_index[256];
+static int current_arch_mask = 0;
+
+/* Set up index table for first opcode byte.  */
+
+static void
+init_disasm (struct disassemble_info *info)
+{
+  const struct s390_opcode *opcode;
+  const struct s390_opcode *opcode_end;
+
+  memset (opc_index, 0, sizeof (opc_index));
+  opcode_end = s390_opcodes + s390_num_opcodes;
+  for (opcode = s390_opcodes; opcode < opcode_end; opcode++)
+    {
+      opc_index[(int) opcode->opcode[0]] = opcode - s390_opcodes;
+      while ((opcode < opcode_end) &&
+	     (opcode[1].opcode[0] == opcode->opcode[0]))
+	opcode++;
+    }
+//  switch (info->mach)
+//    {
+//    case bfd_mach_s390_31:
+      current_arch_mask = 1 << S390_OPCODE_ESA;
+//      break;
+//    case bfd_mach_s390_64:
+//      current_arch_mask = 1 << S390_OPCODE_ZARCH;
+//      break;
+//    default:
+//      abort ();
+//    }
+  init_flag = 1;
+}
+
+/* Extracts an operand value from an instruction.  */
+
+static inline unsigned int
+s390_extract_operand (unsigned char *insn, const struct s390_operand *operand)
+{
+  unsigned int val;
+  int bits;
+
+  /* Extract fragments of the operand byte for byte.  */
+  insn += operand->shift / 8;
+  bits = (operand->shift & 7) + operand->bits;
+  val = 0;
+  do
+    {
+      val <<= 8;
+      val |= (unsigned int) *insn++;
+      bits -= 8;
+    }
+  while (bits > 0);
+  val >>= -bits;
+  val &= ((1U << (operand->bits - 1)) << 1) - 1;
+
+  /* Check for special long displacement case.  */
+  if (operand->bits == 20 && operand->shift == 20)
+    val = (val & 0xff) << 12 | (val & 0xfff00) >> 8;
+
+  /* Sign extend value if the operand is signed or pc relative.  */
+  if ((operand->flags & (S390_OPERAND_SIGNED | S390_OPERAND_PCREL))
+      && (val & (1U << (operand->bits - 1))))
+    val |= (-1U << (operand->bits - 1)) << 1;
+
+  /* Double value if the operand is pc relative.  */
+  if (operand->flags & S390_OPERAND_PCREL)
+    val <<= 1;
+
+  /* Length x in an instructions has real length x + 1.  */
+  if (operand->flags & S390_OPERAND_LENGTH)
+    val++;
+  return val;
+}
+
+/* Print a S390 instruction.  */
+
+int
+print_insn_s390 (bfd_vma memaddr, struct disassemble_info *info)
+{
+  bfd_byte buffer[6];
+  const struct s390_opcode *opcode;
+  const struct s390_opcode *opcode_end;
+  unsigned int value;
+  int status, opsize, bufsize;
+  char separator;
+
+  if (init_flag == 0)
+    init_disasm (info);
+
+  /* The output looks better if we put 6 bytes on a line.  */
+  info->bytes_per_line = 6;
+
+  /* Every S390 instruction is max 6 bytes long.  */
+  memset (buffer, 0, 6);
+  status = (*info->read_memory_func) (memaddr, buffer, 6, info);
+  if (status != 0)
+    {
+      for (bufsize = 0; bufsize < 6; bufsize++)
+	if ((*info->read_memory_func) (memaddr, buffer, bufsize + 1, info) != 0)
+	  break;
+      if (bufsize <= 0)
+	{
+	  (*info->memory_error_func) (status, memaddr, info);
+	  return -1;
+	}
+      /* Opsize calculation looks strange but it works
+	 00xxxxxx -> 2 bytes, 01xxxxxx/10xxxxxx -> 4 bytes,
+	 11xxxxxx -> 6 bytes.  */
+      opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
+      status = opsize > bufsize;
+    }
+  else
+    {
+      bufsize = 6;
+      opsize = ((((buffer[0] >> 6) + 1) >> 1) + 1) << 1;
+    }
+
+  if (status == 0)
+    {
+      /* Find the first match in the opcode table.  */
+      opcode_end = s390_opcodes + s390_num_opcodes;
+      for (opcode = s390_opcodes + opc_index[(int) buffer[0]];
+	   (opcode < opcode_end) && (buffer[0] == opcode->opcode[0]);
+	   opcode++)
+	{
+	  const struct s390_operand *operand;
+	  const unsigned char *opindex;
+
+	  /* Check architecture.  */
+	  if (!(opcode->modes & current_arch_mask))
+	    continue;
+	  /* Check signature of the opcode.  */
+	  if ((buffer[1] & opcode->mask[1]) != opcode->opcode[1]
+	      || (buffer[2] & opcode->mask[2]) != opcode->opcode[2]
+	      || (buffer[3] & opcode->mask[3]) != opcode->opcode[3]
+	      || (buffer[4] & opcode->mask[4]) != opcode->opcode[4]
+	      || (buffer[5] & opcode->mask[5]) != opcode->opcode[5])
+	    continue;
+
+	  /* The instruction is valid.  */
+	  if (opcode->operands[0] != 0)
+	    (*info->fprintf_func) (info->stream, "%s\t", opcode->name);
+	  else
+	    (*info->fprintf_func) (info->stream, "%s", opcode->name);
+
+	  /* Extract the operands.  */
+	  separator = 0;
+	  for (opindex = opcode->operands; *opindex != 0; opindex++)
+	    {
+	      unsigned int value;
+
+	      operand = s390_operands + *opindex;
+	      value = s390_extract_operand (buffer, operand);
+
+	      if ((operand->flags & S390_OPERAND_INDEX) && value == 0)
+		continue;
+	      if ((operand->flags & S390_OPERAND_BASE) &&
+		  value == 0 && separator == '(')
+		{
+		  separator = ',';
+		  continue;
+		}
+
+	      if (separator)
+		(*info->fprintf_func) (info->stream, "%c", separator);
+
+	      if (operand->flags & S390_OPERAND_GPR)
+		(*info->fprintf_func) (info->stream, "%%r%i", value);
+	      else if (operand->flags & S390_OPERAND_FPR)
+		(*info->fprintf_func) (info->stream, "%%f%i", value);
+	      else if (operand->flags & S390_OPERAND_AR)
+		(*info->fprintf_func) (info->stream, "%%a%i", value);
+	      else if (operand->flags & S390_OPERAND_CR)
+		(*info->fprintf_func) (info->stream, "%%c%i", value);
+	      else if (operand->flags & S390_OPERAND_PCREL)
+		(*info->print_address_func) (memaddr + (int) value, info);
+	      else if (operand->flags & S390_OPERAND_SIGNED)
+		(*info->fprintf_func) (info->stream, "%i", (int) value);
+	      else
+		(*info->fprintf_func) (info->stream, "%u", value);
+
+	      if (operand->flags & S390_OPERAND_DISP)
+		{
+		  separator = '(';
+		}
+	      else if (operand->flags & S390_OPERAND_BASE)
+		{
+		  (*info->fprintf_func) (info->stream, ")");
+		  separator = ',';
+		}
+	      else
+		separator = ',';
+	    }
+
+	  /* Found instruction, printed it, return its size.  */
+	  return opsize;
+	}
+      /* No matching instruction found, fall through to hex print.  */
+    }
+
+  if (bufsize >= 4)
+    {
+      value = (unsigned int) buffer[0];
+      value = (value << 8) + (unsigned int) buffer[1];
+      value = (value << 8) + (unsigned int) buffer[2];
+      value = (value << 8) + (unsigned int) buffer[3];
+      (*info->fprintf_func) (info->stream, ".long\t0x%08x", value);
+      return 4;
+    }
+  else if (bufsize >= 2)
+    {
+      value = (unsigned int) buffer[0];
+      value = (value << 8) + (unsigned int) buffer[1];
+      (*info->fprintf_func) (info->stream, ".short\t0x%04x", value);
+      return 2;
+    }
+  else
+    {
+      value = (unsigned int) buffer[0];
+      (*info->fprintf_func) (info->stream, ".byte\t0x%02x", value);
+      return 1;
+    }
+}
+/* s390-opc.c -- S390 opcode list
+   Copyright 2000, 2001, 2003, 2007 Free Software Foundation, Inc.
+   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
+
+   This file is part of the GNU opcodes library.
+
+   This library is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   It is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this file; see the file COPYING.  If not, write to the
+   Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
+#include <stdio.h>
+
+/* This file holds the S390 opcode table.  The opcode table
+   includes almost all of the extended instruction mnemonics.  This
+   permits the disassembler to use them, and simplifies the assembler
+   logic, at the cost of increasing the table size.  The table is
+   strictly constant data, so the compiler should be able to put it in
+   the .text section.
+
+   This file also holds the operand table.  All knowledge about
+   inserting operands into instructions and vice-versa is kept in this
+   file.  */
+
+/* The operands table.
+   The fields are bits, shift, insert, extract, flags.  */
+
+const struct s390_operand s390_operands[] =
+{
+#define UNUSED 0
+  { 0, 0, 0 },                    /* Indicates the end of the operand list */
+
+#define R_8    1                  /* GPR starting at position 8 */
+  { 4, 8, S390_OPERAND_GPR },
+#define R_12   2                  /* GPR starting at position 12 */
+  { 4, 12, S390_OPERAND_GPR },
+#define R_16   3                  /* GPR starting at position 16 */
+  { 4, 16, S390_OPERAND_GPR },
+#define R_20   4                  /* GPR starting at position 20 */
+  { 4, 20, S390_OPERAND_GPR },
+#define R_24   5                  /* GPR starting at position 24 */
+  { 4, 24, S390_OPERAND_GPR },
+#define R_28   6                  /* GPR starting at position 28 */
+  { 4, 28, S390_OPERAND_GPR },
+#define R_32   7                  /* GPR starting at position 32 */
+  { 4, 32, S390_OPERAND_GPR },
+
+#define F_8    8                  /* FPR starting at position 8 */
+  { 4, 8, S390_OPERAND_FPR },
+#define F_12   9                  /* FPR starting at position 12 */
+  { 4, 12, S390_OPERAND_FPR },
+#define F_16   10                 /* FPR starting at position 16 */
+  { 4, 16, S390_OPERAND_FPR },
+#define F_20   11                 /* FPR starting at position 16 */
+  { 4, 16, S390_OPERAND_FPR },
+#define F_24   12                 /* FPR starting at position 24 */
+  { 4, 24, S390_OPERAND_FPR },
+#define F_28   13                 /* FPR starting at position 28 */
+  { 4, 28, S390_OPERAND_FPR },
+#define F_32   14                 /* FPR starting at position 32 */
+  { 4, 32, S390_OPERAND_FPR },
+
+#define A_8    15                 /* Access reg. starting at position 8 */
+  { 4, 8, S390_OPERAND_AR },
+#define A_12   16                 /* Access reg. starting at position 12 */
+  { 4, 12, S390_OPERAND_AR },
+#define A_24   17                 /* Access reg. starting at position 24 */
+  { 4, 24, S390_OPERAND_AR },
+#define A_28   18                 /* Access reg. starting at position 28 */
+  { 4, 28, S390_OPERAND_AR },
+
+#define C_8    19                 /* Control reg. starting at position 8 */
+  { 4, 8, S390_OPERAND_CR },
+#define C_12   20                 /* Control reg. starting at position 12 */
+  { 4, 12, S390_OPERAND_CR },
+
+#define B_16   21                 /* Base register starting at position 16 */
+  { 4, 16, S390_OPERAND_BASE|S390_OPERAND_GPR },
+#define B_32   22                 /* Base register starting at position 32 */
+  { 4, 32, S390_OPERAND_BASE|S390_OPERAND_GPR },
+
+#define X_12   23                 /* Index register starting at position 12 */
+  { 4, 12, S390_OPERAND_INDEX|S390_OPERAND_GPR },
+
+#define D_20   24                 /* Displacement starting at position 20 */
+  { 12, 20, S390_OPERAND_DISP },
+#define D_36   25                 /* Displacement starting at position 36 */
+  { 12, 36, S390_OPERAND_DISP },
+#define D20_20 26		  /* 20 bit displacement starting at 20 */
+  { 20, 20, S390_OPERAND_DISP|S390_OPERAND_SIGNED },
+
+#define L4_8   27                 /* 4 bit length starting at position 8 */
+  { 4, 8, S390_OPERAND_LENGTH },
+#define L4_12  28                 /* 4 bit length starting at position 12 */
+  { 4, 12, S390_OPERAND_LENGTH },
+#define L8_8   29                 /* 8 bit length starting at position 8 */
+  { 8, 8, S390_OPERAND_LENGTH },
+
+#define U4_8   30                 /* 4 bit unsigned value starting at 8 */
+  { 4, 8, 0 },
+#define U4_12  31                 /* 4 bit unsigned value starting at 12 */
+  { 4, 12, 0 },
+#define U4_16  32                 /* 4 bit unsigned value starting at 16 */
+  { 4, 16, 0 },
+#define U4_20  33                 /* 4 bit unsigned value starting at 20 */
+  { 4, 20, 0 },
+#define U8_8   34                 /* 8 bit unsigned value starting at 8 */
+  { 8, 8, 0 },
+#define U8_16  35                 /* 8 bit unsigned value starting at 16 */
+  { 8, 16, 0 },
+#define I16_16 36                 /* 16 bit signed value starting at 16 */
+  { 16, 16, S390_OPERAND_SIGNED },
+#define U16_16 37                 /* 16 bit unsigned value starting at 16 */
+  { 16, 16, 0 },
+#define J16_16 38                 /* PC relative jump offset at 16 */
+  { 16, 16, S390_OPERAND_PCREL },
+#define J32_16 39                 /* PC relative long offset at 16 */
+  { 32, 16, S390_OPERAND_PCREL },
+#define I32_16 40		  /* 32 bit signed value starting at 16 */
+  { 32, 16, S390_OPERAND_SIGNED },
+#define U32_16 41		  /* 32 bit unsigned value starting at 16 */
+  { 32, 16, 0 },
+#define M_16   42                 /* 4 bit optional mask starting at 16 */
+  { 4, 16, S390_OPERAND_OPTIONAL },
+#define RO_28  43                 /* optional GPR starting at position 28 */
+  { 4, 28, (S390_OPERAND_GPR | S390_OPERAND_OPTIONAL) }
+
+};
+
+
+/* Macros used to form opcodes.  */
+
+/* 8/16/48 bit opcodes.  */
+#define OP8(x) { x, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define OP16(x) { x >> 8, x & 255, 0x00, 0x00, 0x00, 0x00 }
+#define OP48(x) { x >> 40, (x >> 32) & 255, (x >> 24) & 255, \
+                  (x >> 16) & 255, (x >> 8) & 255, x & 255}
+
+/* The new format of the INSTR_x_y and MASK_x_y defines is based
+   on the following rules:
+   1) the middle part of the definition (x in INSTR_x_y) is the official
+      names of the instruction format that you can find in the principals
+      of operation.
+   2) the last part of the definition (y in INSTR_x_y) gives you an idea
+      which operands the binary represenation of the instruction has.
+      The meanings of the letters in y are:
+      a - access register
+      c - control register
+      d - displacement, 12 bit
+      f - floating pointer register
+      i - signed integer, 4, 8, 16 or 32 bit
+      l - length, 4 or 8 bit
+      p - pc relative
+      r - general purpose register
+      u - unsigned integer, 4, 8, 16 or 32 bit
+      m - mode field, 4 bit
+      0 - operand skipped.
+      The order of the letters reflects the layout of the format in
+      storage and not the order of the paramaters of the instructions.
+      The use of the letters is not a 100% match with the PoP but it is
+      quite close.
+
+      For example the instruction "mvo" is defined in the PoP as follows:
+
+      MVO  D1(L1,B1),D2(L2,B2)   [SS]
+
+      --------------------------------------
+      | 'F1' | L1 | L2 | B1 | D1 | B2 | D2 |
+      --------------------------------------
+       0      8    12   16   20   32   36
+
+      The instruction format is: INSTR_SS_LLRDRD / MASK_SS_LLRDRD.  */
+
+#define INSTR_E          2, { 0,0,0,0,0,0 }                    /* e.g. pr    */
+#define INSTR_RIE_RRP    6, { R_8,R_12,J16_16,0,0,0 }          /* e.g. brxhg */
+#define INSTR_RIL_0P     6, { J32_16,0,0,0,0 }                 /* e.g. jg    */
+#define INSTR_RIL_RP     6, { R_8,J32_16,0,0,0,0 }             /* e.g. brasl */
+#define INSTR_RIL_UP     6, { U4_8,J32_16,0,0,0,0 }            /* e.g. brcl  */
+#define INSTR_RIL_RI     6, { R_8,I32_16,0,0,0,0 }             /* e.g. afi   */
+#define INSTR_RIL_RU     6, { R_8,U32_16,0,0,0,0 }             /* e.g. alfi  */
+#define INSTR_RI_0P      4, { J16_16,0,0,0,0,0 }               /* e.g. j     */
+#define INSTR_RI_RI      4, { R_8,I16_16,0,0,0,0 }             /* e.g. ahi   */
+#define INSTR_RI_RP      4, { R_8,J16_16,0,0,0,0 }             /* e.g. brct  */
+#define INSTR_RI_RU      4, { R_8,U16_16,0,0,0,0 }             /* e.g. tml   */
+#define INSTR_RI_UP      4, { U4_8,J16_16,0,0,0,0 }            /* e.g. brc   */
+#define INSTR_RRE_00     4, { 0,0,0,0,0,0 }                    /* e.g. palb  */
+#define INSTR_RRE_0R     4, { R_28,0,0,0,0,0 }                 /* e.g. tb    */
+#define INSTR_RRE_AA     4, { A_24,A_28,0,0,0,0 }              /* e.g. cpya  */
+#define INSTR_RRE_AR     4, { A_24,R_28,0,0,0,0 }              /* e.g. sar   */
+#define INSTR_RRE_F0     4, { F_24,0,0,0,0,0 }                 /* e.g. sqer  */
+#define INSTR_RRE_FF     4, { F_24,F_28,0,0,0,0 }              /* e.g. debr  */
+#define INSTR_RRE_R0     4, { R_24,0,0,0,0,0 }                 /* e.g. ipm   */
+#define INSTR_RRE_RA     4, { R_24,A_28,0,0,0,0 }              /* e.g. ear   */
+#define INSTR_RRE_RF     4, { R_24,F_28,0,0,0,0 }              /* e.g. cefbr */
+#define INSTR_RRE_RR     4, { R_24,R_28,0,0,0,0 }              /* e.g. lura  */
+#define INSTR_RRE_FR     4, { F_24,R_28,0,0,0,0 }              /* e.g. ldgr  */
+/* Actually efpc and sfpc do not take an optional operand.
+   This is just a workaround for existing code e.g. glibc.  */
+#define INSTR_RRE_RR_OPT 4, { R_24,RO_28,0,0,0,0 }             /* efpc, sfpc */
+#define INSTR_RRF_F0FF   4, { F_16,F_24,F_28,0,0,0 }           /* e.g. madbr */
+#define INSTR_RRF_F0FF2  4, { F_24,F_16,F_28,0,0,0 }           /* e.g. cpsdr */
+#define INSTR_RRF_F0FR   4, { F_24,F_16,R_28,0,0,0 }           /* e.g. iedtr */
+#define INSTR_RRF_FUFF   4, { F_24,F_16,F_28,U4_20,0,0 }       /* e.g. didbr */
+#define INSTR_RRF_RURR   4, { R_24,R_28,R_16,U4_20,0,0 }       /* e.g. .insn */
+#define INSTR_RRF_R0RR   4, { R_24,R_28,R_16,0,0,0 }           /* e.g. idte  */
+#define INSTR_RRF_U0FF   4, { F_24,U4_16,F_28,0,0,0 }          /* e.g. fixr  */
+#define INSTR_RRF_U0RF   4, { R_24,U4_16,F_28,0,0,0 }          /* e.g. cfebr */
+#define INSTR_RRF_UUFF   4, { F_24,U4_16,F_28,U4_20,0,0 }      /* e.g. fidtr */
+#define INSTR_RRF_0UFF   4, { F_24,F_28,U4_20,0,0,0 }          /* e.g. ldetr */
+#define INSTR_RRF_FFFU   4, { F_24,F_16,F_28,U4_20,0,0 }       /* e.g. qadtr */
+#define INSTR_RRF_M0RR   4, { R_24,R_28,M_16,0,0,0 }           /* e.g. sske  */
+#define INSTR_RR_0R      2, { R_12, 0,0,0,0,0 }                /* e.g. br    */
+#define INSTR_RR_FF      2, { F_8,F_12,0,0,0,0 }               /* e.g. adr   */
+#define INSTR_RR_R0      2, { R_8, 0,0,0,0,0 }                 /* e.g. spm   */
+#define INSTR_RR_RR      2, { R_8,R_12,0,0,0,0 }               /* e.g. lr    */
+#define INSTR_RR_U0      2, { U8_8, 0,0,0,0,0 }                /* e.g. svc   */
+#define INSTR_RR_UR      2, { U4_8,R_12,0,0,0,0 }              /* e.g. bcr   */
+#define INSTR_RRR_F0FF   4, { F_24,F_28,F_16,0,0,0 }           /* e.g. ddtr  */
+#define INSTR_RSE_RRRD   6, { R_8,R_12,D_20,B_16,0,0 }         /* e.g. lmh   */
+#define INSTR_RSE_CCRD   6, { C_8,C_12,D_20,B_16,0,0 }         /* e.g. lmh   */
+#define INSTR_RSE_RURD   6, { R_8,U4_12,D_20,B_16,0,0 }        /* e.g. icmh  */
+#define INSTR_RSL_R0RD   6, { R_8,D_20,B_16,0,0,0 }            /* e.g. tp    */
+#define INSTR_RSI_RRP    4, { R_8,R_12,J16_16,0,0,0 }          /* e.g. brxh  */
+#define INSTR_RSY_RRRD   6, { R_8,R_12,D20_20,B_16,0,0 }       /* e.g. stmy  */
+#define INSTR_RSY_RURD   6, { R_8,U4_12,D20_20,B_16,0,0 }      /* e.g. icmh  */
+#define INSTR_RSY_AARD   6, { A_8,A_12,D20_20,B_16,0,0 }       /* e.g. lamy  */
+#define INSTR_RSY_CCRD   6, { C_8,C_12,D20_20,B_16,0,0 }       /* e.g. lamy  */
+#define INSTR_RS_AARD    4, { A_8,A_12,D_20,B_16,0,0 }         /* e.g. lam   */
+#define INSTR_RS_CCRD    4, { C_8,C_12,D_20,B_16,0,0 }         /* e.g. lctl  */
+#define INSTR_RS_R0RD    4, { R_8,D_20,B_16,0,0,0 }            /* e.g. sll   */
+#define INSTR_RS_RRRD    4, { R_8,R_12,D_20,B_16,0,0 }         /* e.g. cs    */
+#define INSTR_RS_RURD    4, { R_8,U4_12,D_20,B_16,0,0 }        /* e.g. icm   */
+#define INSTR_RXE_FRRD   6, { F_8,D_20,X_12,B_16,0,0 }         /* e.g. axbr  */
+#define INSTR_RXE_RRRD   6, { R_8,D_20,X_12,B_16,0,0 }         /* e.g. lg    */
+#define INSTR_RXF_FRRDF  6, { F_32,F_8,D_20,X_12,B_16,0 }      /* e.g. madb  */
+#define INSTR_RXF_RRRDR  6, { R_32,R_8,D_20,X_12,B_16,0 }      /* e.g. .insn */
+#define INSTR_RXY_RRRD   6, { R_8,D20_20,X_12,B_16,0,0 }       /* e.g. ly    */
+#define INSTR_RXY_FRRD   6, { F_8,D20_20,X_12,B_16,0,0 }       /* e.g. ley   */
+#define INSTR_RX_0RRD    4, { D_20,X_12,B_16,0,0,0 }           /* e.g. be    */
+#define INSTR_RX_FRRD    4, { F_8,D_20,X_12,B_16,0,0 }         /* e.g. ae    */
+#define INSTR_RX_RRRD    4, { R_8,D_20,X_12,B_16,0,0 }         /* e.g. l     */
+#define INSTR_RX_URRD    4, { U4_8,D_20,X_12,B_16,0,0 }        /* e.g. bc    */
+#define INSTR_SI_URD     4, { D_20,B_16,U8_8,0,0,0 }           /* e.g. cli   */
+#define INSTR_SIY_URD    6, { D20_20,B_16,U8_8,0,0,0 }         /* e.g. tmy   */
+#define INSTR_SSE_RDRD   6, { D_20,B_16,D_36,B_32,0,0 }        /* e.g. mvsdk */
+#define INSTR_SS_L0RDRD  6, { D_20,L8_8,B_16,D_36,B_32,0     } /* e.g. mvc   */
+#define INSTR_SS_L2RDRD  6, { D_20,B_16,D_36,L8_8,B_32,0     } /* e.g. pka   */
+#define INSTR_SS_LIRDRD  6, { D_20,L4_8,B_16,D_36,B_32,U4_12 } /* e.g. srp   */
+#define INSTR_SS_LLRDRD  6, { D_20,L4_8,B_16,D_36,L4_12,B_32 } /* e.g. pack  */
+#define INSTR_SS_RRRDRD  6, { D_20,R_8,B_16,D_36,B_32,R_12 }   /* e.g. mvck  */
+#define INSTR_SS_RRRDRD2 6, { R_8,D_20,B_16,R_12,D_36,B_32 }   /* e.g. plo   */
+#define INSTR_SS_RRRDRD3 6, { R_8,R_12,D_20,B_16,D_36,B_32 }   /* e.g. lmd   */
+#define INSTR_S_00       4, { 0,0,0,0,0,0 }                    /* e.g. hsch  */
+#define INSTR_S_RD       4, { D_20,B_16,0,0,0,0 }              /* e.g. lpsw  */
+#define INSTR_SSF_RRDRD  6, { D_20,B_16,D_36,B_32,R_8,0 }      /* e.g. mvcos */
+
+#define MASK_E           { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIE_RRP     { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RIL_0P      { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIL_RP      { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIL_UP      { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIL_RI      { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RIL_RU      { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_0P       { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_RI       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_RP       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_RU       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RI_UP       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRE_00      { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
+#define MASK_RRE_0R      { 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00 }
+#define MASK_RRE_AA      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_AR      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_F0      { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 }
+#define MASK_RRE_FF      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_R0      { 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00 }
+#define MASK_RRE_RA      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_RF      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_RR      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_FR      { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRE_RR_OPT  { 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 }
+#define MASK_RRF_F0FF    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_F0FF2   { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_F0FR    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_FUFF    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_RURR    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_R0RR    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_U0FF    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_U0RF    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RRF_UUFF    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_0UFF    { 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00 }
+#define MASK_RRF_FFFU    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRF_M0RR    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RR_0R       { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_FF       { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_R0       { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_RR       { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_U0       { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RR_UR       { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RRR_F0FF    { 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00 }
+#define MASK_RSE_RRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSE_CCRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSE_RURD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSL_R0RD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSI_RRP     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_AARD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_CCRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_R0RD     { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_RRRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RS_RURD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RSY_RRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSY_RURD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSY_AARD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RSY_CCRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXE_FRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXE_RRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXF_FRRDF   { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXF_RRRDR   { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXY_RRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RXY_FRRD    { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_RX_0RRD     { 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RX_FRRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RX_RRRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_RX_URRD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SI_URD      { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SIY_URD     { 0xff, 0x00, 0x00, 0x00, 0x00, 0xff }
+#define MASK_SSE_RDRD    { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_L0RDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_L2RDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_LIRDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_LLRDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_RRRDRD   { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_RRRDRD2  { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SS_RRRDRD3  { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_S_00        { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00 }
+#define MASK_S_RD        { 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }
+#define MASK_SSF_RRDRD   { 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00 }
+
+/* The opcode formats table (blueprints for .insn pseudo mnemonic).  */
+
+const struct s390_opcode s390_opformats[] =
+  {
+  { "e",	OP8(0x00LL),	MASK_E,		INSTR_E,	3, 0 },
+  { "ri",	OP8(0x00LL),	MASK_RI_RI,	INSTR_RI_RI,	3, 0 },
+  { "rie",	OP8(0x00LL),	MASK_RIE_RRP,	INSTR_RIE_RRP,	3, 0 },
+  { "ril",	OP8(0x00LL),	MASK_RIL_RP,	INSTR_RIL_RP,	3, 0 },
+  { "rilu",	OP8(0x00LL),	MASK_RIL_RU,	INSTR_RIL_RU,	3, 0 },
+  { "rr",	OP8(0x00LL),	MASK_RR_RR,	INSTR_RR_RR,	3, 0 },
+  { "rre",	OP8(0x00LL),	MASK_RRE_RR,	INSTR_RRE_RR,	3, 0 },
+  { "rrf",	OP8(0x00LL),	MASK_RRF_RURR,	INSTR_RRF_RURR,	3, 0 },
+  { "rs",	OP8(0x00LL),	MASK_RS_RRRD,	INSTR_RS_RRRD,	3, 0 },
+  { "rse",	OP8(0x00LL),	MASK_RSE_RRRD,	INSTR_RSE_RRRD,	3, 0 },
+  { "rsi",	OP8(0x00LL),	MASK_RSI_RRP,	INSTR_RSI_RRP,	3, 0 },
+  { "rsy",	OP8(0x00LL),	MASK_RSY_RRRD,	INSTR_RSY_RRRD,	3, 3 },
+  { "rx",	OP8(0x00LL),	MASK_RX_RRRD,	INSTR_RX_RRRD,	3, 0 },
+  { "rxe",	OP8(0x00LL),	MASK_RXE_RRRD,	INSTR_RXE_RRRD,	3, 0 },
+  { "rxf",	OP8(0x00LL),	MASK_RXF_RRRDR,	INSTR_RXF_RRRDR,3, 0 },
+  { "rxy",	OP8(0x00LL),	MASK_RXY_RRRD,	INSTR_RXY_RRRD,	3, 3 },
+  { "s",	OP8(0x00LL),	MASK_S_RD,	INSTR_S_RD,	3, 0 },
+  { "si",	OP8(0x00LL),	MASK_SI_URD,	INSTR_SI_URD,	3, 0 },
+  { "siy",	OP8(0x00LL),	MASK_SIY_URD,	INSTR_SIY_URD,	3, 3 },
+  { "ss",	OP8(0x00LL),	MASK_SS_RRRDRD,	INSTR_SS_RRRDRD,3, 0 },
+  { "sse",	OP8(0x00LL),	MASK_SSE_RDRD,	INSTR_SSE_RDRD,	3, 0 },
+  { "ssf",	OP8(0x00LL),	MASK_SSF_RRDRD,	INSTR_SSF_RRDRD,3, 0 },
+};
+
+const int s390_num_opformats =
+  sizeof (s390_opformats) / sizeof (s390_opformats[0]);
+
+/* The opcode table. This file was generated by s390-mkopc.
+
+   The format of the opcode table is:
+
+   NAME	     OPCODE	MASK	OPERANDS
+
+   Name is the name of the instruction.
+   OPCODE is the instruction opcode.
+   MASK is the opcode mask; this is used to tell the disassembler
+     which bits in the actual opcode must match OPCODE.
+   OPERANDS is the list of operands.
+
+   The disassembler reads the table in order and prints the first
+   instruction which matches.  */
+
+const struct s390_opcode s390_opcodes[] =
+  {
+  { "dp", OP8(0xfdLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "mp", OP8(0xfcLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "sp", OP8(0xfbLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "ap", OP8(0xfaLL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "cp", OP8(0xf9LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "zap", OP8(0xf8LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "unpk", OP8(0xf3LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "pack", OP8(0xf2LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "mvo", OP8(0xf1LL), MASK_SS_LLRDRD, INSTR_SS_LLRDRD, 3, 0},
+  { "srp", OP8(0xf0LL), MASK_SS_LIRDRD, INSTR_SS_LIRDRD, 3, 0},
+  { "lmd", OP8(0xefLL), MASK_SS_RRRDRD3, INSTR_SS_RRRDRD3, 2, 2},
+  { "plo", OP8(0xeeLL), MASK_SS_RRRDRD2, INSTR_SS_RRRDRD2, 3, 0},
+  { "stdy", OP48(0xed0000000067LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3},
+  { "stey", OP48(0xed0000000066LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3},
+  { "ldy", OP48(0xed0000000065LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3},
+  { "ley", OP48(0xed0000000064LL), MASK_RXY_FRRD, INSTR_RXY_FRRD, 2, 3},
+  { "tgxt", OP48(0xed0000000059LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tcxt", OP48(0xed0000000058LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tgdt", OP48(0xed0000000055LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tcdt", OP48(0xed0000000054LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tget", OP48(0xed0000000051LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "tcet", OP48(0xed0000000050LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 2, 5},
+  { "srxt", OP48(0xed0000000049LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5},
+  { "slxt", OP48(0xed0000000048LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5},
+  { "srdt", OP48(0xed0000000041LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5},
+  { "sldt", OP48(0xed0000000040LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 5},
+  { "msd", OP48(0xed000000003fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3},
+  { "mad", OP48(0xed000000003eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3},
+  { "myh", OP48(0xed000000003dLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "mayh", OP48(0xed000000003cLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "my", OP48(0xed000000003bLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "may", OP48(0xed000000003aLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "myl", OP48(0xed0000000039LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "mayl", OP48(0xed0000000038LL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 2, 4},
+  { "mee", OP48(0xed0000000037LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "sqe", OP48(0xed0000000034LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mse", OP48(0xed000000002fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3},
+  { "mae", OP48(0xed000000002eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 3},
+  { "lxe", OP48(0xed0000000026LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "lxd", OP48(0xed0000000025LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "lde", OP48(0xed0000000024LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "msdb", OP48(0xed000000001fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0},
+  { "madb", OP48(0xed000000001eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0},
+  { "ddb", OP48(0xed000000001dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mdb", OP48(0xed000000001cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "sdb", OP48(0xed000000001bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "adb", OP48(0xed000000001aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "cdb", OP48(0xed0000000019LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "kdb", OP48(0xed0000000018LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "meeb", OP48(0xed0000000017LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "sqdb", OP48(0xed0000000015LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "sqeb", OP48(0xed0000000014LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "tcxb", OP48(0xed0000000012LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "tcdb", OP48(0xed0000000011LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "tceb", OP48(0xed0000000010LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mseb", OP48(0xed000000000fLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0},
+  { "maeb", OP48(0xed000000000eLL), MASK_RXF_FRRDF, INSTR_RXF_FRRDF, 3, 0},
+  { "deb", OP48(0xed000000000dLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mdeb", OP48(0xed000000000cLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "seb", OP48(0xed000000000bLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "aeb", OP48(0xed000000000aLL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "ceb", OP48(0xed0000000009LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "keb", OP48(0xed0000000008LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "mxdb", OP48(0xed0000000007LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "lxeb", OP48(0xed0000000006LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "lxdb", OP48(0xed0000000005LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "ldeb", OP48(0xed0000000004LL), MASK_RXE_FRRD, INSTR_RXE_FRRD, 3, 0},
+  { "brxlg", OP48(0xec0000000045LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2},
+  { "brxhg", OP48(0xec0000000044LL), MASK_RIE_RRP, INSTR_RIE_RRP, 2, 2},
+  { "tp", OP48(0xeb00000000c0LL), MASK_RSL_R0RD, INSTR_RSL_R0RD, 3, 0},
+  { "stamy", OP48(0xeb000000009bLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3},
+  { "lamy", OP48(0xeb000000009aLL), MASK_RSY_AARD, INSTR_RSY_AARD, 2, 3},
+  { "lmy", OP48(0xeb0000000098LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "lmh", OP48(0xeb0000000096LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "lmh", OP48(0xeb0000000096LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "stmy", OP48(0xeb0000000090LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "clclu", OP48(0xeb000000008fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "mvclu", OP48(0xeb000000008eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3},
+  { "mvclu", OP48(0xeb000000008eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 0},
+  { "icmy", OP48(0xeb0000000081LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "icmh", OP48(0xeb0000000080LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "icmh", OP48(0xeb0000000080LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2},
+  { "xiy", OP48(0xeb0000000057LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "oiy", OP48(0xeb0000000056LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "cliy", OP48(0xeb0000000055LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "niy", OP48(0xeb0000000054LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "mviy", OP48(0xeb0000000052LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "tmy", OP48(0xeb0000000051LL), MASK_SIY_URD, INSTR_SIY_URD, 2, 3},
+  { "bxleg", OP48(0xeb0000000045LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "bxleg", OP48(0xeb0000000045LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "bxhg", OP48(0xeb0000000044LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "bxhg", OP48(0xeb0000000044LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "cdsg", OP48(0xeb000000003eLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "cdsg", OP48(0xeb000000003eLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "cdsy", OP48(0xeb0000000031LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "csg", OP48(0xeb0000000030LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "csg", OP48(0xeb0000000030LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "lctlg", OP48(0xeb000000002fLL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3},
+  { "lctlg", OP48(0xeb000000002fLL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2},
+  { "stcmy", OP48(0xeb000000002dLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "stcmh", OP48(0xeb000000002cLL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "stcmh", OP48(0xeb000000002cLL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2},
+  { "stmh", OP48(0xeb0000000026LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "stmh", OP48(0xeb0000000026LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "stctg", OP48(0xeb0000000025LL), MASK_RSY_CCRD, INSTR_RSY_CCRD, 2, 3},
+  { "stctg", OP48(0xeb0000000025LL), MASK_RSE_CCRD, INSTR_RSE_CCRD, 2, 2},
+  { "stmg", OP48(0xeb0000000024LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "stmg", OP48(0xeb0000000024LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "clmy", OP48(0xeb0000000021LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "clmh", OP48(0xeb0000000020LL), MASK_RSY_RURD, INSTR_RSY_RURD, 2, 3},
+  { "clmh", OP48(0xeb0000000020LL), MASK_RSE_RURD, INSTR_RSE_RURD, 2, 2},
+  { "rll", OP48(0xeb000000001dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 3, 3},
+  { "rll", OP48(0xeb000000001dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 3, 2},
+  { "rllg", OP48(0xeb000000001cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "rllg", OP48(0xeb000000001cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "csy", OP48(0xeb0000000014LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "tracg", OP48(0xeb000000000fLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "tracg", OP48(0xeb000000000fLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "sllg", OP48(0xeb000000000dLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "sllg", OP48(0xeb000000000dLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "srlg", OP48(0xeb000000000cLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "srlg", OP48(0xeb000000000cLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "slag", OP48(0xeb000000000bLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "slag", OP48(0xeb000000000bLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "srag", OP48(0xeb000000000aLL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "srag", OP48(0xeb000000000aLL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "lmg", OP48(0xeb0000000004LL), MASK_RSY_RRRD, INSTR_RSY_RRRD, 2, 3},
+  { "lmg", OP48(0xeb0000000004LL), MASK_RSE_RRRD, INSTR_RSE_RRRD, 2, 2},
+  { "unpka", OP8(0xeaLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "pka", OP8(0xe9LL), MASK_SS_L2RDRD, INSTR_SS_L2RDRD, 3, 0},
+  { "mvcin", OP8(0xe8LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvcdk", OP16(0xe50fLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
+  { "mvcsk", OP16(0xe50eLL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
+  { "tprot", OP16(0xe501LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
+  { "strag", OP48(0xe50000000002LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 2, 2},
+  { "lasp", OP16(0xe500LL), MASK_SSE_RDRD, INSTR_SSE_RDRD, 3, 0},
+  { "slb", OP48(0xe30000000099LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "slb", OP48(0xe30000000099LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "alc", OP48(0xe30000000098LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "alc", OP48(0xe30000000098LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "dl", OP48(0xe30000000097LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "dl", OP48(0xe30000000097LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "ml", OP48(0xe30000000096LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "ml", OP48(0xe30000000096LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "llh", OP48(0xe30000000095LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
+  { "llc", OP48(0xe30000000094LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
+  { "llgh", OP48(0xe30000000091LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "llgh", OP48(0xe30000000091LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "llgc", OP48(0xe30000000090LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "llgc", OP48(0xe30000000090LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lpq", OP48(0xe3000000008fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lpq", OP48(0xe3000000008fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "stpq", OP48(0xe3000000008eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "stpq", OP48(0xe3000000008eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "slbg", OP48(0xe30000000089LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "slbg", OP48(0xe30000000089LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "alcg", OP48(0xe30000000088LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "alcg", OP48(0xe30000000088LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "dlg", OP48(0xe30000000087LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "dlg", OP48(0xe30000000087LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "mlg", OP48(0xe30000000086LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "mlg", OP48(0xe30000000086LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "xg", OP48(0xe30000000082LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "xg", OP48(0xe30000000082LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "og", OP48(0xe30000000081LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "og", OP48(0xe30000000081LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "ng", OP48(0xe30000000080LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ng", OP48(0xe30000000080LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "shy", OP48(0xe3000000007bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ahy", OP48(0xe3000000007aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "chy", OP48(0xe30000000079LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lhy", OP48(0xe30000000078LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lgb", OP48(0xe30000000077LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lb", OP48(0xe30000000076LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "icy", OP48(0xe30000000073LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "stcy", OP48(0xe30000000072LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lay", OP48(0xe30000000071LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sthy", OP48(0xe30000000070LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sly", OP48(0xe3000000005fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "aly", OP48(0xe3000000005eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sy", OP48(0xe3000000005bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ay", OP48(0xe3000000005aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cy", OP48(0xe30000000059LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ly", OP48(0xe30000000058LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "xy", OP48(0xe30000000057LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "oy", OP48(0xe30000000056LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cly", OP48(0xe30000000055LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ny", OP48(0xe30000000054LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "msy", OP48(0xe30000000051LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sty", OP48(0xe30000000050LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "bctg", OP48(0xe30000000046LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "bctg", OP48(0xe30000000046LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "strvh", OP48(0xe3000000003fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "strvh", OP48(0xe3000000003fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "strv", OP48(0xe3000000003eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "strv", OP48(0xe3000000003eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "clgf", OP48(0xe30000000031LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "clgf", OP48(0xe30000000031LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cgf", OP48(0xe30000000030LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cgf", OP48(0xe30000000030LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "strvg", OP48(0xe3000000002fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "strvg", OP48(0xe3000000002fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cvdg", OP48(0xe3000000002eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cvdg", OP48(0xe3000000002eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cvdy", OP48(0xe30000000026LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "stg", OP48(0xe30000000024LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "stg", OP48(0xe30000000024LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "clg", OP48(0xe30000000021LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "clg", OP48(0xe30000000021LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cg", OP48(0xe30000000020LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cg", OP48(0xe30000000020LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lrvh", OP48(0xe3000000001fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "lrvh", OP48(0xe3000000001fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "lrv", OP48(0xe3000000001eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 3, 3},
+  { "lrv", OP48(0xe3000000001eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 3, 2},
+  { "dsgf", OP48(0xe3000000001dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "dsgf", OP48(0xe3000000001dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "msgf", OP48(0xe3000000001cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "msgf", OP48(0xe3000000001cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "slgf", OP48(0xe3000000001bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "slgf", OP48(0xe3000000001bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "algf", OP48(0xe3000000001aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "algf", OP48(0xe3000000001aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "sgf", OP48(0xe30000000019LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sgf", OP48(0xe30000000019LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "agf", OP48(0xe30000000018LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "agf", OP48(0xe30000000018LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "llgt", OP48(0xe30000000017LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "llgt", OP48(0xe30000000017LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "llgf", OP48(0xe30000000016LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "llgf", OP48(0xe30000000016LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lgh", OP48(0xe30000000015LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lgh", OP48(0xe30000000015LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lgf", OP48(0xe30000000014LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lgf", OP48(0xe30000000014LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lray", OP48(0xe30000000013LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lt", OP48(0xe30000000012LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
+  { "lrvg", OP48(0xe3000000000fLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lrvg", OP48(0xe3000000000fLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cvbg", OP48(0xe3000000000eLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "cvbg", OP48(0xe3000000000eLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "dsg", OP48(0xe3000000000dLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "dsg", OP48(0xe3000000000dLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "msg", OP48(0xe3000000000cLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "msg", OP48(0xe3000000000cLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "slg", OP48(0xe3000000000bLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "slg", OP48(0xe3000000000bLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "alg", OP48(0xe3000000000aLL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "alg", OP48(0xe3000000000aLL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "sg", OP48(0xe30000000009LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "sg", OP48(0xe30000000009LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "ag", OP48(0xe30000000008LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "ag", OP48(0xe30000000008LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "cvby", OP48(0xe30000000006LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lg", OP48(0xe30000000004LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lg", OP48(0xe30000000004LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "lrag", OP48(0xe30000000003LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 3},
+  { "lrag", OP48(0xe30000000003LL), MASK_RXE_RRRD, INSTR_RXE_RRRD, 2, 2},
+  { "ltg", OP48(0xe30000000002LL), MASK_RXY_RRRD, INSTR_RXY_RRRD, 2, 4},
+  { "unpku", OP8(0xe2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "pku", OP8(0xe1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "edmk", OP8(0xdfLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "ed", OP8(0xdeLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "trt", OP8(0xddLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "tr", OP8(0xdcLL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvcs", OP8(0xdbLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0},
+  { "mvcp", OP8(0xdaLL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0},
+  { "mvck", OP8(0xd9LL), MASK_SS_RRRDRD, INSTR_SS_RRRDRD, 3, 0},
+  { "xc", OP8(0xd7LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "oc", OP8(0xd6LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "clc", OP8(0xd5LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "nc", OP8(0xd4LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvz", OP8(0xd3LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvc", OP8(0xd2LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "mvn", OP8(0xd1LL), MASK_SS_L0RDRD, INSTR_SS_L0RDRD, 3, 0},
+  { "csst", OP16(0xc802LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5},
+  { "ectg", OP16(0xc801LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 5},
+  { "mvcos", OP16(0xc800LL), MASK_SSF_RRDRD, INSTR_SSF_RRDRD, 2, 4},
+  { "clfi", OP16(0xc20fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "clgfi", OP16(0xc20eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "cfi", OP16(0xc20dLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "cgfi", OP16(0xc20cLL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "alfi", OP16(0xc20bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "algfi", OP16(0xc20aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "afi", OP16(0xc209LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "agfi", OP16(0xc208LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "slfi", OP16(0xc205LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "slgfi", OP16(0xc204LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "jg", OP16(0xc0f4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgno", OP16(0xc0e4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnh", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnp", OP16(0xc0d4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgle", OP16(0xc0c4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnl", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnm", OP16(0xc0b4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jghe", OP16(0xc0a4LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnlh", OP16(0xc094LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jge", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgz", OP16(0xc084LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgne", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnz", OP16(0xc074LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jglh", OP16(0xc064LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnhe", OP16(0xc054LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgl", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgm", OP16(0xc044LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgnle", OP16(0xc034LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgh", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgp", OP16(0xc024LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "jgo", OP16(0xc014LL), MASK_RIL_0P, INSTR_RIL_0P, 3, 2},
+  { "llilf", OP16(0xc00fLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "llihf", OP16(0xc00eLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "oilf", OP16(0xc00dLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "oihf", OP16(0xc00cLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "nilf", OP16(0xc00bLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "nihf", OP16(0xc00aLL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "iilf", OP16(0xc009LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "iihf", OP16(0xc008LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "xilf", OP16(0xc007LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "xihf", OP16(0xc006LL), MASK_RIL_RU, INSTR_RIL_RU, 2, 4},
+  { "brasl", OP16(0xc005LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2},
+  { "brcl", OP16(0xc004LL), MASK_RIL_UP, INSTR_RIL_UP, 3, 2},
+  { "lgfi", OP16(0xc001LL), MASK_RIL_RI, INSTR_RIL_RI, 2, 4},
+  { "larl", OP16(0xc000LL), MASK_RIL_RP, INSTR_RIL_RP, 3, 2},
+  { "icm", OP8(0xbfLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0},
+  { "stcm", OP8(0xbeLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0},
+  { "clm", OP8(0xbdLL), MASK_RS_RURD, INSTR_RS_RURD, 3, 0},
+  { "cds", OP8(0xbbLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "cs", OP8(0xbaLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "cu42", OP16(0xb9b3LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cu41", OP16(0xb9b2LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cu24", OP16(0xb9b1LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cu14", OP16(0xb9b0LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "lptea", OP16(0xb9aaLL), MASK_RRF_RURR, INSTR_RRF_RURR, 2, 4},
+  { "esea", OP16(0xb99dLL), MASK_RRE_R0, INSTR_RRE_R0, 2, 2},
+  { "slbr", OP16(0xb999LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "alcr", OP16(0xb998LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "dlr", OP16(0xb997LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "mlr", OP16(0xb996LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "llhr", OP16(0xb995LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "llcr", OP16(0xb994LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "troo", OP16(0xb993LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4},
+  { "troo", OP16(0xb993LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "trot", OP16(0xb992LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4},
+  { "trot", OP16(0xb992LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "trto", OP16(0xb991LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4},
+  { "trto", OP16(0xb991LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "trtt", OP16(0xb990LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 3, 4},
+  { "trtt", OP16(0xb990LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "idte", OP16(0xb98eLL), MASK_RRF_R0RR, INSTR_RRF_R0RR, 2, 3},
+  { "epsw", OP16(0xb98dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "cspg", OP16(0xb98aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 3},
+  { "slbgr", OP16(0xb989LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "alcgr", OP16(0xb988LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "dlgr", OP16(0xb987LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "mlgr", OP16(0xb986LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "llghr", OP16(0xb985LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "llgcr", OP16(0xb984LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "flogr", OP16(0xb983LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "xgr", OP16(0xb982LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ogr", OP16(0xb981LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ngr", OP16(0xb980LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "bctgr", OP16(0xb946LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "klmd", OP16(0xb93fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "kimd", OP16(0xb93eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "clgfr", OP16(0xb931LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cgfr", OP16(0xb930LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "kmc", OP16(0xb92fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "km", OP16(0xb92eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "lhr", OP16(0xb927LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "lbr", OP16(0xb926LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "sturg", OP16(0xb925LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "clgr", OP16(0xb921LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cgr", OP16(0xb920LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lrvr", OP16(0xb91fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 2},
+  { "kmac", OP16(0xb91eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 3},
+  { "dsgfr", OP16(0xb91dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "msgfr", OP16(0xb91cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "slgfr", OP16(0xb91bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "algfr", OP16(0xb91aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "sgfr", OP16(0xb919LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "agfr", OP16(0xb918LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "llgtr", OP16(0xb917LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "llgfr", OP16(0xb916LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lgfr", OP16(0xb914LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lcgfr", OP16(0xb913LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ltgfr", OP16(0xb912LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lngfr", OP16(0xb911LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lpgfr", OP16(0xb910LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lrvgr", OP16(0xb90fLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "eregg", OP16(0xb90eLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "dsgr", OP16(0xb90dLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "msgr", OP16(0xb90cLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "slgr", OP16(0xb90bLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "algr", OP16(0xb90aLL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "sgr", OP16(0xb909LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "agr", OP16(0xb908LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lghr", OP16(0xb907LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "lgbr", OP16(0xb906LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 4},
+  { "lurag", OP16(0xb905LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lgr", OP16(0xb904LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lcgr", OP16(0xb903LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ltgr", OP16(0xb902LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lngr", OP16(0xb901LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lpgr", OP16(0xb900LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "lctl", OP8(0xb7LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0},
+  { "stctl", OP8(0xb6LL), MASK_RS_CCRD, INSTR_RS_CCRD, 3, 0},
+  { "rrxtr", OP16(0xb3ffLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
+  { "iextr", OP16(0xb3feLL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5},
+  { "qaxtr", OP16(0xb3fdLL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
+  { "cextr", OP16(0xb3fcLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "cxstr", OP16(0xb3fbLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cxutr", OP16(0xb3faLL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cxgtr", OP16(0xb3f9LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "rrdtr", OP16(0xb3f7LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
+  { "iedtr", OP16(0xb3f6LL), MASK_RRF_F0FR, INSTR_RRF_F0FR, 2, 5},
+  { "qadtr", OP16(0xb3f5LL), MASK_RRF_FFFU, INSTR_RRF_FFFU, 2, 5},
+  { "cedtr", OP16(0xb3f4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "cdstr", OP16(0xb3f3LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cdutr", OP16(0xb3f2LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cdgtr", OP16(0xb3f1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "esxtr", OP16(0xb3efLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "eextr", OP16(0xb3edLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cxtr", OP16(0xb3ecLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "csxtr", OP16(0xb3ebLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cuxtr", OP16(0xb3eaLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cgxtr", OP16(0xb3e9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5},
+  { "kxtr", OP16(0xb3e8LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "esdtr", OP16(0xb3e7LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "eedtr", OP16(0xb3e5LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cdtr", OP16(0xb3e4LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "csdtr", OP16(0xb3e3LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cudtr", OP16(0xb3e2LL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cgdtr", OP16(0xb3e1LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 5},
+  { "kdtr", OP16(0xb3e0LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "fixtr", OP16(0xb3dfLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5},
+  { "ltxtr", OP16(0xb3deLL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "ldxtr", OP16(0xb3ddLL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5},
+  { "lxdtr", OP16(0xb3dcLL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5},
+  { "sxtr", OP16(0xb3dbLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "axtr", OP16(0xb3daLL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "dxtr", OP16(0xb3d9LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "mxtr", OP16(0xb3d8LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "fidtr", OP16(0xb3d7LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5},
+  { "ltdtr", OP16(0xb3d6LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "ledtr", OP16(0xb3d5LL), MASK_RRF_UUFF, INSTR_RRF_UUFF, 2, 5},
+  { "ldetr", OP16(0xb3d4LL), MASK_RRF_0UFF, INSTR_RRF_0UFF, 2, 5},
+  { "sdtr", OP16(0xb3d3LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "adtr", OP16(0xb3d2LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "ddtr", OP16(0xb3d1LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "mdtr", OP16(0xb3d0LL), MASK_RRR_F0FF, INSTR_RRR_F0FF, 2, 5},
+  { "lgdr", OP16(0xb3cdLL), MASK_RRE_RF, INSTR_RRE_RF, 2, 5},
+  { "cgxr", OP16(0xb3caLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cgdr", OP16(0xb3c9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cger", OP16(0xb3c8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cxgr", OP16(0xb3c6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cdgr", OP16(0xb3c5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cegr", OP16(0xb3c4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "ldgr", OP16(0xb3c1LL), MASK_RRE_FR, INSTR_RRE_FR, 2, 5},
+  { "cfxr", OP16(0xb3baLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cfdr", OP16(0xb3b9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cfer", OP16(0xb3b8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cxfr", OP16(0xb3b6LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cdfr", OP16(0xb3b5LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cefr", OP16(0xb3b4LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cgxbr", OP16(0xb3aaLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cgdbr", OP16(0xb3a9LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cgebr", OP16(0xb3a8LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 2, 2},
+  { "cxgbr", OP16(0xb3a6LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cdgbr", OP16(0xb3a5LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cegbr", OP16(0xb3a4LL), MASK_RRE_RR, INSTR_RRE_RR, 2, 2},
+  { "cfxbr", OP16(0xb39aLL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0},
+  { "cfdbr", OP16(0xb399LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0},
+  { "cfebr", OP16(0xb398LL), MASK_RRF_U0RF, INSTR_RRF_U0RF, 3, 0},
+  { "cxfbr", OP16(0xb396LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cdfbr", OP16(0xb395LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "cefbr", OP16(0xb394LL), MASK_RRE_RF, INSTR_RRE_RF, 3, 0},
+  { "efpc", OP16(0xb38cLL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0},
+  { "sfasr", OP16(0xb385LL), MASK_RRE_R0, INSTR_RRE_R0, 2, 5},
+  { "sfpc", OP16(0xb384LL), MASK_RRE_RR_OPT, INSTR_RRE_RR_OPT, 3, 0},
+  { "fidr", OP16(0xb37fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "fier", OP16(0xb377LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "lzxr", OP16(0xb376LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "lzdr", OP16(0xb375LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "lzer", OP16(0xb374LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "lcdfr", OP16(0xb373LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "cpsdr", OP16(0xb372LL), MASK_RRF_F0FF2, INSTR_RRF_F0FF2, 2, 5},
+  { "lndfr", OP16(0xb371LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "lpdfr", OP16(0xb370LL), MASK_RRE_FF, INSTR_RRE_FF, 2, 5},
+  { "cxr", OP16(0xb369LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "fixr", OP16(0xb367LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "lexr", OP16(0xb366LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lxr", OP16(0xb365LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "lcxr", OP16(0xb363LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ltxr", OP16(0xb362LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lnxr", OP16(0xb361LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lpxr", OP16(0xb360LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "fidbr", OP16(0xb35fLL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "didbr", OP16(0xb35bLL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0},
+  { "thdr", OP16(0xb359LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "thder", OP16(0xb358LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "fiebr", OP16(0xb357LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "diebr", OP16(0xb353LL), MASK_RRF_FUFF, INSTR_RRF_FUFF, 3, 0},
+  { "tbdr", OP16(0xb351LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "tbedr", OP16(0xb350LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "dxbr", OP16(0xb34dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mxbr", OP16(0xb34cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sxbr", OP16(0xb34bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "axbr", OP16(0xb34aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "cxbr", OP16(0xb349LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "kxbr", OP16(0xb348LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "fixbr", OP16(0xb347LL), MASK_RRF_U0FF, INSTR_RRF_U0FF, 3, 0},
+  { "lexbr", OP16(0xb346LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ldxbr", OP16(0xb345LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ledbr", OP16(0xb344LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lcxbr", OP16(0xb343LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ltxbr", OP16(0xb342LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lnxbr", OP16(0xb341LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lpxbr", OP16(0xb340LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "msdr", OP16(0xb33fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3},
+  { "madr", OP16(0xb33eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3},
+  { "myhr", OP16(0xb33dLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "mayhr", OP16(0xb33cLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "myr", OP16(0xb33bLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "mayr", OP16(0xb33aLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "mylr", OP16(0xb339LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "maylr", OP16(0xb338LL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 2, 4},
+  { "meer", OP16(0xb337LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sqxr", OP16(0xb336LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mser", OP16(0xb32fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3},
+  { "maer", OP16(0xb32eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 3},
+  { "lxer", OP16(0xb326LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lxdr", OP16(0xb325LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lder", OP16(0xb324LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "msdbr", OP16(0xb31fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0},
+  { "madbr", OP16(0xb31eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0},
+  { "ddbr", OP16(0xb31dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mdbr", OP16(0xb31cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sdbr", OP16(0xb31bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "adbr", OP16(0xb31aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "cdbr", OP16(0xb319LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "kdbr", OP16(0xb318LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "meebr", OP16(0xb317LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sqxbr", OP16(0xb316LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sqdbr", OP16(0xb315LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sqebr", OP16(0xb314LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lcdbr", OP16(0xb313LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ltdbr", OP16(0xb312LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lndbr", OP16(0xb311LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lpdbr", OP16(0xb310LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "msebr", OP16(0xb30fLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0},
+  { "maebr", OP16(0xb30eLL), MASK_RRF_F0FF, INSTR_RRF_F0FF, 3, 0},
+  { "debr", OP16(0xb30dLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mdebr", OP16(0xb30cLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "sebr", OP16(0xb30bLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "aebr", OP16(0xb30aLL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "cebr", OP16(0xb309LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "kebr", OP16(0xb308LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "mxdbr", OP16(0xb307LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lxebr", OP16(0xb306LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lxdbr", OP16(0xb305LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ldebr", OP16(0xb304LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lcebr", OP16(0xb303LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "ltebr", OP16(0xb302LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lnebr", OP16(0xb301LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "lpebr", OP16(0xb300LL), MASK_RRE_FF, INSTR_RRE_FF, 3, 0},
+  { "trap4", OP16(0xb2ffLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "lfas", OP16(0xb2bdLL), MASK_S_RD, INSTR_S_RD, 2, 5},
+  { "srnmt", OP16(0xb2b9LL), MASK_S_RD, INSTR_S_RD, 2, 5},
+  { "lpswe", OP16(0xb2b2LL), MASK_S_RD, INSTR_S_RD, 2, 2},
+  { "stfl", OP16(0xb2b1LL), MASK_S_RD, INSTR_S_RD, 3, 2},
+  { "stfle", OP16(0xb2b0LL), MASK_S_RD, INSTR_S_RD, 2, 4},
+  { "cu12", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cutfu", OP16(0xb2a7LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cutfu", OP16(0xb2a7LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "cu21", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cuutf", OP16(0xb2a6LL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "cuutf", OP16(0xb2a6LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "tre", OP16(0xb2a5LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "lfpc", OP16(0xb29dLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stfpc", OP16(0xb29cLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "srnm", OP16(0xb299LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stsi", OP16(0xb27dLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stckf", OP16(0xb27cLL), MASK_S_RD, INSTR_S_RD, 2, 4},
+  { "sacf", OP16(0xb279LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stcke", OP16(0xb278LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "rp", OP16(0xb277LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "xsch", OP16(0xb276LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "siga", OP16(0xb274LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "cmpsc", OP16(0xb263LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "srst", OP16(0xb25eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "clst", OP16(0xb25dLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "bsa", OP16(0xb25aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "bsg", OP16(0xb258LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "cuse", OP16(0xb257LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "mvst", OP16(0xb255LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "mvpg", OP16(0xb254LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "msr", OP16(0xb252LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "csp", OP16(0xb250LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "ear", OP16(0xb24fLL), MASK_RRE_RA, INSTR_RRE_RA, 3, 0},
+  { "sar", OP16(0xb24eLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0},
+  { "cpya", OP16(0xb24dLL), MASK_RRE_AA, INSTR_RRE_AA, 3, 0},
+  { "tar", OP16(0xb24cLL), MASK_RRE_AR, INSTR_RRE_AR, 3, 0},
+  { "lura", OP16(0xb24bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "esta", OP16(0xb24aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "ereg", OP16(0xb249LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "palb", OP16(0xb248LL), MASK_RRE_00, INSTR_RRE_00, 3, 0},
+  { "msta", OP16(0xb247LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "stura", OP16(0xb246LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "sqer", OP16(0xb245LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0},
+  { "sqdr", OP16(0xb244LL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0},
+  { "cksm", OP16(0xb241LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "bakr", OP16(0xb240LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "schm", OP16(0xb23cLL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "rchp", OP16(0xb23bLL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "stcps", OP16(0xb23aLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stcrw", OP16(0xb239LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "rsch", OP16(0xb238LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "sal", OP16(0xb237LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "tpi", OP16(0xb236LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "tsch", OP16(0xb235LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stsch", OP16(0xb234LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "ssch", OP16(0xb233LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "msch", OP16(0xb232LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "hsch", OP16(0xb231LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "csch", OP16(0xb230LL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "pgout", OP16(0xb22fLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "pgin", OP16(0xb22eLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "dxr", OP16(0xb22dLL), MASK_RRE_F0, INSTR_RRE_F0, 3, 0},
+  { "tb", OP16(0xb22cLL), MASK_RRE_0R, INSTR_RRE_0R, 3, 0},
+  { "sske", OP16(0xb22bLL), MASK_RRF_M0RR, INSTR_RRF_M0RR, 2, 4},
+  { "sske", OP16(0xb22bLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "rrbe", OP16(0xb22aLL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "iske", OP16(0xb229LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "pt", OP16(0xb228LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "esar", OP16(0xb227LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "epar", OP16(0xb226LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "ssar", OP16(0xb225LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "iac", OP16(0xb224LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "ivsk", OP16(0xb223LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "ipm", OP16(0xb222LL), MASK_RRE_R0, INSTR_RRE_R0, 3, 0},
+  { "ipte", OP16(0xb221LL), MASK_RRE_RR, INSTR_RRE_RR, 3, 0},
+  { "cfc", OP16(0xb21aLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "sac", OP16(0xb219LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "pc", OP16(0xb218LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "sie", OP16(0xb214LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stap", OP16(0xb212LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stpx", OP16(0xb211LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "spx", OP16(0xb210LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "ptlb", OP16(0xb20dLL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "ipk", OP16(0xb20bLL), MASK_S_00, INSTR_S_00, 3, 0},
+  { "spka", OP16(0xb20aLL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stpt", OP16(0xb209LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "spt", OP16(0xb208LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stckc", OP16(0xb207LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "sckc", OP16(0xb206LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stck", OP16(0xb205LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "sck", OP16(0xb204LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "stidp", OP16(0xb202LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "lra", OP8(0xb1LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "mc", OP8(0xafLL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "sigp", OP8(0xaeLL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "stosm", OP8(0xadLL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "stnsm", OP8(0xacLL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "clcle", OP8(0xa9LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "mvcle", OP8(0xa8LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "j", OP16(0xa7f4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jno", OP16(0xa7e4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnh", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnp", OP16(0xa7d4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jle", OP16(0xa7c4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnl", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnm", OP16(0xa7b4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jhe", OP16(0xa7a4LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnlh", OP16(0xa794LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "je", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jz", OP16(0xa784LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jne", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnz", OP16(0xa774LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jlh", OP16(0xa764LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnhe", OP16(0xa754LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jl", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jm", OP16(0xa744LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jnle", OP16(0xa734LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jh", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jp", OP16(0xa724LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "jo", OP16(0xa714LL), MASK_RI_0P, INSTR_RI_0P, 3, 0},
+  { "cghi", OP16(0xa70fLL), MASK_RI_RI, INSTR_RI_RI, 2, 2},
+  { "chi", OP16(0xa70eLL), MASK_RI_RI, INSTR_RI_RI, 3, 0},
+  { "mghi", OP16(0xa70dLL), MASK_RI_RI, INSTR_RI_RI, 2, 2},
+  { "mhi", OP16(0xa70cLL), MASK_RI_RI, INSTR_RI_RI, 3, 0},
+  { "aghi", OP16(0xa70bLL), MASK_RI_RI, INSTR_RI_RI, 2, 2},
+  { "ahi", OP16(0xa70aLL), MASK_RI_RI, INSTR_RI_RI, 3, 0},
+  { "lghi", OP16(0xa709LL), MASK_RI_RI, INSTR_RI_RI, 2, 2},
+  { "lhi", OP16(0xa708LL), MASK_RI_RI, INSTR_RI_RI, 3, 0},
+  { "brctg", OP16(0xa707LL), MASK_RI_RP, INSTR_RI_RP, 2, 2},
+  { "brct", OP16(0xa706LL), MASK_RI_RP, INSTR_RI_RP, 3, 0},
+  { "bras", OP16(0xa705LL), MASK_RI_RP, INSTR_RI_RP, 3, 0},
+  { "brc", OP16(0xa704LL), MASK_RI_UP, INSTR_RI_UP, 3, 0},
+  { "tmhl", OP16(0xa703LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "tmhh", OP16(0xa702LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "tml", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0},
+  { "tmll", OP16(0xa701LL), MASK_RI_RU, INSTR_RI_RU, 3, 0},
+  { "tmh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0},
+  { "tmlh", OP16(0xa700LL), MASK_RI_RU, INSTR_RI_RU, 3, 0},
+  { "llill", OP16(0xa50fLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "llilh", OP16(0xa50eLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "llihl", OP16(0xa50dLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "llihh", OP16(0xa50cLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "oill", OP16(0xa50bLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "oilh", OP16(0xa50aLL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "oihl", OP16(0xa509LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "oihh", OP16(0xa508LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "nill", OP16(0xa507LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "nilh", OP16(0xa506LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "nihl", OP16(0xa505LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "nihh", OP16(0xa504LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "iill", OP16(0xa503LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "iilh", OP16(0xa502LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "iihl", OP16(0xa501LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "iihh", OP16(0xa500LL), MASK_RI_RU, INSTR_RI_RU, 2, 2},
+  { "stam", OP8(0x9bLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0},
+  { "lam", OP8(0x9aLL), MASK_RS_AARD, INSTR_RS_AARD, 3, 0},
+  { "trace", OP8(0x99LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "lm", OP8(0x98LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "xi", OP8(0x97LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "oi", OP8(0x96LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "cli", OP8(0x95LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "ni", OP8(0x94LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "ts", OP8(0x93LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "mvi", OP8(0x92LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "tm", OP8(0x91LL), MASK_SI_URD, INSTR_SI_URD, 3, 0},
+  { "stm", OP8(0x90LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "slda", OP8(0x8fLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "srda", OP8(0x8eLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "sldl", OP8(0x8dLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "srdl", OP8(0x8cLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "sla", OP8(0x8bLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "sra", OP8(0x8aLL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "sll", OP8(0x89LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "srl", OP8(0x88LL), MASK_RS_R0RD, INSTR_RS_R0RD, 3, 0},
+  { "bxle", OP8(0x87LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "bxh", OP8(0x86LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "brxle", OP8(0x85LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0},
+  { "brxh", OP8(0x84LL), MASK_RSI_RRP, INSTR_RSI_RRP, 3, 0},
+  { "diag", OP8(0x83LL), MASK_RS_RRRD, INSTR_RS_RRRD, 3, 0},
+  { "lpsw", OP8(0x82LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "ssm", OP8(0x80LL), MASK_S_RD, INSTR_S_RD, 3, 0},
+  { "su", OP8(0x7fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "au", OP8(0x7eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "de", OP8(0x7dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "me", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "mde", OP8(0x7cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "se", OP8(0x7bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ae", OP8(0x7aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ce", OP8(0x79LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "le", OP8(0x78LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ms", OP8(0x71LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ste", OP8(0x70LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "sw", OP8(0x6fLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "aw", OP8(0x6eLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "dd", OP8(0x6dLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "md", OP8(0x6cLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "sd", OP8(0x6bLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ad", OP8(0x6aLL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "cd", OP8(0x69LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "ld", OP8(0x68LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "mxd", OP8(0x67LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "std", OP8(0x60LL), MASK_RX_FRRD, INSTR_RX_FRRD, 3, 0},
+  { "sl", OP8(0x5fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "al", OP8(0x5eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "d", OP8(0x5dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "m", OP8(0x5cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "s", OP8(0x5bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "a", OP8(0x5aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "c", OP8(0x59LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "l", OP8(0x58LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "x", OP8(0x57LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "o", OP8(0x56LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "cl", OP8(0x55LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "n", OP8(0x54LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "lae", OP8(0x51LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "st", OP8(0x50LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "cvb", OP8(0x4fLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "cvd", OP8(0x4eLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "bas", OP8(0x4dLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "mh", OP8(0x4cLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "sh", OP8(0x4bLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ah", OP8(0x4aLL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ch", OP8(0x49LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "lh", OP8(0x48LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "b", OP16(0x47f0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bno", OP16(0x47e0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnh", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnp", OP16(0x47d0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "ble", OP16(0x47c0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnl", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnm", OP16(0x47b0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bhe", OP16(0x47a0LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnlh", OP16(0x4790LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "be", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bz", OP16(0x4780LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bne", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnz", OP16(0x4770LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "blh", OP16(0x4760LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnhe", OP16(0x4750LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bl", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bm", OP16(0x4740LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bnle", OP16(0x4730LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bh", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bp", OP16(0x4720LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bo", OP16(0x4710LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bc", OP8(0x47LL), MASK_RX_URRD, INSTR_RX_URRD, 3, 0},
+  { "nop", OP16(0x4700LL), MASK_RX_0RRD, INSTR_RX_0RRD, 3, 0},
+  { "bct", OP8(0x46LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "bal", OP8(0x45LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ex", OP8(0x44LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "ic", OP8(0x43LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "stc", OP8(0x42LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "la", OP8(0x41LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "sth", OP8(0x40LL), MASK_RX_RRRD, INSTR_RX_RRRD, 3, 0},
+  { "sur", OP8(0x3fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "aur", OP8(0x3eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "der", OP8(0x3dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mer", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mder", OP8(0x3cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ser", OP8(0x3bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "aer", OP8(0x3aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "cer", OP8(0x39LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ler", OP8(0x38LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "sxr", OP8(0x37LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "axr", OP8(0x36LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lrer", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ledr", OP8(0x35LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "her", OP8(0x34LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lcer", OP8(0x33LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lter", OP8(0x32LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lner", OP8(0x31LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lper", OP8(0x30LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "swr", OP8(0x2fLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "awr", OP8(0x2eLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ddr", OP8(0x2dLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mdr", OP8(0x2cLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "sdr", OP8(0x2bLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "adr", OP8(0x2aLL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "cdr", OP8(0x29LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ldr", OP8(0x28LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mxdr", OP8(0x27LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "mxr", OP8(0x26LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lrdr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ldxr", OP8(0x25LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "hdr", OP8(0x24LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lcdr", OP8(0x23LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "ltdr", OP8(0x22LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lndr", OP8(0x21LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "lpdr", OP8(0x20LL), MASK_RR_FF, INSTR_RR_FF, 3, 0},
+  { "slr", OP8(0x1fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "alr", OP8(0x1eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "dr", OP8(0x1dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "mr", OP8(0x1cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "sr", OP8(0x1bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "ar", OP8(0x1aLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "cr", OP8(0x19LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "lr", OP8(0x18LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "xr", OP8(0x17LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "or", OP8(0x16LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "clr", OP8(0x15LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "nr", OP8(0x14LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "lcr", OP8(0x13LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "ltr", OP8(0x12LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "lnr", OP8(0x11LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "lpr", OP8(0x10LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "clcl", OP8(0x0fLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "mvcl", OP8(0x0eLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "basr", OP8(0x0dLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "bassm", OP8(0x0cLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "bsm", OP8(0x0bLL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "svc", OP8(0x0aLL), MASK_RR_U0, INSTR_RR_U0, 3, 0},
+  { "br", OP16(0x07f0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnor", OP16(0x07e0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnhr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnpr", OP16(0x07d0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bler", OP16(0x07c0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnlr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnmr", OP16(0x07b0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bher", OP16(0x07a0LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnlhr", OP16(0x0790LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "ber", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bzr", OP16(0x0780LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bner", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnzr", OP16(0x0770LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "blhr", OP16(0x0760LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnher", OP16(0x0750LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "blr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bmr", OP16(0x0740LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bnler", OP16(0x0730LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bhr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bpr", OP16(0x0720LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bor", OP16(0x0710LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bcr", OP8(0x07LL), MASK_RR_UR, INSTR_RR_UR, 3, 0},
+  { "nopr", OP16(0x0700LL), MASK_RR_0R, INSTR_RR_0R, 3, 0},
+  { "bctr", OP8(0x06LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "balr", OP8(0x05LL), MASK_RR_RR, INSTR_RR_RR, 3, 0},
+  { "spm", OP8(0x04LL), MASK_RR_R0, INSTR_RR_R0, 3, 0},
+  { "trap2", OP16(0x01ffLL), MASK_E, INSTR_E, 3, 0},
+  { "sam64", OP16(0x010eLL), MASK_E, INSTR_E, 2, 2},
+  { "sam31", OP16(0x010dLL), MASK_E, INSTR_E, 3, 2},
+  { "sam24", OP16(0x010cLL), MASK_E, INSTR_E, 3, 2},
+  { "tam", OP16(0x010bLL), MASK_E, INSTR_E, 3, 2},
+  { "pfpo", OP16(0x010aLL), MASK_E, INSTR_E, 2, 5},
+  { "sckpf", OP16(0x0107LL), MASK_E, INSTR_E, 3, 0},
+  { "upt", OP16(0x0102LL), MASK_E, INSTR_E, 3, 0},
+  { "pr", OP16(0x0101LL), MASK_E, INSTR_E, 3, 0}
+};
+
+const int s390_num_opcodes =
+  sizeof (s390_opcodes) / sizeof (s390_opcodes[0]);
+
diff --git a/sdl.c b/sdl.c
index d242cce..02500c9 100644
--- a/sdl.c
+++ b/sdl.c
@@ -1,8 +1,8 @@
 /*
  * QEMU SDL display driver
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -34,6 +34,7 @@
 static int last_vm_running;
 static int gui_saved_grab;
 static int gui_fullscreen;
+static int gui_noframe;
 static int gui_key_modifier_pressed;
 static int gui_keysym;
 static int gui_fullscreen_initial_grab;
@@ -43,6 +44,9 @@
 static SDL_Cursor *sdl_cursor_normal;
 static SDL_Cursor *sdl_cursor_hidden;
 static int absolute_enabled = 0;
+static int guest_cursor = 0;
+static int guest_x, guest_y;
+static SDL_Cursor *guest_sprite = 0;
 
 static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
 {
@@ -59,6 +63,8 @@
     flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
     if (gui_fullscreen)
         flags |= SDL_FULLSCREEN;
+    if (gui_noframe)
+        flags |= SDL_NOFRAME;
 
     width = w;
     height = h;
@@ -81,7 +87,7 @@
     ds->data = screen->pixels;
     ds->linesize = screen->pitch;
     ds->depth = screen->format->BitsPerPixel;
-    if (ds->depth == 32 && screen->format->Rshift == 0) {
+    if (screen->format->Bshift > screen->format->Rshift) {
         ds->bgr = 1;
     } else {
         ds->bgr = 0;
@@ -213,23 +219,36 @@
 static void sdl_update_caption(void)
 {
     char buf[1024];
-    strcpy(buf, "QEMU");
+    const char *status = "";
+
+    if (!vm_running)
+        status = " [Stopped]";
+    else if (gui_grab) {
+        if (!alt_grab)
+            status = " - Press Ctrl-Alt to exit grab";
+        else
+            status = " - Press Ctrl-Alt-Shift to exit grab";
+    }
+
+    if (qemu_name)
+        snprintf(buf, sizeof(buf), "QEMU (%s)%s", qemu_name, status);
+    else
+        snprintf(buf, sizeof(buf), "QEMU%s", status);
+
 #if USE_KVM
     if (kvm_allowed) {
         strcat(buf, "/KVM");
     }
 #endif
-    if (!vm_running) {
-        strcat(buf, " [Stopped]");
-    }
-    if (gui_grab) {
-        strcat(buf, " - Press Ctrl-Alt to exit grab");
-    }
+
     SDL_WM_SetCaption(buf, "QEMU");
 }
 
 static void sdl_hide_cursor(void)
 {
+    if (!cursor_hide)
+        return;
+
     if (kbd_mouse_is_absolute()) {
         SDL_ShowCursor(1);
         SDL_SetCursor(sdl_cursor_hidden);
@@ -240,15 +259,26 @@
 
 static void sdl_show_cursor(void)
 {
+    if (!cursor_hide)
+        return;
+
     if (!kbd_mouse_is_absolute()) {
         SDL_ShowCursor(1);
-        SDL_SetCursor(sdl_cursor_normal);
+        if (guest_cursor &&
+                (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+            SDL_SetCursor(guest_sprite);
+        else
+            SDL_SetCursor(sdl_cursor_normal);
     }
 }
 
 static void sdl_grab_start(void)
 {
-    sdl_hide_cursor();
+    if (guest_cursor) {
+        SDL_SetCursor(guest_sprite);
+        SDL_WarpMouse(guest_x, guest_y);
+    } else
+        sdl_hide_cursor();
     SDL_WM_GrabInput(SDL_GRAB_ON);
     /* dummy read to avoid moving the mouse */
     SDL_GetRelativeMouseState(NULL, NULL);
@@ -259,8 +289,8 @@
 static void sdl_grab_end(void)
 {
     SDL_WM_GrabInput(SDL_GRAB_OFF);
-    sdl_show_cursor();
     gui_grab = 0;
+    sdl_show_cursor();
     sdl_update_caption();
 }
 
@@ -291,6 +321,12 @@
     } else if (absolute_enabled) {
 	sdl_show_cursor();
 	absolute_enabled = 0;
+    } else if (guest_cursor) {
+        SDL_GetMouseState(&dx, &dy);
+        dx -= guest_x;
+        dy -= guest_y;
+        guest_x += dx;
+        guest_y += dy;
     }
 
     kbd_mouse_event(dx, dy, dz, buttons);
@@ -315,7 +351,7 @@
 {
     SDL_Event ev1, *ev = &ev1;
     int mod_state;
-                     
+
     if (last_vm_running != vm_running) {
         last_vm_running = vm_running;
         sdl_update_caption();
@@ -331,8 +367,13 @@
         case SDL_KEYDOWN:
         case SDL_KEYUP:
             if (ev->type == SDL_KEYDOWN) {
-                mod_state = (SDL_GetModState() & gui_grab_code) ==
-                    gui_grab_code;
+                if (!alt_grab) {
+                    mod_state = (SDL_GetModState() & gui_grab_code) ==
+                                gui_grab_code;
+                } else {
+                    mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
+                                (gui_grab_code | KMOD_LSHIFT);
+                }
                 gui_key_modifier_pressed = mod_state;
                 if (gui_key_modifier_pressed) {
                     int keycode;
@@ -342,7 +383,7 @@
                         toggle_full_screen(ds);
                         gui_keysym = 1;
                         break;
-                    case 0x02 ... 0x0a: /* '1' to '9' keys */ 
+                    case 0x02 ... 0x0a: /* '1' to '9' keys */
                         /* Reset the modifiers sent to the current console */
                         reset_keys();
                         console_select(keycode - 0x02);
@@ -381,7 +422,8 @@
                         case SDLK_END: keysym = QEMU_KEY_END; break;
                         case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
                         case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
-                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
+                        case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
+                        case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
                         default: break;
                         }
                     }
@@ -392,7 +434,12 @@
                     }
                 }
             } else if (ev->type == SDL_KEYUP) {
-                mod_state = (ev->key.keysym.mod & gui_grab_code);
+                if (!alt_grab) {
+                    mod_state = (ev->key.keysym.mod & gui_grab_code);
+                } else {
+                    mod_state = (ev->key.keysym.mod &
+                                 (gui_grab_code | KMOD_LSHIFT));
+                }
                 if (!mod_state) {
                     if (gui_key_modifier_pressed) {
                         gui_key_modifier_pressed = 0;
@@ -419,12 +466,13 @@
                     }
                 }
             }
-            if (is_graphic_console() && !gui_keysym) 
+            if (is_graphic_console() && !gui_keysym)
                 sdl_process_key(&ev->key);
             break;
         case SDL_QUIT:
             if (!no_quit) {
-               qemu_system_shutdown_request();
+                qemu_system_shutdown_request();
+                vm_start();	/* In case we're paused */
             }
             break;
         case SDL_MOUSEMOTION:
@@ -452,7 +500,7 @@
                     } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
                         dz = 1;
                     }
-#endif               
+#endif
                     sdl_send_mouse_event(dz);
                 }
             }
@@ -469,12 +517,81 @@
     }
 }
 
-static void sdl_cleanup(void) 
+static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
 {
+    SDL_Rect dst = { x, y, w, h };
+    SDL_FillRect(screen, &dst, c);
+}
+
+static void sdl_mouse_warp(int x, int y, int on)
+{
+    if (on) {
+        if (!guest_cursor)
+            sdl_show_cursor();
+        if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
+            SDL_SetCursor(guest_sprite);
+            SDL_WarpMouse(x, y);
+        }
+    } else if (gui_grab)
+        sdl_hide_cursor();
+    guest_cursor = on;
+    guest_x = x, guest_y = y;
+}
+
+static void sdl_mouse_define(int width, int height, int bpp,
+                             int hot_x, int hot_y,
+                             uint8_t *image, uint8_t *mask)
+{
+    uint8_t sprite[256], *line;
+    int x, y, dst, bypl, src = 0;
+    if (guest_sprite)
+        SDL_FreeCursor(guest_sprite);
+
+    memset(sprite, 0, 256);
+    bypl = ((width * bpp + 31) >> 5) << 2;
+    for (y = 0, dst = 0; y < height; y ++, image += bypl) {
+        line = image;
+        for (x = 0; x < width; x ++, dst ++) {
+            switch (bpp) {
+            case 24:
+                src = *(line ++); src |= *(line ++); src |= *(line ++);
+                break;
+            case 16:
+            case 15:
+                src = *(line ++); src |= *(line ++);
+                break;
+            case 8:
+                src = *(line ++);
+                break;
+            case 4:
+                src = 0xf & (line[x >> 1] >> ((x & 1)) << 2);
+                break;
+            case 2:
+                src = 3 & (line[x >> 2] >> ((x & 3)) << 1);
+                break;
+            case 1:
+                src = 1 & (line[x >> 3] >> (x & 7));
+                break;
+            }
+            if (!src)
+                sprite[dst >> 3] |= (1 << (~dst & 7)) & mask[dst >> 3];
+        }
+    }
+    guest_sprite = SDL_CreateCursor(sprite, mask, width, height, hot_x, hot_y);
+
+    if (guest_cursor &&
+            (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+        SDL_SetCursor(guest_sprite);
+}
+
+static void sdl_cleanup(void)
+{
+    if (guest_sprite)
+        SDL_FreeCursor(guest_sprite);
     SDL_Quit();
 }
 
-void sdl_display_init(DisplayState *ds, int full_screen)
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
 {
     int flags;
     uint8_t data = 0;
@@ -490,6 +607,9 @@
             exit(1);
     }
 
+    if (no_frame)
+        gui_noframe = 1;
+
     flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
     if (SDL_Init (flags)) {
         fprintf(stderr, "Could not initialize SDL - exiting\n");
@@ -504,6 +624,9 @@
     ds->dpy_update = sdl_update;
     ds->dpy_resize = sdl_resize;
     ds->dpy_refresh = sdl_refresh;
+    ds->dpy_fill = sdl_fill;
+    ds->mouse_set = sdl_mouse_warp;
+    ds->cursor_define = sdl_mouse_define;
 
     sdl_resize(ds, 640, 400);
     sdl_update_caption();
diff --git a/sh4-dis.c b/sh4-dis.c
index 5f45e5e..a1d56c5 100644
--- a/sh4-dis.c
+++ b/sh4-dis.c
@@ -483,7 +483,7 @@
 /* 0100nnnn10111010 lds <REG_N>,Y1	*/{"lds",{A_REG_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up},
 
 /* 0100nnnn01011010 lds <REG_N>,FPUL    */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}, arch_sh2e_up},
-  
+
 /* 0100nnnn01101010 lds <REG_M>,FPSCR   */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}, arch_sh2e_up},
 
 /* 0100nnnn00000110 lds.l @<REG_N>+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}, arch_sh1_up},
@@ -505,7 +505,7 @@
 /* 0100nnnn10110110 lds.l @<REG_N>+,Y1	*/{"lds.l",{A_INC_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_6}, arch_sh_dsp_up},
 
 /* 0100nnnn01010110 lds.l @<REG_M>+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}, arch_sh2e_up},
-  
+
 /* 0100nnnn01100110 lds.l @<REG_M>+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}, arch_sh2e_up},
 
 /* 0000000000111000 ldtlb               */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}, arch_sh3_up},
@@ -758,7 +758,7 @@
 /* 0000nnnn10111010 sts Y1,<REG_N>	*/{"sts",{A_Y1,A_REG_N},{HEX_0,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up},
 
 /* 0000nnnn01011010 sts FPUL,<REG_N>    */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}, arch_sh2e_up},
-  
+
 /* 0000nnnn01101010 sts FPSCR,<REG_N>   */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh2e_up},
 
 /* 0100nnnn00000010 sts.l MACH,@-<REG_N>*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}, arch_sh1_up},
@@ -780,7 +780,7 @@
 /* 0100nnnn10110110 sts.l Y1,@-<REG_N>	*/{"sts.l",{A_Y1,A_DEC_N},{HEX_4,REG_N,HEX_B,HEX_2}, arch_sh_dsp_up},
 
 /* 0100nnnn01010010 sts.l FPUL,@-<REG_N>*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}, arch_sh2e_up},
-  
+
 /* 0100nnnn01100010 sts.l FPSCR,@-<REG_N>*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh2e_up},
 
 /* 0011nnnnmmmm1000 sub <REG_M>,<REG_N> */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}, arch_sh1_up},
@@ -1155,7 +1155,7 @@
 /* 0011nnnnmmmm0001 1001dddddddddddd movu.w @(<DISP12>,<REG_M>),<REG_N> */
 {"movu.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_9,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32},
 
-{ 0, {0}, {0}, 0 } 
+{ 0, {0}, {0}, 0 }
 };
 
 #endif
@@ -1293,7 +1293,7 @@
 	while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3)
 	       || op->nibbles[3] != (unsigned) (insn & 0xf))
 	  op++;
-	
+
 	print_movxy (op,
 		     (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0)
 		      + 2 * is_movy
diff --git a/slirp/COPYRIGHT b/slirp/COPYRIGHT
index 2e86862..3f331ee 100644
--- a/slirp/COPYRIGHT
+++ b/slirp/COPYRIGHT
@@ -16,7 +16,7 @@
 ---BEGIN---
 
  Copyright (c) 1995,1996 Danny Gasparovski.  All rights reserved.
- 
+
  Redistribution and use in source and binary forms, with or without
  modification, are permitted provided that the following conditions
  are met:
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 62cbcfd..9f2635b 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -1,8 +1,8 @@
 /*
  * QEMU BOOTP/DHCP server
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -38,6 +38,8 @@
 
 BOOTPClient bootp_clients[NB_ADDR];
 
+const char *bootp_filename;
+
 static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
 
 #ifdef DEBUG
@@ -87,7 +89,7 @@
     const uint8_t *p, *p_end;
     int len, tag;
 
-    *pmsg_type = 0;    
+    *pmsg_type = 0;
 
     p = buf;
     p_end = buf + size;
@@ -99,7 +101,7 @@
     while (p < p_end) {
         tag = p[0];
         if (tag == RFC1533_PAD) {
-            p++; 
+            p++;
         } else if (tag == RFC1533_END) {
             break;
         } else {
@@ -135,16 +137,16 @@
     /* extract exact DHCP msg type */
     dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type);
     dprintf("bootp packet op=%d msgtype=%d\n", bp->bp_op, dhcp_msg_type);
-    
+
     if (dhcp_msg_type == 0)
         dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
-        
-    if (dhcp_msg_type != DHCPDISCOVER && 
+
+    if (dhcp_msg_type != DHCPDISCOVER &&
         dhcp_msg_type != DHCPREQUEST)
         return;
     /* XXX: this is a hack to get the client mac address */
     memcpy(client_ethaddr, bp->bp_hwaddr, 6);
-    
+
     if ((m = m_get()) == NULL)
         return;
     m->m_data += if_maxlinkhdr;
@@ -168,6 +170,10 @@
             goto new_addr;
         }
     }
+
+    if (bootp_filename)
+        snprintf(rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
+
     dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));
 
     saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
@@ -197,7 +203,7 @@
         *q++ = 1;
         *q++ = DHCPACK;
     }
-        
+
     if (dhcp_msg_type == DHCPDISCOVER ||
         dhcp_msg_type == DHCPREQUEST) {
         *q++ = RFC2132_SRV_ID;
@@ -211,12 +217,12 @@
         *q++ = 0xff;
         *q++ = 0xff;
         *q++ = 0x00;
-        
+
         *q++ = RFC1533_GATEWAY;
         *q++ = 4;
         memcpy(q, &saddr.sin_addr, 4);
         q += 4;
-        
+
         *q++ = RFC1533_DNS;
         *q++ = 4;
         dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS);
@@ -238,8 +244,8 @@
         }
     }
     *q++ = RFC1533_END;
-    
-    m->m_len = sizeof(struct bootp_t) - 
+
+    m->m_len = sizeof(struct bootp_t) -
         sizeof(struct ip) - sizeof(struct udphdr);
     udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
 }
diff --git a/slirp/cksum.c b/slirp/cksum.c
index f8f7512..b98373b 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -41,7 +41,7 @@
  *
  * This routine is very heavily used in the network
  * code and should be modified for each CPU to be as fast as possible.
- * 
+ *
  * XXX Since we will never span more than 1 mbuf, we can optimise this
  */
 
@@ -63,13 +63,13 @@
 		u_int16_t s[2];
 		u_int32_t l;
 	} l_util;
-	
+
 	if (m->m_len == 0)
 	   goto cont;
 	w = mtod(m, u_int16_t *);
-	
+
 	mlen = m->m_len;
-	
+
 	if (len < mlen)
 	   mlen = len;
 	len -= mlen;
@@ -107,7 +107,7 @@
 	while ((mlen -= 2) >= 0) {
 		sum += *w++;
 	}
-	
+
 	if (byte_swapped) {
 		REDUCE;
 		sum <<= 8;
@@ -117,11 +117,11 @@
 			sum += s_util.s;
 			mlen = 0;
 		} else
-		   
+
 		   mlen = -1;
 	} else if (mlen == -1)
 	   s_util.c[0] = *(u_int8_t *)w;
-	
+
 cont:
 #ifdef DEBUG
 	if (len) {
diff --git a/slirp/debug.c b/slirp/debug.c
index d3d8c57..e312445 100644
--- a/slirp/debug.c
+++ b/slirp/debug.c
@@ -1,8 +1,8 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
  * Portions copyright (c) 2000 Kelly Price.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -18,7 +18,7 @@
 
 extern char *strerror _P((int));
 
-/* Carry over one item from main.c so that the tty's restored. 
+/* Carry over one item from main.c so that the tty's restored.
  * Only done when the tty being used is /dev/tty --RedWolf */
 extern struct termios slirp_tty_settings;
 extern int slirp_tty_restore;
@@ -32,7 +32,7 @@
 	/* Close the old debugging file */
 	if (dfd)
 	   fclose(dfd);
-	
+
 	dfd = fopen(file,"w");
 	if (dfd != NULL) {
 #if 0
@@ -58,7 +58,7 @@
 {
 	u_char *pptr = (u_char *)dat;
 	int j,k;
-	
+
 	n /= 16;
 	n++;
 	DEBUG_MISC((dfd, "PACKET DUMPED: \n"));
@@ -74,7 +74,7 @@
 #if 0
 /*
  * Statistic routines
- * 
+ *
  * These will print statistics to the screen, the debug file (dfd), or
  * a buffer, depending on "type", so that the stats can be sent over
  * the link as well.
@@ -86,9 +86,9 @@
 {
 	struct slirp_ifstats *is = &ttyp->ifstats;
 	char buff[512];
-	
+
 	lprint(" \r\n");
-	
+
 	if (if_comp & IF_COMPRESS)
 	   strcpy(buff, "on");
 	else if (if_comp & IF_NOCOMPRESS)
@@ -123,7 +123,7 @@
 allttystats()
 {
 	struct ttys *ttyp;
-	
+
 	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
 	   ttystats(ttyp);
 }
@@ -132,7 +132,7 @@
 void
 ipstats()
 {
-	lprint(" \r\n");	
+	lprint(" \r\n");
 
 	lprint("IP stats:\r\n");
 	lprint("  %6d total packets received (%d were unaligned)\r\n",
@@ -158,9 +158,9 @@
 vjstats()
 {
 	lprint(" \r\n");
-	
+
 	lprint("VJ compression stats:\r\n");
-	
+
 	lprint("  %6d outbound packets (%d compressed)\r\n",
 	       comp_s.sls_packets, comp_s.sls_compressed);
 	lprint("  %6d searches for connection stats (%d misses)\r\n",
@@ -178,7 +178,7 @@
 	lprint(" \r\n");
 
 	lprint("TCP stats:\r\n");
-	
+
 	lprint("  %6d packets sent\r\n", tcpstat.tcps_sndtotal);
 	lprint("          %6d data packets (%d bytes)\r\n",
 			tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte);
@@ -191,8 +191,8 @@
 	lprint("          %6d window update packets\r\n", tcpstat.tcps_sndwinup);
 	lprint("          %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl);
 	lprint("          %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin);
-	
-	lprint("  %6d packets received\r\n", tcpstat.tcps_rcvtotal);       
+
+	lprint("  %6d packets received\r\n", tcpstat.tcps_rcvtotal);
 	lprint("          %6d acks (for %d bytes)\r\n",
 			tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte);
 	lprint("          %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack);
@@ -201,7 +201,7 @@
 			tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte);
         lprint("          %6d completely duplicate packets (%d bytes)\r\n",
 			tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte);
-	
+
 	lprint("          %6d packets with some duplicate data (%d bytes duped)\r\n",
 			tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte);
 	lprint("          %6d out-of-order packets (%d bytes)\r\n",
@@ -214,7 +214,7 @@
 	lprint("          %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum);
 	lprint("          %6d discarded for bad header offset fields\r\n",
 			tcpstat.tcps_rcvbadoff);
-	
+
 	lprint("  %6d connection requests\r\n", tcpstat.tcps_connattempt);
 	lprint("  %6d connection accepts\r\n", tcpstat.tcps_accepts);
 	lprint("  %6d connections established (including accepts)\r\n", tcpstat.tcps_connects);
@@ -233,8 +233,8 @@
 	lprint("  %6d correct ACK header predictions\r\n", tcpstat.tcps_predack);
 	lprint("  %6d correct data packet header predictions\n", tcpstat.tcps_preddat);
 	lprint("  %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss);
-	
-	
+
+
 /*	lprint("    Packets received too short:		%d\r\n", tcpstat.tcps_rcvshort); */
 /*	lprint("    Segments dropped due to PAWS:	%d\r\n", tcpstat.tcps_pawsdrop); */
 
@@ -272,18 +272,18 @@
 {
 	struct mbuf *m;
 	int i;
-	
+
         lprint(" \r\n");
-	
+
 	lprint("Mbuf stats:\r\n");
 
 	lprint("  %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max);
-	
+
 	i = 0;
 	for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next)
 		i++;
 	lprint("  %6d mbufs on free list\r\n",  i);
-	
+
 	i = 0;
 	for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
 		i++;
@@ -299,12 +299,12 @@
 	struct socket *so;
 
         lprint(" \r\n");
-	
+
 	lprint(
 	   "Proto[state]     Sock     Local Address, Port  Remote Address, Port RecvQ SendQ\r\n");
-			
+
 	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
-		
+
 		n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE");
 		while (n < 17)
 		   buff[n++] = ' ';
@@ -316,9 +316,9 @@
 				inet_ntoa(so->so_faddr), ntohs(so->so_fport),
 				so->so_rcv.sb_cc, so->so_snd.sb_cc);
 	}
-		   
+
 	for (so = udb.so_next; so != &udb; so = so->so_next) {
-		
+
 		n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000);
 		while (n < 17)
 		   buff[n++] = ' ';
@@ -338,7 +338,7 @@
 	int exit_status;
 {
 	struct ttys *ttyp;
-	
+
 	DEBUG_CALL("slirp_exit");
 	DEBUG_ARG("exit_status = %d", exit_status);
 
@@ -347,7 +347,7 @@
 		if (!dfd)
 		   debug_init("slirp_stats", 0xf);
 		lprint_arg = (char **)&dfd;
-		
+
 		ipstats();
 		tcpstats();
 		udpstats();
@@ -357,17 +357,17 @@
 		allttystats();
 		vjstats();
 	}
-	
+
 	for (ttyp = ttys; ttyp; ttyp = ttyp->next)
 	   tty_detached(ttyp, 1);
-	
+
 	if (slirp_forked) {
 		/* Menendez time */
 		if (kill(getppid(), SIGQUIT) < 0)
 			lprint("Couldn't kill parent process %ld!\n",
 			    (long) getppid());
     	}
-	
+
 	/* Restore the terminal if we gotta */
 	if(slirp_tty_restore)
 	  tcsetattr(0,TCSANOW, &slirp_tty_settings);  /* NOW DAMMIT! */
diff --git a/slirp/debug.h b/slirp/debug.h
index 6e8444d..fa62cb9 100644
--- a/slirp/debug.h
+++ b/slirp/debug.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
diff --git a/slirp/if.c b/slirp/if.c
index 94132ca..6d72fa7 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -77,12 +77,12 @@
 {
 	int ret;
 	int total;
-	
+
 	/* This should succeed most of the time */
 	ret = send(fd, bptr, n,0);
 	if (ret == n || ret <= 0)
 	   return ret;
-	
+
 	/* Didn't write everything, go into the loop */
 	total = ret;
 	while (n > total) {
@@ -97,7 +97,7 @@
 /*
  * if_input - read() the tty, do "top level" processing (ie: check for any escapes),
  * and pass onto (*ttyp->if_input)
- * 
+ *
  * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet.
  */
 #define INBUFF_SIZE 2048 /* XXX */
@@ -107,14 +107,14 @@
 {
 	u_char if_inbuff[INBUFF_SIZE];
 	int if_n;
-	
+
 	DEBUG_CALL("if_input");
 	DEBUG_ARG("ttyp = %lx", (long)ttyp);
-	
+
 	if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0);
-	
+
 	DEBUG_MISC((dfd, " read %d bytes\n", if_n));
-	
+
 	if (if_n <= 0) {
 		if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) {
 			if (ttyp->up)
@@ -138,19 +138,19 @@
 		}
 	}
 	ttyp->ones = ttyp->zeros = 0;
-	
+
 	(*ttyp->if_input)(ttyp, if_inbuff, if_n);
 }
-#endif	
-	
+#endif
+
 /*
  * if_output: Queue packet into an output queue.
- * There are 2 output queue's, if_fastq and if_batchq. 
+ * There are 2 output queue's, if_fastq and if_batchq.
  * Each output queue is a doubly linked list of double linked lists
  * of mbufs, each list belonging to one "session" (socket).  This
  * way, we can output packets fairly by sending one packet from each
  * session, instead of all the packets from one session, then all packets
- * from the next session, etc.  Packets on the if_fastq get absolute 
+ * from the next session, etc.  Packets on the if_fastq get absolute
  * priority, but if one session hogs the link, it gets "downgraded"
  * to the batchq until it runs out of packets, then it'll return
  * to the fastq (eg. if the user does an ls -alR in a telnet session,
@@ -163,11 +163,11 @@
 {
 	struct mbuf *ifq;
 	int on_fastq = 1;
-	
+
 	DEBUG_CALL("if_output");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("ifm = %lx", (long)ifm);
-	
+
 	/*
 	 * First remove the mbuf from m_usedlist,
 	 * since we're gonna use m_next and m_prev ourselves
@@ -177,9 +177,9 @@
 		remque(ifm);
 		ifm->m_flags &= ~M_USEDLIST;
 	}
-	
+
 	/*
-	 * See if there's already a batchq list for this session.  
+	 * See if there's already a batchq list for this session.
 	 * This can include an interactive session, which should go on fastq,
 	 * but gets too greedy... hence it'll be downgraded from fastq to batchq.
 	 * We mustn't put this packet back on the fastq (or we'll send it out of order)
@@ -193,7 +193,7 @@
 			goto diddit;
 		}
 	}
-	
+
 	/* No match, check which queue to put it on */
 	if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
 		ifq = if_fastq.ifq_prev;
@@ -209,15 +209,15 @@
 		}
 	} else
 		ifq = if_batchq.ifq_prev;
-	
+
 	/* Create a new doubly linked list for this session */
 	ifm->ifq_so = so;
 	ifs_init(ifm);
 	insque(ifm, ifq);
-	
+
 diddit:
 	++if_queued;
-	
+
 	if (so) {
 		/* Update *_queued */
 		so->so_queued++;
@@ -229,12 +229,12 @@
 		 * have been sent over the link
 		 * (XXX These are arbitrary numbers, probably not optimal..)
 		 */
-		if (on_fastq && ((so->so_nqueued >= 6) && 
+		if (on_fastq && ((so->so_nqueued >= 6) &&
 				 (so->so_nqueued - so->so_queued) >= 3)) {
-			
+
 			/* Remove from current queue... */
 			remque(ifm->ifs_next);
-			
+
 			/* ...And insert in the new.  That'll teach ya! */
 			insque(ifm->ifs_next, &if_batchq);
 		}
@@ -267,12 +267,12 @@
 if_start(void)
 {
 	struct mbuf *ifm, *ifqt;
-	
+
 	DEBUG_CALL("if_start");
-	
+
 	if (if_queued == 0)
 	   return; /* Nothing to do */
-	
+
  again:
         /* check if we can really output */
         if (!slirp_can_output())
@@ -290,7 +290,7 @@
 		   ifm = next_m;
 		else
 		   ifm = if_batchq.ifq_next;
-		
+
 		/* Set which packet to send on next iteration */
 		next_m = ifm->ifq_next;
 	}
@@ -298,20 +298,20 @@
 	ifqt = ifm->ifq_prev;
 	remque(ifm);
 	--if_queued;
-	
+
 	/* If there are more packets for this session, re-queue them */
 	if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) {
 		insque(ifm->ifs_next, ifqt);
 		ifs_remque(ifm);
 	}
-	
+
 	/* Update so_queued */
 	if (ifm->ifq_so) {
 		if (--ifm->ifq_so->so_queued == 0)
 		   /* If there's no more queued, reset nqueued */
 		   ifm->ifq_so->so_nqueued = 0;
 	}
-	
+
 	/* Encapsulate the packet for sending */
         if_encap(ifm->m_data, ifm->m_len);
 
diff --git a/slirp/if.h b/slirp/if.h
index 5d96a90..bf24174 100644
--- a/slirp/if.h
+++ b/slirp/if.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -39,11 +39,11 @@
 	u_int in_bytes;		/* Input bytes */
 	u_int in_errpkts;		/* Input Error Packets */
 	u_int in_errbytes;	/* Input Error Bytes */
-	
+
 	u_int bytes_saved;	/* Number of bytes that compression "saved" */
 				/* ie: number of bytes that didn't need to be sent over the link
 				 * because of compression */
-	
+
 	u_int in_mbad;		/* Bad incoming packets */
 };
 
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index b67a373..ae5a321 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -63,7 +63,7 @@
 /* INFO (15) */          0,
 /* INFO REPLY (16) */    0,
 /* ADDR MASK (17) */     0,
-/* ADDR MASK REPLY (18) */ 0 
+/* ADDR MASK REPLY (18) */ 0
 };
 
 /*
@@ -78,13 +78,13 @@
   register struct ip *ip=mtod(m, struct ip *);
   int icmplen=ip->ip_len;
   /* int code; */
-	
+
   DEBUG_CALL("icmp_input");
   DEBUG_ARG("m = %lx", (long )m);
   DEBUG_ARG("m_len = %d", m->m_len);
 
   icmpstat.icps_received++;
-	
+
   /*
    * Locate icmp structure in mbuf, and check
    * that its not corrupted and of at least minimum length.
@@ -105,7 +105,7 @@
   }
   m->m_len += hlen;
   m->m_data -= hlen;
-  
+
   /*	icmpstat.icps_inhist[icp->icmp_type]++; */
   /* code = icp->icmp_code; */
 
@@ -121,7 +121,7 @@
       struct sockaddr_in addr;
       if ((so = socreate()) == NULL) goto freeit;
       if(udp_attach(so) == -1) {
-	DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", 
+	DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
 		    errno,strerror(errno)));
 	sofree(so);
 	m_free(m);
@@ -135,7 +135,7 @@
       so->so_iptos = ip->ip_tos;
       so->so_type = IPPROTO_ICMP;
       so->so_state = SS_ISFCONNECTED;
-      
+
       /* Send the packet */
       addr.sin_family = AF_INET;
       if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
@@ -157,7 +157,7 @@
 		(struct sockaddr *)&addr, sizeof(addr)) == -1) {
 	DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
 		    errno,strerror(errno)));
-	icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); 
+	icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
 	udp_detach(so);
       }
     } /* if ip->ip_dst.s_addr == alias_addr.s_addr */
@@ -173,7 +173,7 @@
     icmpstat.icps_notsupp++;
     m_freem(m);
     break;
-    
+
   default:
     icmpstat.icps_badtype++;
     m_freem(m);
@@ -199,7 +199,7 @@
  * mbuf *msrc is used as a template, but is NOT m_free()'d.
  * It is reported as the bad ip packet.  The header should
  * be fully correct and in host byte order.
- * ICMP fragmentation is illegal.  All machines must accept 576 bytes in one 
+ * ICMP fragmentation is illegal.  All machines must accept 576 bytes in one
  * packet.  The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
  */
 
@@ -226,7 +226,7 @@
   /* check msrc */
   if(!msrc) goto end_error;
   ip = mtod(msrc, struct ip *);
-#if DEBUG  
+#if DEBUG
   { char bufa[20], bufb[20];
     strcpy(bufa, inet_ntoa(ip->ip_src));
     strcpy(bufb, inet_ntoa(ip->ip_dst));
@@ -258,9 +258,9 @@
   /* make the header of the reply packet */
   ip  = mtod(m, struct ip *);
   hlen= sizeof(struct ip );     /* no options in reply */
-  
+
   /* fill in icmp */
-  m->m_data += hlen;                  
+  m->m_data += hlen;
   m->m_len -= hlen;
 
   icp = mtod(m, struct icmp *);
@@ -269,7 +269,7 @@
   else if(s_ip_len>ICMP_MAXDATALEN)         /* maximum size */
     s_ip_len=ICMP_MAXDATALEN;
 
-  m->m_len=ICMP_MINLEN+s_ip_len;        /* 8 bytes ICMP header */  
+  m->m_len=ICMP_MINLEN+s_ip_len;        /* 8 bytes ICMP header */
 
   /* min. size = 8+sizeof(struct ip)+8 */
 
@@ -304,7 +304,7 @@
   /* fill in ip */
   ip->ip_hl = hlen >> 2;
   ip->ip_len = m->m_len;
-  
+
   ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0);  /* high priority for errors */
 
   ip->ip_ttl = MAXTTL;
@@ -313,7 +313,7 @@
   ip->ip_src = alias_addr;
 
   (void ) ip_output((struct socket *)NULL, m);
-  
+
   icmpstat.icps_reflect++;
 
 end_error:
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index 4f5bfd9..a7d6e31 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -37,7 +37,7 @@
 /*
  * Changes and additions relating to SLiRP are
  * Copyright (c) 1995 Danny Gasparovski.
- * 
+ *
  * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
@@ -73,20 +73,20 @@
 {
 	register struct ip *ip;
 	int hlen;
-	
+
 	DEBUG_CALL("ip_input");
 	DEBUG_ARG("m = %lx", (long)m);
 	DEBUG_ARG("m_len = %d", m->m_len);
 
 	ipstat.ips_total++;
-	
+
 	if (m->m_len < sizeof (struct ip)) {
 		ipstat.ips_toosmall++;
 		return;
 	}
-	
+
 	ip = mtod(m, struct ip *);
-	
+
 	if (ip->ip_v != IPVERSION) {
 		ipstat.ips_badvers++;
 		goto bad;
@@ -99,8 +99,8 @@
 	}
 
         /* keep ip header intact for ICMP reply
-	 * ip->ip_sum = cksum(m, hlen); 
-	 * if (ip->ip_sum) { 
+	 * ip->ip_sum = cksum(m, hlen);
+	 * if (ip->ip_sum) {
 	 */
 	if(cksum(m,hlen)) {
 	  ipstat.ips_badsum++;
@@ -154,7 +154,7 @@
 	 * (We could look in the reassembly queue to see
 	 * if the packet was previously fragmented,
 	 * but it's not worth the time; just let them time out.)
-	 * 
+	 *
 	 * XXX This should fail, don't fragment yet
 	 */
 	if (ip->ip_off &~ IP_DF) {
@@ -181,7 +181,7 @@
 		ip->ip_len -= hlen;
 		if (ip->ip_off & IP_MF)
 		  ((struct ipasfrag *)ip)->ipf_mff |= 1;
-		else 
+		else
 		  ((struct ipasfrag *)ip)->ipf_mff &= ~1;
 
 		ip->ip_off <<= 3;
@@ -244,7 +244,7 @@
 	register struct ipasfrag *q;
 	int hlen = ip->ip_hl << 2;
 	int i, next;
-	
+
 	DEBUG_CALL("ip_reass");
 	DEBUG_ARG("ip = %lx", (long)ip);
 	DEBUG_ARG("fp = %lx", (long)fp);
@@ -275,7 +275,7 @@
 	  q = (struct ipasfrag *)fp;
 	  goto insert;
 	}
-	
+
 	/*
 	 * Find a segment which begins after this one does.
 	 */
@@ -369,7 +369,7 @@
 	  ip = (struct ipasfrag *)(m->m_ext + delta);
 	}
 
-	/* DEBUG_ARG("ip = %lx", (long)ip); 
+	/* DEBUG_ARG("ip = %lx", (long)ip);
 	 * ip=(struct ipasfrag *)m->m_data; */
 
 	ip->ip_len = next;
@@ -446,9 +446,9 @@
 ip_slowtimo()
 {
 	register struct ipq *fp;
-	
+
 	DEBUG_CALL("ip_slowtimo");
-	
+
 	fp = (struct ipq *) ipq.next;
 	if (fp == 0)
 	   return;
@@ -692,6 +692,6 @@
 	i = m->m_len - (sizeof (struct ip) + olen);
 	memcpy(opts, opts  + olen, (unsigned)i);
 	m->m_len -= olen;
-	
+
 	ip->ip_hl = sizeof(struct ip) >> 2;
 }
diff --git a/slirp/ip_output.c b/slirp/ip_output.c
index f3dc9b7..b1a8484 100644
--- a/slirp/ip_output.c
+++ b/slirp/ip_output.c
@@ -65,7 +65,7 @@
 	DEBUG_CALL("ip_output");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m0 = %lx", (long)m0);
-	
+
 	/* We do no options */
 /*	if (opt) {
  *		m = ip_insertoptions(m, opt, &len);
@@ -92,7 +92,7 @@
  *		goto bad;
  *	}
  */
-	
+
 	/*
 	 * If small enough for interface, can just send directly.
 	 */
@@ -115,7 +115,7 @@
 		ipstat.ips_cantfrag++;
 		goto bad;
 	}
-	
+
 	len = (if_mtu - hlen) &~ 7;       /* ip databytes per packet */
 	if (len < 8) {
 		error = -1;
@@ -143,7 +143,7 @@
 	  m->m_data += if_maxlinkhdr;
 	  mhip = mtod(m, struct ip *);
 	  *mhip = *ip;
-		
+
 		/* No options */
 /*		if (hlen > sizeof (struct ip)) {
  *			mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip);
@@ -156,15 +156,15 @@
 	    mhip->ip_off |= IP_MF;
 	  if (off + len >= (u_int16_t)ip->ip_len)
 	    len = (u_int16_t)ip->ip_len - off;
-	  else 
+	  else
 	    mhip->ip_off |= IP_MF;
 	  mhip->ip_len = htons((u_int16_t)(len + mhlen));
-	  
+
 	  if (m_copy(m, m0, off, len) < 0) {
 	    error = -1;
 	    goto sendorfree;
 	  }
-	  
+
 	  mhip->ip_off = htons((u_int16_t)mhip->ip_off);
 	  mhip->ip_sum = 0;
 	  mhip->ip_sum = cksum(m, mhlen);
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index a9260af..639f5f2 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -1,21 +1,13 @@
 #ifndef _LIBSLIRP_H
 #define _LIBSLIRP_H
 
-#ifdef _WIN32
-#include <winsock2.h>
-int inet_aton(const char *cp, struct in_addr *ia);
-#else
-#include <sys/select.h>
-#include <arpa/inet.h>
-#endif
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
 void slirp_init(void);
 
-void slirp_select_fill(int *pnfds, 
+void slirp_select_fill(int *pnfds,
                        fd_set *readfds, fd_set *writefds, fd_set *xfds);
 
 void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds);
@@ -26,9 +18,9 @@
 int slirp_can_output(void);
 void slirp_output(const uint8_t *pkt, int pkt_len);
 
-int slirp_redir(int is_udp, int host_port, 
+int slirp_redir(int is_udp, int host_port,
                 struct in_addr guest_addr, int guest_port);
-int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, 
+int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
                    int guest_port);
 
 extern const char *tftp_prefix;
diff --git a/slirp/main.h b/slirp/main.h
index 181b6ae..9cd8758 100644
--- a/slirp/main.h
+++ b/slirp/main.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
index 3769baf..392aea8 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -40,14 +40,14 @@
 	 * Find a nice value for msize
 	 * XXX if_maxlinkhdr already in mtu
 	 */
-	msize = (if_mtu>if_mru?if_mtu:if_mru) + 
+	msize = (if_mtu>if_mru?if_mtu:if_mru) +
 			if_maxlinkhdr + sizeof(struct m_hdr ) + 6;
 }
 
 /*
  * Get an mbuf from the free list, if there are none
  * malloc one
- * 
+ *
  * Because fragmentation can occur if we alloc new mbufs and
  * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
  * which tells m_free to actually free() it
@@ -57,9 +57,9 @@
 {
 	register struct mbuf *m;
 	int flags = 0;
-	
+
 	DEBUG_CALL("m_get");
-	
+
 	if (m_freelist.m_next == &m_freelist) {
 		m = (struct mbuf *)malloc(msize);
 		if (m == NULL) goto end_error;
@@ -72,11 +72,11 @@
 		m = m_freelist.m_next;
 		remque(m);
 	}
-	
+
 	/* Insert it in the used list */
 	insque(m,&m_usedlist);
 	m->m_flags = (flags | M_USEDLIST);
-	
+
 	/* Initialise it */
 	m->m_size = msize - sizeof(struct m_hdr);
 	m->m_data = m->m_dat;
@@ -92,15 +92,15 @@
 m_free(m)
 	struct mbuf *m;
 {
-	
+
   DEBUG_CALL("m_free");
   DEBUG_ARG("m = %lx", (long )m);
-	
+
   if(m) {
 	/* Remove from m_usedlist */
 	if (m->m_flags & M_USEDLIST)
 	   remque(m);
-	
+
 	/* If it's M_EXT, free() it */
 	if (m->m_flags & M_EXT)
 	   free(m->m_ext);
@@ -132,7 +132,7 @@
 	 */
 	if (M_FREEROOM(m) < n->m_len)
 		m_inc(m,m->m_size+MINCSIZE);
-	
+
 	memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
 	m->m_len += n->m_len;
 
@@ -156,7 +156,7 @@
 	  m->m_ext = (char *)realloc(m->m_ext,size);
 /*		if (m->m_ext == NULL)
  *			return (struct mbuf *)NULL;
- */		
+ */
 	  m->m_data = m->m_ext + datasize;
         } else {
 	  char *dat;
@@ -166,12 +166,12 @@
  *			return (struct mbuf *)NULL;
  */
 	  memcpy(dat, m->m_dat, m->m_size);
-	  
+
 	  m->m_ext = dat;
 	  m->m_data = m->m_ext + datasize;
 	  m->m_flags |= M_EXT;
         }
- 
+
         m->m_size = size;
 
 }
@@ -224,7 +224,7 @@
 	void *dat;
 {
 	struct mbuf *m;
-	
+
 	DEBUG_CALL("dtom");
 	DEBUG_ARG("dat = %lx", (long )dat);
 
@@ -238,9 +238,9 @@
 	      return m;
 	  }
 	}
-	
+
 	DEBUG_ERROR((dfd, "dtom failed"));
-	
+
 	return (struct mbuf *)0;
 }
 
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index 8cc292b..1e8f7a8 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -69,12 +69,12 @@
 
 	int	mh_size;		/* Size of data */
 	struct	socket *mh_so;
-	
+
 	caddr_t	mh_data;		/* Location of data */
 	int	mh_len;			/* Amount of data in this mbuf */
 };
 
-/* 
+/*
  * How much room is in the mbuf, from m_data to the end of the mbuf
  */
 #define M_ROOM(m) ((m->m_flags & M_EXT)? \
@@ -126,7 +126,7 @@
 
 struct mbstat {
 	int mbs_alloced;		/* Number of mbufs allocated */
-	
+
 };
 
 extern struct	mbstat mbstat;
diff --git a/slirp/misc.c b/slirp/misc.c
index 2c42fd1..a41dd76 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
+ *
  * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
@@ -31,7 +31,7 @@
 		if (x_display)
 		   lprint("X Redir: Redirecting to display %d\r\n", x_display);
 	}
-	
+
 	return CFG_OK;
 }
 
@@ -47,7 +47,7 @@
 	int screen;
 {
 	int i;
-	
+
 	if (x_port >= 0) {
 		lprint("X Redir: X already being redirected.\r\n");
 		show_x(0, 0);
@@ -89,7 +89,7 @@
 {
 	char buff[256];
 	struct hostent *he = NULL;
-	
+
 	if (gethostname(buff,256) == 0)
             he = gethostbyname(buff);
         if (he)
@@ -172,13 +172,13 @@
 	int port;
 {
 	struct ex_list *tmp_ptr;
-	
+
 	/* First, check if the port is "bound" */
 	for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
 		if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr)
 		   return -1;
 	}
-	
+
 	tmp_ptr = *ex_ptr;
 	*ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
 	(*ex_ptr)->ex_fport = port;
@@ -233,7 +233,7 @@
 
 #ifdef HAVE_GRANTPT
 	char *ptr;
-	
+
 	if ((master = open("/dev/ptmx", O_RDWR)) < 0 ||
 	    grantpt(master) < 0 ||
 	    unlockpt(master) < 0 ||
@@ -241,7 +241,7 @@
 		close(master);
 		return -1;
 	}
-	
+
 	if ((slave = open(ptr, O_RDWR)) < 0 ||
 	    ioctl(slave, I_PUSH, "ptem") < 0 ||
 	    ioctl(slave, I_PUSH, "ldterm") < 0 ||
@@ -250,16 +250,16 @@
 		close(slave);
 		return -1;
 	}
-	
+
 	*amaster = master;
 	*aslave = slave;
 	return 0;
-	
+
 #else
-	
+
 	static char line[] = "/dev/ptyXX";
 	register const char *cp1, *cp2;
-	
+
 	for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
 		line[8] = *cp1;
 		for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
@@ -296,7 +296,7 @@
  * process, which connects to this socket, after which we
  * exec the wanted program.  If something (strange) happens,
  * the accept() call could block us forever.
- * 
+ *
  * do_pty = 0   Fork/exec inetd style
  * do_pty = 1   Fork/exec using slirp.telnetd
  * do_ptr = 2   Fork/exec using pty
@@ -320,12 +320,12 @@
 	char *bptr;
 	char *curarg;
 	int c, i, ret;
-	
+
 	DEBUG_CALL("fork_exec");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("ex = %lx", (long)ex);
 	DEBUG_ARG("do_pty = %lx", (long)do_pty);
-	
+
 	if (do_pty == 2) {
 		if (slirp_openpty(&master, &s) == -1) {
 			lprint("Error: openpty failed: %s\n", strerror(errno));
@@ -335,17 +335,17 @@
 		addr.sin_family = AF_INET;
 		addr.sin_port = 0;
 		addr.sin_addr.s_addr = INADDR_ANY;
-		
+
 		if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
 		    bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
 		    listen(s, 1) < 0) {
 			lprint("Error: inet socket: %s\n", strerror(errno));
 			closesocket(s);
-			
+
 			return 0;
 		}
 	}
-	
+
 	switch(fork()) {
 	 case -1:
 		lprint("Error: fork failed: %s\n", strerror(errno));
@@ -353,7 +353,7 @@
 		if (do_pty == 2)
 		   close(master);
 		return 0;
-		
+
 	 case 0:
 		/* Set the DISPLAY */
 		if (do_pty == 2) {
@@ -375,7 +375,7 @@
                             ret = connect(s, (struct sockaddr *)&addr, addrlen);
                         } while (ret < 0 && errno == EINTR);
 		}
-		
+
 #if 0
 		if (x_port >= 0) {
 #ifdef HAVE_SETENV
@@ -386,13 +386,13 @@
 			putenv(buff);
 #endif
 		}
-#endif	
+#endif
 		dup2(s, 0);
 		dup2(s, 1);
 		dup2(s, 2);
 		for (s = 3; s <= 255; s++)
 		   close(s);
-		
+
 		i = 0;
 		bptr = strdup(ex); /* No need to free() this */
 		if (do_pty == 1) {
@@ -410,21 +410,21 @@
 			*bptr++ = (char)0;
 			argv[i++] = strdup(curarg);
 		   } while (c);
-		
+
 		argv[i] = 0;
 		execvp(argv[0], argv);
-		
+
 		/* Ooops, failed, let's tell the user why */
 		  {
 			  char buff[256];
-			  
-			  sprintf(buff, "Error: execvp of %s failed: %s\n", 
+
+			  sprintf(buff, "Error: execvp of %s failed: %s\n",
 				  argv[0], strerror(errno));
 			  write(2, buff, strlen(buff)+1);
 		  }
 		close(0); close(1); close(2); /* XXX */
 		exit(1);
-		
+
 	 default:
 		if (do_pty == 2) {
 			close(s);
@@ -447,13 +447,13 @@
 			setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
 		}
 		fd_nonblock(so->s);
-		
+
 		/* Append the telnet options now */
 		if (so->so_m != 0 && do_pty == 1)  {
 			sbappend(so, so->so_m);
 			so->so_m = 0;
 		}
-		
+
 		return 1;
 	}
 }
@@ -465,10 +465,10 @@
 	const char *str;
 {
 	char *bptr;
-	
+
 	bptr = (char *)malloc(strlen(str)+1);
 	strcpy(bptr, str);
-	
+
 	return bptr;
 }
 #endif
@@ -484,7 +484,7 @@
 #endif
 	struct sockaddr_in sock_in;
 	char buff[256];
-	
+
 	ret = -1;
 	if (slirp_socket_passwd) {
 		s = socket(AF_INET, SOCK_STREAM, 0);
@@ -514,29 +514,29 @@
 #endif
 	slirp_exit(0);
 }
-	
-	
+
+
 void
 snooze()
 {
 	sigset_t s;
 	int i;
-	
+
 	/* Don't need our data anymore */
 	/* XXX This makes SunOS barf */
 /*	brk(0); */
-	
+
 	/* Close all fd's */
 	for (i = 255; i >= 0; i--)
 	   close(i);
-	
+
 	signal(SIGQUIT, slirp_exit);
 	signal(SIGHUP, snooze_hup);
 	sigemptyset(&s);
-	
+
 	/* Wait for any signal */
 	sigsuspend(&s);
-	
+
 	/* Just in case ... */
 	exit(255);
 }
@@ -549,16 +549,16 @@
 	int n;
 	fd_set readfds;
 	struct ttys *ttyp;
-	
+
 	/* Don't need our data anymore */
 	/* XXX This makes SunOS barf */
 /*	brk(0); */
-	
+
 	signal(SIGQUIT, slirp_exit);
 	signal(SIGHUP, slirp_exit);
         signal(SIGINT, slirp_exit);
 	signal(SIGTERM, slirp_exit);
-	
+
 	/* Fudge to get term_raw and term_restore to work */
 	if (NULL == (ttyp = tty_attach (0, slirp_tty))) {
          lprint ("Error: tty_attach failed in misc.c:relay()\r\n");
@@ -567,18 +567,18 @@
 	ttyp->fd = 0;
 	ttyp->flags |= TTY_CTTY;
 	term_raw(ttyp);
-	
+
 	while (1) {
 		FD_ZERO(&readfds);
-		
+
 		FD_SET(0, &readfds);
 		FD_SET(s, &readfds);
-		
+
 		n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
-		
+
 		if (n <= 0)
 		   slirp_exit(0);
-		
+
 		if (FD_ISSET(0, &readfds)) {
 			n = read(0, buf, 8192);
 			if (n <= 0)
@@ -587,7 +587,7 @@
 			if (n <= 0)
 			   slirp_exit(0);
 		}
-		
+
 		if (FD_ISSET(s, &readfds)) {
 			n = read(s, buf, 8192);
 			if (n <= 0)
@@ -597,7 +597,7 @@
 			   slirp_exit(0);
 		}
 	}
-	
+
 	/* Just in case.... */
 	exit(1);
 }
@@ -614,7 +614,7 @@
 #endif
 {
 	va_list args;
-        
+
 #ifdef __STDC__
         va_start(args, format);
 #else
@@ -631,33 +631,33 @@
 			int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data;
 			int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data;
 			int deltap = lprint_ptr -         lprint_sb->sb_data;
-			                        
+
 			lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data,
 							     lprint_sb->sb_datalen + TCP_SNDSPACE);
-			
+
 			/* Adjust all values */
 			lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw;
 			lprint_sb->sb_rptr = lprint_sb->sb_data + deltar;
 			lprint_ptr =         lprint_sb->sb_data + deltap;
-			
+
 			lprint_sb->sb_datalen += TCP_SNDSPACE;
 		}
 	}
-#endif	
+#endif
 	if (lprint_print)
 	   lprint_ptr += (*lprint_print)(*lprint_arg, format, args);
-	
+
 	/* Check if they want output to be logged to file as well */
 	if (lfd) {
-		/* 
+		/*
 		 * Remove \r's
 		 * otherwise you'll get ^M all over the file
 		 */
 		int len = strlen(format);
 		char *bptr1, *bptr2;
-		
+
 		bptr1 = bptr2 = strdup(format);
-		
+
 		while (len--) {
 			if (*bptr1 == '\r')
 			   memcpy(bptr1, bptr1+1, len+1);
@@ -680,12 +680,12 @@
 	char *buff3 = buff4;
 	struct emu_t *emup;
 	struct socket *so;
-	
+
 	if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) {
 		lprint("Error: Bad arguments\r\n");
 		return;
 	}
-	
+
 	if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) {
 		lport = 0;
 		if (sscanf(buff1, "%d", &fport) != 1) {
@@ -693,7 +693,7 @@
 			return;
 		}
 	}
-	
+
 	if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) {
 		buff3 = 0;
 		if (sscanf(buff2, "%256s", buff1) != 1) {
@@ -701,7 +701,7 @@
 			return;
 		}
 	}
-	
+
 	if (buff3) {
 		if (strcmp(buff3, "lowdelay") == 0)
 		   tos = IPTOS_LOWDELAY;
@@ -712,7 +712,7 @@
 			return;
 		}
 	}
-	
+
 	if (strcmp(buff1, "ftp") == 0)
 	   emu = EMU_FTP;
 	else if (strcmp(buff1, "irc") == 0)
@@ -723,7 +723,7 @@
 		lprint("Error: Unknown service\r\n");
 		return;
 	}
-	
+
 	/* First, check that it isn't already emulated */
 	for (emup = tcpemu; emup; emup = emup->next) {
 		if (emup->lport == lport && emup->fport == fport) {
@@ -731,7 +731,7 @@
 			return;
 		}
 	}
-	
+
 	/* link it */
 	emup = (struct emu_t *)malloc(sizeof (struct emu_t));
 	emup->lport = (u_int16_t)lport;
@@ -740,7 +740,7 @@
 	emup->emu = emu;
 	emup->next = tcpemu;
 	tcpemu = emup;
-	
+
 	/* And finally, mark all current sessions, if any, as being emulated */
 	for (so = tcb.so_next; so != &tcb; so = so->so_next) {
 		if ((lport && lport == ntohs(so->so_lport)) ||
@@ -751,7 +751,7 @@
 			   so->so_iptos = tos;
 		}
 	}
-	
+
 	lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport);
 }
 
@@ -803,12 +803,12 @@
 {
 	struct timeval t;
 	fd_set fdset;
-	
+
 	FD_ZERO(&fdset);
-	
+
 	t.tv_sec = 0;
 	t.tv_usec = usec * 1000;
-	
+
 	select(0, &fdset, &fdset, &fdset, &t);
 }
 
@@ -822,11 +822,11 @@
 {
 #ifdef FIONBIO
 	int opt = 1;
-	
+
 	ioctlsocket(fd, FIONBIO, &opt);
 #else
 	int opt;
-	
+
 	opt = fcntl(fd, F_GETFL, 0);
 	opt |= O_NONBLOCK;
 	fcntl(fd, F_SETFL, opt);
@@ -839,11 +839,11 @@
 {
 #ifdef FIONBIO
 	int opt = 0;
-	
+
 	ioctlsocket(fd, FIONBIO, &opt);
 #else
 	int opt;
-	
+
 	opt = fcntl(fd, F_GETFL, 0);
 	opt &= ~O_NONBLOCK;
 	fcntl(fd, F_SETFL, opt);
@@ -867,10 +867,10 @@
 	int fd0[2];
 	int s;
 	char buff[256];
-	
+
 	DEBUG_CALL("rsh_exec");
 	DEBUG_ARG("so = %lx", (long)so);
-	
+
 	if (pipe(fd)<0) {
           lprint("Error: pipe failed: %s\n", strerror(errno));
           return 0;
@@ -891,7 +891,7 @@
           return 0;
         }
 #endif
-	
+
 	switch(fork()) {
 	 case -1:
            lprint("Error: fork failed: %s\n", strerror(errno));
@@ -900,11 +900,11 @@
            close(fd0[0]);
            close(fd0[1]);
            return 0;
-           
+
 	 case 0:
            close(fd[0]);
            close(fd0[0]);
-           
+
 		/* Set the DISPLAY */
            if (x_port >= 0) {
 #ifdef HAVE_SETENV
@@ -915,29 +915,29 @@
              putenv(buff);
 #endif
            }
-           
+
            dup2(fd0[1], 0);
            dup2(fd0[1], 1);
            dup2(fd[1], 2);
            for (s = 3; s <= 255; s++)
              close(s);
-           
+
            execlp("rsh","rsh","-l", user, host, args, NULL);
-           
+
            /* Ooops, failed, let's tell the user why */
-           
-           sprintf(buff, "Error: execlp of %s failed: %s\n", 
+
+           sprintf(buff, "Error: execlp of %s failed: %s\n",
                    "rsh", strerror(errno));
            write(2, buff, strlen(buff)+1);
            close(0); close(1); close(2); /* XXX */
            exit(1);
-           
+
         default:
           close(fd[1]);
           close(fd0[1]);
           ns->s=fd[0];
           so->s=fd0[0];
-          
+
           return 1;
 	}
 }
diff --git a/slirp/misc.h b/slirp/misc.h
index 8e6a606..6484a81 100644
--- a/slirp/misc.h
+++ b/slirp/misc.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
diff --git a/slirp/sbuf.c b/slirp/sbuf.c
index d6726c9..209064b 100644
--- a/slirp/sbuf.c
+++ b/slirp/sbuf.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -9,7 +9,7 @@
 
 /* Done as a macro in socket.h */
 /* int
- * sbspace(struct sockbuff *sb) 
+ * sbspace(struct sockbuff *sb)
  * {
  *	return SB_DATALEN - sb->sb_cc;
  * }
@@ -25,11 +25,11 @@
 void
 sbdrop(sb, num)
 	struct sbuf *sb;
-	int num; 
+	int num;
 {
-	/* 
+	/*
 	 * We can only drop how much we have
-	 * This should never succeed 
+	 * This should never succeed
 	 */
 	if(num > sb->sb_cc)
 		num = sb->sb_cc;
@@ -37,7 +37,7 @@
 	sb->sb_rptr += num;
 	if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen)
 		sb->sb_rptr -= sb->sb_datalen;
-   
+
 }
 
 void
@@ -77,18 +77,18 @@
 	struct mbuf *m;
 {
 	int ret = 0;
-	
+
 	DEBUG_CALL("sbappend");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m = %lx", (long)m);
 	DEBUG_ARG("m->m_len = %d", m->m_len);
-	
+
 	/* Shouldn't happen, but...  e.g. foreign host closes connection */
 	if (m->m_len <= 0) {
 		m_free(m);
 		return;
 	}
-	
+
 	/*
 	 * If there is urgent data, call sosendoob
 	 * if not all was sent, sowrite will take care of the rest
@@ -100,16 +100,16 @@
 		sosendoob(so);
 		return;
 	}
-	
+
 	/*
 	 * We only write if there's nothing in the buffer,
 	 * ottherwise it'll arrive out of order, and hence corrupt
 	 */
 	if (!so->so_rcv.sb_cc)
 	   ret = send(so->s, m->m_data, m->m_len, 0);
-	
+
 	if (ret <= 0) {
-		/* 
+		/*
 		 * Nothing was written
 		 * It's possible that the socket has closed, but
 		 * we don't need to check because if it has closed,
@@ -139,7 +139,7 @@
 	 struct mbuf *m;
 {
 	int len, n,  nn;
-	
+
 	len = m->m_len;
 
 	if (sb->sb_wptr < sb->sb_rptr) {
@@ -180,7 +180,7 @@
 	char *to;
 {
 	char *from;
-	
+
 	from = sb->sb_rptr + off;
 	if (from >= sb->sb_data + sb->sb_datalen)
 		from -= sb->sb_datalen;
@@ -198,4 +198,4 @@
 		   memcpy(to+off,sb->sb_data,len);
 	}
 }
-		
+
diff --git a/slirp/sbuf.h b/slirp/sbuf.h
index 161e0bb..89c4eb2 100644
--- a/slirp/sbuf.h
+++ b/slirp/sbuf.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 6ba753e..f535db1 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -12,7 +12,7 @@
 /* virtual address alias for host */
 struct in_addr alias_addr;
 
-const uint8_t special_ethaddr[6] = { 
+const uint8_t special_ethaddr[6] = {
     0x52, 0x54, 0x00, 0x12, 0x35, 0x00
 };
 
@@ -38,10 +38,10 @@
     DWORD    ret;
     IP_ADDR_STRING *pIPAddr;
     struct in_addr tmp_addr;
-    
+
     FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
     BufLen = sizeof(FIXED_INFO);
-   
+
     if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
         if (FixedInfo) {
             GlobalFree(FixedInfo);
@@ -49,7 +49,7 @@
         }
         FixedInfo = GlobalAlloc(GPTR, BufLen);
     }
-	
+
     if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
         printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
         if (FixedInfo) {
@@ -58,14 +58,14 @@
         }
         return -1;
     }
-     
+
     pIPAddr = &(FixedInfo->DnsServerList);
     inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
     *pdns_addr = tmp_addr;
 #if 0
     printf( "DNS Servers:\n" );
     printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
-    
+
     pIPAddr = FixedInfo -> DnsServerList.Next;
     while ( pIPAddr ) {
             printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
@@ -88,7 +88,7 @@
     FILE *f;
     int found = 0;
     struct in_addr tmp_addr;
-    
+
     f = fopen("/etc/resolv.conf", "r");
     if (!f)
         return -1;
@@ -130,7 +130,7 @@
 void slirp_init(void)
 {
     //    debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
-    
+
 #ifdef _WIN32
     {
         WSADATA Data;
@@ -180,16 +180,16 @@
 static void updtime(void)
 {
 	gettimeofday(&tt, 0);
-	
+
 	curtime = (u_int)tt.tv_sec * (u_int)1000;
 	curtime += (u_int)tt.tv_usec / (u_int)1000;
-	
+
 	if ((tt.tv_usec % 1000) >= 500)
 	   curtime++;
 }
 #endif
 
-void slirp_select_fill(int *pnfds, 
+void slirp_select_fill(int *pnfds,
                        fd_set *readfds, fd_set *writefds, fd_set *xfds)
 {
     struct socket *so, *so_next;
@@ -201,36 +201,36 @@
     global_readfds = NULL;
     global_writefds = NULL;
     global_xfds = NULL;
-    
+
     nfds = *pnfds;
 	/*
 	 * First, TCP sockets
 	 */
 	do_slowtimo = 0;
 	if (link_up) {
-		/* 
+		/*
 		 * *_slowtimo needs calling if there are IP fragments
 		 * in the fragment queue, or there are TCP connections active
 		 */
 		do_slowtimo = ((tcb.so_next != &tcb) ||
 			       ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next));
-		
+
 		for (so = tcb.so_next; so != &tcb; so = so_next) {
 			so_next = so->so_next;
-			
+
 			/*
 			 * See if we need a tcp_fasttimo
 			 */
 			if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
 			   time_fasttimo = curtime; /* Flag when we want a fasttimo */
-			
+
 			/*
 			 * NOFDREF can include still connecting to local-host,
 			 * newly socreated() sockets etc. Don't want to select these.
 	 		 */
 			if (so->so_state & SS_NOFDREF || so->s == -1)
 			   continue;
-			
+
 			/*
 			 * Set for reading sockets which are accepting
 			 */
@@ -239,7 +239,7 @@
 				UPD_NFDS(so->s);
 				continue;
 			}
-			
+
 			/*
 			 * Set for writing sockets which are connecting
 			 */
@@ -248,7 +248,7 @@
 				UPD_NFDS(so->s);
 				continue;
 			}
-			
+
 			/*
 			 * Set for writing if we are connected, can send more, and
 			 * we have something to send
@@ -257,7 +257,7 @@
 				FD_SET(so->s, writefds);
 				UPD_NFDS(so->s);
 			}
-			
+
 			/*
 			 * Set for reading (and urgent data) if we are connected, can
 			 * receive more, and we have room for it XXX /2 ?
@@ -268,13 +268,13 @@
 				UPD_NFDS(so->s);
 			}
 		}
-		
+
 		/*
 		 * UDP sockets
 		 */
 		for (so = udb.so_next; so != &udb; so = so_next) {
 			so_next = so->so_next;
-			
+
 			/*
 			 * See if it's timed out
 			 */
@@ -285,7 +285,7 @@
 				} else
 					do_slowtimo = 1; /* Let socket expire */
 			}
-			
+
 			/*
 			 * When UDP packets are received from over the
 			 * link, they're sendto()'d straight away, so
@@ -302,12 +302,12 @@
 			}
 		}
 	}
-	
+
 	/*
 	 * Setup timeout to use minimum CPU usage, especially when idle
 	 */
-	
-	/* 
+
+	/*
 	 * First, see the timeout needed by *timo
 	 */
 	timeout.tv_sec = 0;
@@ -324,20 +324,20 @@
 		   timeout.tv_usec = 0;
 		else if (timeout.tv_usec > 510000)
 		   timeout.tv_usec = 510000;
-		
+
 		/* Can only fasttimo if we also slowtimo */
 		if (time_fasttimo) {
 			tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
 			if (tmp_time < 0)
 			   tmp_time = 0;
-			
+
 			/* Choose the smallest of the 2 */
 			if (tmp_time < timeout.tv_usec)
 			   timeout.tv_usec = (u_int)tmp_time;
 		}
 	}
         *pnfds = nfds;
-}	
+}
 
 void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
 {
@@ -350,9 +350,9 @@
 
 	/* Update time */
 	updtime();
-	
+
 	/*
-	 * See if anything has timed out 
+	 * See if anything has timed out
 	 */
 	if (link_up) {
 		if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
@@ -365,7 +365,7 @@
 			last_slowtimo = curtime;
 		}
 	}
-	
+
 	/*
 	 * Check sockets
 	 */
@@ -375,14 +375,14 @@
 		 */
 		for (so = tcb.so_next; so != &tcb; so = so_next) {
 			so_next = so->so_next;
-			
+
 			/*
 			 * FD_ISSET is meaningless on these sockets
 			 * (and they can crash the program)
 			 */
 			if (so->so_state & SS_NOFDREF || so->s == -1)
 			   continue;
-			
+
 			/*
 			 * Check for URG data
 			 * This will soread as well, so no need to
@@ -402,12 +402,12 @@
 					continue;
 				} /* else */
 				ret = soread(so);
-				
+
 				/* Output it if we read something */
 				if (ret > 0)
 				   tcp_output(sototcpcb(so));
 			}
-			
+
 			/*
 			 * Check sockets for writing
 			 */
@@ -418,19 +418,19 @@
 			  if (so->so_state & SS_ISFCONNECTING) {
 			    /* Connected */
 			    so->so_state &= ~SS_ISFCONNECTING;
-			    
+
 			    ret = send(so->s, &ret, 0, 0);
 			    if (ret < 0) {
 			      /* XXXXX Must fix, zero bytes is a NOP */
 			      if (errno == EAGAIN || errno == EWOULDBLOCK ||
 				  errno == EINPROGRESS || errno == ENOTCONN)
 				continue;
-			      
+
 			      /* else failed */
 			      so->so_state = SS_NOFDREF;
 			    }
 			    /* else so->so_state &= ~SS_ISFCONNECTING; */
-			    
+
 			    /*
 			     * Continue tcp_input
 			     */
@@ -439,13 +439,13 @@
 			  } else
 			    ret = sowrite(so);
 			  /*
-			   * XXXXX If we wrote something (a lot), there 
+			   * XXXXX If we wrote something (a lot), there
 			   * could be a need for a window update.
 			   * In the worst case, the remote will send
 			   * a window probe to get things going again
 			   */
 			}
-			
+
 			/*
 			 * Probe a still-connecting, non-blocking socket
 			 * to check if it's still alive
@@ -453,16 +453,16 @@
 #ifdef PROBE_CONN
 			if (so->so_state & SS_ISFCONNECTING) {
 			  ret = recv(so->s, (char *)&ret, 0,0);
-			  
+
 			  if (ret < 0) {
 			    /* XXX */
 			    if (errno == EAGAIN || errno == EWOULDBLOCK ||
 				errno == EINPROGRESS || errno == ENOTCONN)
 			      continue; /* Still connecting, continue */
-			    
+
 			    /* else failed */
 			    so->so_state = SS_NOFDREF;
-			    
+
 			    /* tcp_input will take care of it */
 			  } else {
 			    ret = send(so->s, &ret, 0,0);
@@ -475,13 +475,13 @@
 			      so->so_state = SS_NOFDREF;
 			    } else
 			      so->so_state &= ~SS_ISFCONNECTING;
-			    
+
 			  }
 			  tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
 			} /* SS_ISFCONNECTING */
 #endif
 		}
-		
+
 		/*
 		 * Now UDP sockets.
 		 * Incoming packets are sent straight away, they're not buffered.
@@ -489,13 +489,13 @@
 		 */
 		for (so = udb.so_next; so != &udb; so = so_next) {
 			so_next = so->so_next;
-			
+
 			if (so->s != -1 && FD_ISSET(so->s, readfds)) {
                             sorecvfrom(so);
                         }
 		}
 	}
-	
+
 	/*
 	 * See if we can start outputting
 	 */
@@ -521,7 +521,7 @@
 #define	ARPOP_REQUEST	1		/* ARP request			*/
 #define	ARPOP_REPLY	2		/* ARP reply			*/
 
-struct ethhdr 
+struct ethhdr
 {
 	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
 	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
@@ -559,7 +559,7 @@
     switch(ar_op) {
     case ARPOP_REQUEST:
         if (!memcmp(ah->ar_tip, &special_addr, 3)) {
-            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) 
+            if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
                 goto arp_ok;
             for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
                 if (ex_ptr->ex_addr == ah->ar_tip[3])
@@ -600,7 +600,7 @@
 
     if (pkt_len < ETH_HLEN)
         return;
-    
+
     proto = ntohs(*(uint16_t *)(pkt + 12));
     switch(proto) {
     case ETH_P_ARP:
@@ -642,24 +642,24 @@
     slirp_output(buf, ip_data_len + ETH_HLEN);
 }
 
-int slirp_redir(int is_udp, int host_port, 
+int slirp_redir(int is_udp, int host_port,
                 struct in_addr guest_addr, int guest_port)
 {
     if (is_udp) {
-        if (!udp_listen(htons(host_port), guest_addr.s_addr, 
+        if (!udp_listen(htons(host_port), guest_addr.s_addr,
                         htons(guest_port), 0))
             return -1;
     } else {
-        if (!solisten(htons(host_port), guest_addr.s_addr, 
+        if (!solisten(htons(host_port), guest_addr.s_addr,
                       htons(guest_port), 0))
             return -1;
     }
     return 0;
 }
 
-int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, 
+int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
                   int guest_port)
 {
-    return add_exec(&exec_list, do_pty, (char *)args, 
+    return add_exec(&exec_list, do_pty, (char *)args,
                     addr_low_byte, htons(guest_port));
 }
diff --git a/slirp/socket.c b/slirp/socket.c
index 0ae1f87..7e07cf8 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -29,19 +29,19 @@
 	u_int fport;
 {
 	struct socket *so;
-	
+
 	for (so = head->so_next; so != head; so = so->so_next) {
-		if (so->so_lport == lport && 
+		if (so->so_lport == lport &&
 		    so->so_laddr.s_addr == laddr.s_addr &&
 		    so->so_faddr.s_addr == faddr.s_addr &&
 		    so->so_fport == fport)
 		   break;
 	}
-	
+
 	if (so == head)
 	   return (struct socket *)NULL;
 	return so;
-	
+
 }
 
 /*
@@ -53,7 +53,7 @@
 socreate()
 {
   struct socket *so;
-	
+
   so = (struct socket *)malloc(sizeof(struct socket));
   if(so) {
     memset(so, 0, sizeof(struct socket));
@@ -78,10 +78,10 @@
     tcp_last_so = &tcb;
   else if (so == udp_last_so)
     udp_last_so = &udb;
-	
+
   m_free(so->so_m);
-	
-  if(so->so_next && so->so_prev) 
+
+  if(so->so_next && so->so_prev)
     remque(so);  /* crashes if so is not in a queue */
 
   free(so);
@@ -101,17 +101,17 @@
 	int len = sb->sb_datalen - sb->sb_cc;
 	struct iovec iov[2];
 	int mss = so->so_tcpcb->t_maxseg;
-	
+
 	DEBUG_CALL("soread");
 	DEBUG_ARG("so = %lx", (long )so);
-	
-	/* 
+
+	/*
 	 * No need to check if there's enough room to read.
 	 * soread wouldn't have been called if there weren't
 	 */
-	
+
 	len = sb->sb_datalen - sb->sb_cc;
-	
+
 	iov[0].iov_base = sb->sb_wptr;
 	if (sb->sb_wptr < sb->sb_rptr) {
 		iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
@@ -150,13 +150,13 @@
 			n = 1;
 		}
 	}
-	
+
 #ifdef HAVE_READV
 	nn = readv(so->s, (struct iovec *)iov, n);
 	DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
 #else
 	nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
-#endif	
+#endif
 	if (nn <= 0) {
 		if (nn < 0 && (errno == EINTR || errno == EAGAIN))
 			return 0;
@@ -167,7 +167,7 @@
 			return -1;
 		}
 	}
-	
+
 #ifndef HAVE_READV
 	/*
 	 * If there was no error, try and read the second time round
@@ -184,10 +184,10 @@
             if (ret > 0)
                 nn += ret;
         }
-	
+
 	DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
 #endif
-	
+
 	/* Update fields */
 	sb->sb_cc += nn;
 	sb->sb_wptr += nn;
@@ -195,10 +195,10 @@
 		sb->sb_wptr -= sb->sb_datalen;
 	return nn;
 }
-	
+
 /*
  * Get urgent data
- * 
+ *
  * When the socket is created, we set it SO_OOBINLINE,
  * so when OOB data arrives, we soread() it and everything
  * in the send buffer is sent as urgent data
@@ -211,13 +211,13 @@
 
 	DEBUG_CALL("sorecvoob");
 	DEBUG_ARG("so = %lx", (long)so);
-	
+
 	/*
 	 * We take a guess at how much urgent data has arrived.
 	 * In most situations, when urgent data arrives, the next
 	 * read() should get all the urgent data.  This guess will
 	 * be wrong however if more data arrives just after the
-	 * urgent data, or the read() doesn't return all the 
+	 * urgent data, or the read() doesn't return all the
 	 * urgent data.
 	 */
 	soread(so);
@@ -237,24 +237,24 @@
 {
 	struct sbuf *sb = &so->so_rcv;
 	char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
-	
+
 	int n, len;
-	
+
 	DEBUG_CALL("sosendoob");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
-	
+
 	if (so->so_urgc > 2048)
 	   so->so_urgc = 2048; /* XXXX */
-	
+
 	if (sb->sb_rptr < sb->sb_wptr) {
 		/* We can send it directly */
 		n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
 		so->so_urgc -= n;
-		
+
 		DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
 	} else {
-		/* 
+		/*
 		 * Since there's no sendv or sendtov like writev,
 		 * we must copy all data to a linear buffer then
 		 * send it all
@@ -274,20 +274,20 @@
 #ifdef DEBUG
 		if (n != len)
 		   DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
-#endif		
+#endif
 		DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
 	}
-	
+
 	sb->sb_cc -= n;
 	sb->sb_rptr += n;
 	if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
 		sb->sb_rptr -= sb->sb_datalen;
-	
+
 	return n;
 }
 
 /*
- * Write data from so_rcv to so's socket, 
+ * Write data from so_rcv to so's socket,
  * updating all sbuf field as necessary
  */
 int
@@ -298,10 +298,10 @@
 	struct sbuf *sb = &so->so_rcv;
 	int len = sb->sb_cc;
 	struct iovec iov[2];
-	
+
 	DEBUG_CALL("sowrite");
 	DEBUG_ARG("so = %lx", (long)so);
-	
+
 	if (so->so_urgc) {
 		sosendoob(so);
 		if (sb->sb_cc == 0)
@@ -312,9 +312,9 @@
 	 * No need to check if there's something to write,
 	 * sowrite wouldn't have been called otherwise
 	 */
-	
+
         len = sb->sb_cc;
-	
+
 	iov[0].iov_base = sb->sb_rptr;
 	if (sb->sb_rptr < sb->sb_wptr) {
 		iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
@@ -337,7 +337,7 @@
 
 #ifdef HAVE_READV
 	nn = writev(so->s, (const struct iovec *)iov, n);
-	
+
 	DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
 #else
 	nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0);
@@ -345,7 +345,7 @@
 	/* This should never happen, but people tell me it does *shrug* */
 	if (nn < 0 && (errno == EAGAIN || errno == EINTR))
 		return 0;
-	
+
 	if (nn <= 0) {
 		DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
 			so->so_state, errno));
@@ -353,7 +353,7 @@
 		tcp_sockclosed(sototcpcb(so));
 		return -1;
 	}
-	
+
 #ifndef HAVE_READV
 	if (n == 2 && nn == iov[0].iov_len) {
             int ret;
@@ -363,20 +363,20 @@
         }
         DEBUG_MISC((dfd, "  ... wrote nn = %d bytes\n", nn));
 #endif
-	
+
 	/* Update sbuf */
 	sb->sb_cc -= nn;
 	sb->sb_rptr += nn;
 	if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
 		sb->sb_rptr -= sb->sb_datalen;
-	
+
 	/*
 	 * If in DRAIN mode, and there's no more data, set
 	 * it CANTSENDMORE
 	 */
 	if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
 		sofcantsendmore(so);
-	
+
 	return nn;
 }
 
@@ -389,24 +389,24 @@
 {
 	struct sockaddr_in addr;
 	int addrlen = sizeof(struct sockaddr_in);
-	
+
 	DEBUG_CALL("sorecvfrom");
 	DEBUG_ARG("so = %lx", (long)so);
-	
+
 	if (so->so_type == IPPROTO_ICMP) {   /* This is a "ping" reply */
 	  char buff[256];
 	  int len;
-		
-	  len = recvfrom(so->s, buff, 256, 0, 
+
+	  len = recvfrom(so->s, buff, 256, 0,
 			 (struct sockaddr *)&addr, &addrlen);
 	  /* XXX Check if reply is "correct"? */
-	  
+
 	  if(len == -1 || len == 0) {
 	    u_char code=ICMP_UNREACH_PORT;
 
 	    if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
 	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
-	    
+
 	    DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
 			errno,strerror(errno)));
 	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
@@ -422,32 +422,32 @@
 
 	  if (!(m = m_get())) return;
 	  m->m_data += if_maxlinkhdr;
-		
-	  /* 
+
+	  /*
 	   * XXX Shouldn't FIONREAD packets destined for port 53,
 	   * but I don't know the max packet size for DNS lookups
 	   */
 	  len = M_FREEROOM(m);
 	  /* if (so->so_fport != htons(53)) { */
 	  ioctlsocket(so->s, FIONREAD, &n);
-	  
+
 	  if (n > len) {
 	    n = (m->m_data - m->m_dat) + m->m_len + n + 1;
 	    m_inc(m, n);
 	    len = M_FREEROOM(m);
 	  }
 	  /* } */
-		
+
 	  m->m_len = recvfrom(so->s, m->m_data, len, 0,
 			      (struct sockaddr *)&addr, &addrlen);
-	  DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", 
+	  DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
 		      m->m_len, errno,strerror(errno)));
 	  if(m->m_len<0) {
 	    u_char code=ICMP_UNREACH_PORT;
 
 	    if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
 	    else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
-	    
+
 	    DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
 	    icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
 	    m_free(m);
@@ -470,8 +470,8 @@
 	     *			m->m_len = 0;
 	     *		}
 	     */
-	    
-	    /* 
+
+	    /*
 	     * If this packet was destined for CTL_ADDR,
 	     * make it look like that's where it came from, done by udp_output
 	     */
@@ -494,7 +494,7 @@
 	DEBUG_CALL("sosendto");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m = %lx", (long)m);
-	
+
         addr.sin_family = AF_INET;
 	if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
 	  /* It's an alias */
@@ -512,13 +512,13 @@
 	addr.sin_port = so->so_fport;
 
 	DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
-	
+
 	/* Don't care what port we get */
 	ret = sendto(so->s, m->m_data, m->m_len, 0,
 		     (struct sockaddr *)&addr, sizeof (struct sockaddr));
 	if (ret < 0)
 		return -1;
-	
+
 	/*
 	 * Kill the socket if there's no reply in 4 minutes,
 	 * but only if it's an expirable socket
@@ -548,39 +548,39 @@
 	DEBUG_ARG("laddr = %x", laddr);
 	DEBUG_ARG("lport = %d", lport);
 	DEBUG_ARG("flags = %x", flags);
-	
+
 	if ((so = socreate()) == NULL) {
 	  /* free(so);      Not sofree() ??? free(NULL) == NOP */
 	  return NULL;
 	}
-	
+
 	/* Don't tcp_attach... we don't need so_snd nor so_rcv */
 	if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
 		free(so);
 		return NULL;
 	}
 	insque(so,&tcb);
-	
-	/* 
+
+	/*
 	 * SS_FACCEPTONCE sockets must time out.
 	 */
 	if (flags & SS_FACCEPTONCE)
 	   so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
-	
+
 	so->so_state = (SS_FACCEPTCONN|flags);
 	so->so_lport = lport; /* Kept in network format */
 	so->so_laddr.s_addr = laddr; /* Ditto */
-	
+
 	addr.sin_family = AF_INET;
 	addr.sin_addr.s_addr = INADDR_ANY;
 	addr.sin_port = port;
-	
+
 	if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
 	    (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
 	    (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
 	    (listen(s,1) < 0)) {
 		int tmperrno = errno; /* Don't clobber the real reason we failed */
-		
+
 		close(s);
 		sofree(so);
 		/* Restore the real errno */
@@ -592,7 +592,7 @@
 		return NULL;
 	}
 	setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
-	
+
 	getsockname(s,(struct sockaddr *)&addr,&addrlen);
 	so->so_fport = addr.sin_port;
 	if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
@@ -604,7 +604,7 @@
 	return so;
 }
 
-/* 
+/*
  * Data is available in so_rcv
  * Just write() the data to the socket
  * XXX not yet...
@@ -616,7 +616,7 @@
 /*	sowrite(so); */
 /*	FD_CLR(so->s,&writefds); */
 }
-	
+
 /*
  * Data has been freed in so_snd
  * We have room for a read() if we want to
diff --git a/slirp/socket.h b/slirp/socket.h
index d05354c..99cc17f 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -1,7 +1,7 @@
 /*
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -33,21 +33,21 @@
   struct in_addr so_laddr;	   /* local host table entry */
   u_int16_t so_fport;		   /* foreign port */
   u_int16_t so_lport;		   /* local port */
-  
+
   u_int8_t	so_iptos;	/* Type of service */
   u_int8_t	so_emu;		/* Is the socket emulated? */
-  
+
   u_char	so_type;		/* Type of socket, UDP or TCP */
   int	so_state;		/* internal state flags SS_*, below */
-  
+
   struct 	tcpcb *so_tcpcb;	/* pointer to TCP protocol control block */
   u_int	so_expire;		/* When the socket will expire */
-  
+
   int	so_queued;		/* Number of packets queued from this socket */
   int	so_nqueued;		/* Number of packets queued in a row
 				 * Used to determine when to "downgrade" a session
 					 * from fastq to batchq */
-	
+
   struct sbuf so_rcv;		/* Receive buffer */
   struct sbuf so_snd;		/* Send buffer */
   void * extra;			/* Extra pointer */
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index c015161..04f6553 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -37,8 +37,8 @@
 /*
  * Changes and additions relating to SLiRP
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -122,7 +122,7 @@
 	register struct tcpiphdr *q;
 	struct socket *so = tp->t_socket;
 	int flags;
-	
+
 	/*
 	 * Call with ti==0 after become established to
 	 * force pre-ESTABLISHED data up to user socket.
@@ -254,15 +254,15 @@
 /*	int ts_present = 0; */
 
 	DEBUG_CALL("tcp_input");
-	DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n", 
+	DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n",
 		    (long )m, iphlen, (long )inso ));
-	
+
 	/*
 	 * If called with m == 0, then we're continuing the connect
 	 */
 	if (m == NULL) {
 		so = inso;
-		
+
 		/* Re-set a few variables */
 		tp = sototcpcb(so);
 		m = so->so_m;
@@ -270,11 +270,11 @@
 		ti = so->so_ti;
 		tiwin = ti->ti_win;
 		tiflags = ti->ti_flags;
-		
+
 		goto cont_conn;
 	}
-	
-	
+
+
 	tcpstat.tcps_rcvtotal++;
 	/*
 	 * Get IP and TCP header together in first mbuf.
@@ -286,14 +286,14 @@
 	  iphlen=sizeof(struct ip );
 	}
 	/* XXX Check if too short */
-	
+
 
 	/*
 	 * Save a copy of the IP header in case we want restore it
 	 * for sending an ICMP error message in response.
 	 */
 	ip=mtod(m, struct ip *);
-	save_ip = *ip; 
+	save_ip = *ip;
 	save_ip.ip_len+= iphlen;
 
 	/*
@@ -305,7 +305,7 @@
 	ti->ti_len = htons((u_int16_t)tlen);
 	len = sizeof(struct ip ) + tlen;
 	/* keep checksum for ICMP reply
-	 * ti->ti_sum = cksum(m, len); 
+	 * ti->ti_sum = cksum(m, len);
 	 * if (ti->ti_sum) { */
 	if(cksum(m, len)) {
 	  tcpstat.tcps_rcvbadsum++;
@@ -327,7 +327,7 @@
 	  optlen = off - sizeof (struct tcphdr);
 	  optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
 
-		/* 
+		/*
 		 * Do quick retrieval of timestamp options ("options
 		 * prediction?").  If timestamp is the only option and it's
 		 * formatted as recommended in RFC 1323 appendix A, we
@@ -347,7 +347,7 @@
  */
 	}
 	tiflags = ti->ti_flags;
-	
+
 	/*
 	 * Convert TCP protocol specific fields to host format.
 	 */
@@ -361,7 +361,7 @@
 	 */
 	m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
 	m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
-	
+
 	/*
 	 * Locate pcb for segment.
 	 */
@@ -385,8 +385,8 @@
 	 * but should either do a listen or a connect soon.
 	 *
 	 * state == CLOSED means we've done socreate() but haven't
-	 * attached it to a protocol yet... 
-	 * 
+	 * attached it to a protocol yet...
+	 *
 	 * XXX If a TCB does not exist, and the TH_SYN flag is
 	 * the only flag set, then create a session, mark it
 	 * as if it was LISTENING, and continue...
@@ -394,32 +394,32 @@
 	if (so == 0) {
 	  if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
 	    goto dropwithreset;
-		
+
 	  if ((so = socreate()) == NULL)
 	    goto dropwithreset;
 	  if (tcp_attach(so) < 0) {
 	    free(so); /* Not sofree (if it failed, it's not insqued) */
 	    goto dropwithreset;
 	  }
-		
+
 	  sbreserve(&so->so_snd, tcp_sndspace);
 	  sbreserve(&so->so_rcv, tcp_rcvspace);
-	  
+
 	  /*		tcp_last_so = so; */  /* XXX ? */
 	  /*		tp = sototcpcb(so);    */
-		
+
 	  so->so_laddr = ti->ti_src;
 	  so->so_lport = ti->ti_sport;
 	  so->so_faddr = ti->ti_dst;
 	  so->so_fport = ti->ti_dport;
-		
+
 	  if ((so->so_iptos = tcp_tos(so)) == 0)
 	    so->so_iptos = ((struct ip *)ti)->ip_tos;
-		
+
 	  tp = sototcpcb(so);
 	  tp->t_state = TCPS_LISTEN;
 	}
-           
+
         /*
          * If this is a still-connecting socket, this probably
          * a retransmit of the SYN.  Whether it's a retransmit SYN
@@ -429,13 +429,13 @@
                 goto drop;
 
 	tp = sototcpcb(so);
-	
+
 	/* XXX Should never fail */
 	if (tp == 0)
 		goto dropwithreset;
 	if (tp->t_state == TCPS_CLOSED)
 		goto drop;
-	
+
 	/* Unscale the window into a 32-bit value. */
 /*	if ((tiflags & TH_SYN) == 0)
  *		tiwin = ti->ti_win << tp->snd_scale;
@@ -458,11 +458,11 @@
 	 * else do it below (after getting remote address).
 	 */
 	if (optp && tp->t_state != TCPS_LISTEN)
-		tcp_dooptions(tp, (u_char *)optp, optlen, ti); 
+		tcp_dooptions(tp, (u_char *)optp, optlen, ti);
 /* , */
 /*			&ts_present, &ts_val, &ts_ecr); */
 
-	/* 
+	/*
 	 * Header prediction: check for the two common cases
 	 * of a uni-directional data xfer.  If the packet has
 	 * no control flags, is in-sequence, the window didn't
@@ -486,7 +486,7 @@
 	    ti->ti_seq == tp->rcv_nxt &&
 	    tiwin && tiwin == tp->snd_wnd &&
 	    tp->snd_nxt == tp->snd_max) {
-		/* 
+		/*
 		 * If last ACK falls within this segment's sequence numbers,
 		 *  record the timestamp.
 		 */
@@ -506,7 +506,7 @@
 				++tcpstat.tcps_predack;
 /*				if (ts_present)
  *					tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
- *				else 
+ *				else
  */				     if (tp->t_rtt &&
 					    SEQ_GT(ti->ti_ack, tp->t_rtseq))
 					tcp_xmit_timer(tp, tp->t_rtt);
@@ -531,14 +531,14 @@
 				else if (tp->t_timer[TCPT_PERSIST] == 0)
 					tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
 
-				/* 
+				/*
 				 * There's room in so_snd, sowwakup will read()
 				 * from the socket if we can
 				 */
 /*				if (so->so_snd.sb_flags & SB_NOTIFY)
  *					sowwakeup(so);
  */
-				/* 
+				/*
 				 * This is called because sowwakeup might have
 				 * put data into so_snd.  Since we don't so sowwakeup,
 				 * we don't need this.. XXX???
@@ -567,22 +567,22 @@
 				if (tcp_emu(so,m)) sbappend(so, m);
 			} else
 				sbappend(so, m);
-			
-			/* 
+
+			/*
 			 * XXX This is called when data arrives.  Later, check
 			 * if we can actually write() to the socket
 			 * XXX Need to check? It's be NON_BLOCKING
 			 */
 /*			sorwakeup(so); */
-			
+
 			/*
 			 * If this is a short packet, then ACK now - with Nagel
 			 *	congestion avoidance sender won't send more until
 			 *	he gets an ACK.
-			 * 
+			 *
 			 * It is better to not delay acks at all to maximize
 			 * TCP throughput.  See RFC 2581.
-			 */ 
+			 */
 			tp->t_flags |= TF_ACKNOW;
 			tcp_output(tp);
 			return;
@@ -624,12 +624,12 @@
 	    goto dropwithreset;
 	  if ((tiflags & TH_SYN) == 0)
 	    goto drop;
-		
+
 	  /*
 	   * This has way too many gotos...
 	   * But a bit of spaghetti code never hurt anybody :)
 	   */
-	  
+
 	  /*
 	   * If this is destined for the control address, then flag to
 	   * tcp_ctl once connected, otherwise connect
@@ -641,13 +641,13 @@
 	      if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) {
 		/* Command or exec adress */
 		so->so_state |= SS_CTL;
-	      } else 
+	      } else
 #endif
               {
 		/* May be an add exec */
 		struct ex_list *ex_ptr;
 		for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
-		  if(ex_ptr->ex_fport == so->so_fport && 
+		  if(ex_ptr->ex_fport == so->so_fport &&
 		     lastbyte == ex_ptr->ex_addr) {
 		    so->so_state |= SS_CTL;
 		    break;
@@ -658,12 +658,12 @@
 	    }
 	    /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
 	  }
-	  
+
 	  if (so->so_emu & EMU_NOCONNECT) {
 	    so->so_emu &= ~EMU_NOCONNECT;
 	    goto cont_input;
 	  }
-	  
+
 	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
 	    u_char code=ICMP_UNREACH_NET;
 	    DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
@@ -671,7 +671,7 @@
 	    if(errno == ECONNREFUSED) {
 	      /* ACK the SYN, send RST to refuse the connection */
 	      tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,
-			  TH_RST|TH_ACK); 
+			  TH_RST|TH_ACK);
 	    } else {
 	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
 	      HTONL(ti->ti_seq);             /* restore tcp header */
@@ -699,25 +699,25 @@
 	  }
 	  return;
 
-	cont_conn:     
-	  /* m==NULL 
+	cont_conn:
+	  /* m==NULL
 	   * Check if the connect succeeded
 	   */
 	  if (so->so_state & SS_NOFDREF) {
 	    tp = tcp_close(tp);
 	    goto dropwithreset;
 	  }
-	cont_input:		
+	cont_input:
 	  tcp_template(tp);
-	  
+
 	  if (optp)
 	    tcp_dooptions(tp, (u_char *)optp, optlen, ti);
 	  /* , */
 	  /*				&ts_present, &ts_val, &ts_ecr); */
-	  
+
 	  if (iss)
 	    tp->iss = iss;
-	  else 
+	  else
 	    tp->iss = tcp_iss;
 	  tcp_iss += TCP_ISSINCR/2;
 	  tp->irs = ti->ti_seq;
@@ -729,7 +729,7 @@
 	  tcpstat.tcps_accepts++;
 	  goto trimthenstep6;
 	} /* case TCPS_LISTEN */
-	
+
 	/*
 	 * If the state is SYN_SENT:
 	 *	if seg contains an ACK, but not for our SYN, drop the input.
@@ -770,7 +770,7 @@
 			tcpstat.tcps_connects++;
 			soisfconnected(so);
 			tp->t_state = TCPS_ESTABLISHED;
-			
+
 			/* Do window scaling on this connection? */
 /*			if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
  *				(TF_RCVD_SCALE|TF_REQ_SCALE)) {
@@ -811,10 +811,10 @@
 	/*
 	 * States other than LISTEN or SYN_SENT.
 	 * First check timestamp, if present.
-	 * Then check that at least some bytes of segment are within 
+	 * Then check that at least some bytes of segment are within
 	 * receive window.  If segment begins before rcv_nxt,
 	 * drop leading data (and SYN); if nothing left, just ack.
-	 * 
+	 *
 	 * RFC 1323 PAWS: If we have a timestamp reply on this segment
 	 * and it's less than ts_recent, drop it.
 	 */
@@ -849,7 +849,7 @@
 		if (tiflags & TH_SYN) {
 			tiflags &= ~TH_SYN;
 			ti->ti_seq++;
-			if (ti->ti_urp > 1) 
+			if (ti->ti_urp > 1)
 				ti->ti_urp--;
 			else
 				tiflags &= ~TH_URG;
@@ -866,7 +866,7 @@
 			 * of sequence; drop it.
 			 */
 			tiflags &= ~TH_FIN;
-			
+
 			/*
 			 * Send an ACK to resynchronize and drop any data.
 			 * But keep on processing for RST or ACK.
@@ -1017,12 +1017,12 @@
 			goto dropwithreset;
 		tcpstat.tcps_connects++;
 		tp->t_state = TCPS_ESTABLISHED;
-		/* 
-		 * The sent SYN is ack'ed with our sequence number +1 
-		 * The first data byte already in the buffer will get 
+		/*
+		 * The sent SYN is ack'ed with our sequence number +1
+		 * The first data byte already in the buffer will get
 		 * lost if no correction is made.  This is only needed for
 		 * SS_CTL since the buffer is empty otherwise.
-		 * tp->snd_una++; or:     
+		 * tp->snd_una++; or:
 		 */
 		tp->snd_una=ti->ti_ack;
 		if (so->so_state & SS_CTL) {
@@ -1040,7 +1040,7 @@
 		} else {
 		  soisfconnected(so);
 		}
-		
+
 		/* Do window scaling? */
 /*		if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
  *			(TF_RCVD_SCALE|TF_REQ_SCALE)) {
@@ -1094,7 +1094,7 @@
 				 * the new ssthresh).
 				 *
 				 * Dup acks mean that packets have left the
-				 * network (they're now cached at the receiver) 
+				 * network (they're now cached at the receiver)
 				 * so bump cwnd by the amount in the receiver
 				 * to keep a constant cwnd packets in the
 				 * network.
@@ -1159,7 +1159,7 @@
 /*		if (ts_present)
  *			tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
  *		else
- */		     
+ */
 		     if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
 			tcp_xmit_timer(tp,tp->t_rtt);
 
@@ -1200,7 +1200,7 @@
 		}
 		/*
 		 * XXX sowwakup is called when data is acked and there's room for
-		 * for more data... it should read() the socket 
+		 * for more data... it should read() the socket
 		 */
 /*		if (so->so_snd.sb_flags & SB_NOTIFY)
  *			sowwakeup(so);
@@ -1278,7 +1278,7 @@
 	 * Don't look at window if no ACK: TAC's send garbage on first SYN.
 	 */
 	if ((tiflags & TH_ACK) &&
-	    (SEQ_LT(tp->snd_wl1, ti->ti_seq) || 
+	    (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
 	    (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
 	    (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
 		/* keep track of pure window updates */
@@ -1313,14 +1313,14 @@
 		 * If this segment advances the known urgent pointer,
 		 * then mark the data stream.  This should not happen
 		 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
-		 * a FIN has been received from the remote side. 
+		 * a FIN has been received from the remote side.
 		 * In these states we ignore the URG.
 		 *
 		 * According to RFC961 (Assigned Protocols),
 		 * the urgent pointer points to the last octet
 		 * of urgent data.  We continue, however,
 		 * to consider it to indicate the first octet
-		 * of data past the urgent section as the original 
+		 * of data past the urgent section as the original
 		 * spec states (in one of two places).
 		 */
 		if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
@@ -1328,7 +1328,7 @@
 			so->so_urgc =  so->so_rcv.sb_cc +
 				(tp->rcv_up - tp->rcv_nxt); /* -1; */
 			tp->rcv_up = ti->ti_seq + ti->ti_urp;
-	 
+
 		}
 	} else
 		/*
@@ -1379,7 +1379,7 @@
 			 */
 /*			sofcantrcvmore(so); */
 			sofwdrain(so);
-			
+
 			tp->t_flags |= TF_ACKNOW;
 			tp->rcv_nxt++;
 		}
@@ -1393,7 +1393,7 @@
 		case TCPS_ESTABLISHED:
 		  if(so->so_emu == EMU_CTL)        /* no shutdown on socket */
 		    tp->t_state = TCPS_LAST_ACK;
-		  else 
+		  else
 		    tp->t_state = TCPS_CLOSE_WAIT;
 		  break;
 
@@ -1407,7 +1407,7 @@
 
 	 	/*
 		 * In FIN_WAIT_2 state enter the TIME_WAIT state,
-		 * starting the time-wait timer, turning off the other 
+		 * starting the time-wait timer, turning off the other
 		 * standard timers.
 		 */
 		case TCPS_FIN_WAIT_2:
@@ -1430,7 +1430,7 @@
 	 * If this is a small packet, then ACK now - with Nagel
 	 *      congestion avoidance sender won't send more until
 	 *      he gets an ACK.
-	 * 
+	 *
 	 * See above.
 	 */
 /*	if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) {
@@ -1547,7 +1547,7 @@
  *			memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr));
  *			NTOHL(*ts_ecr);
  *
- */			/* 
+ */			/*
  *			 * A timestamp received in a SYN makes
  *			 * it ok to send timestamp requests and replies.
  *			 */
@@ -1578,7 +1578,7 @@
 	register struct mbuf *m;
 {
 	int cnt = ti->ti_urp - 1;
-	
+
 	while (cnt >= 0) {
 		if (m->m_len > cnt) {
 			char *cp = mtod(m, caddr_t) + cnt;
@@ -1615,7 +1615,7 @@
 	DEBUG_CALL("tcp_xmit_timer");
 	DEBUG_ARG("tp = %lx", (long)tp);
 	DEBUG_ARG("rtt = %d", rtt);
-	
+
 	tcpstat.tcps_rttupdated++;
 	if (tp->t_srtt != 0) {
 		/*
@@ -1644,7 +1644,7 @@
 		if ((tp->t_rttvar += delta) <= 0)
 			tp->t_rttvar = 1;
 	} else {
-		/* 
+		/*
 		 * No rtt measurement yet - use the unsmoothed rtt.
 		 * Set the variance to half the rtt (so our first
 		 * retransmit happens at 3*rtt).
@@ -1668,7 +1668,7 @@
 	 */
 	TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
 	    (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
-	
+
 	/*
 	 * We received an ack for a packet that wasn't retransmitted;
 	 * it is probably safe to discard any error indications we've
@@ -1702,24 +1702,24 @@
 {
 	struct socket *so = tp->t_socket;
 	int mss;
-	
+
 	DEBUG_CALL("tcp_mss");
 	DEBUG_ARG("tp = %lx", (long)tp);
 	DEBUG_ARG("offer = %d", offer);
-	
+
 	mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr);
 	if (offer)
 		mss = min(mss, offer);
 	mss = max(mss, 32);
 	if (mss < tp->t_maxseg || offer != 0)
 	   tp->t_maxseg = mss;
-	
+
 	tp->snd_cwnd = mss;
-	
+
 	sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0));
 	sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0));
-	
+
 	DEBUG_MISC((dfd, " returning mss = %d\n", mss));
-	
+
 	return mss;
 }
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index b79bcf1..3eddfd3 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -37,8 +37,8 @@
 /*
  * Changes and additions relating to SLiRP
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -57,7 +57,7 @@
 
 u_char  tcp_outflags[TCP_NSTATES] = {
 	TH_RST|TH_ACK, 0,      TH_SYN,        TH_SYN|TH_ACK,
-	TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, 
+	TH_ACK,        TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK,
 	TH_FIN|TH_ACK, TH_ACK, TH_ACK,
 };
 
@@ -79,10 +79,10 @@
 	u_char opt[MAX_TCPOPTLEN];
 	unsigned optlen, hdrlen;
 	int idle, sendalot;
-	
+
 	DEBUG_CALL("tcp_output");
 	DEBUG_ARG("tp = %lx", (long )tp);
-	
+
 	/*
 	 * Determine length of data that should be transmitted,
 	 * and flags that will be used.
@@ -103,9 +103,9 @@
 	win = min(tp->snd_wnd, tp->snd_cwnd);
 
 	flags = tcp_outflags[tp->t_state];
-	
+
 	DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags));
-	
+
 	/*
 	 * If in persist timeout with window of 0, send 1 byte.
 	 * Otherwise, if window is small but nonzero
@@ -158,7 +158,7 @@
 			tp->snd_nxt = tp->snd_una;
 		}
 	}
-	
+
 	if (len > tp->t_maxseg) {
 		len = tp->t_maxseg;
 		sendalot = 1;
@@ -200,7 +200,7 @@
 	 * window, then want to send a window update to peer.
 	 */
 	if (win > 0) {
-		/* 
+		/*
 		 * "adv" is the amount we can increase the window,
 		 * taking into account that we are limited by
 		 * TCP_MAXWIN << tp->rcv_scale.
@@ -264,7 +264,7 @@
 	 * No reason to send a segment, just return.
 	 */
 	tcpstat.tcps_didnuttin++;
-	
+
 	return (0);
 
 send:
@@ -302,9 +302,9 @@
  */
 		}
  	}
- 
+
  	/*
-	 * Send a timestamp and echo-reply if this is a SYN and our side 
+	 * Send a timestamp and echo-reply if this is a SYN and our side
 	 * wants to use timestamps (TF_REQ_TSTMP is set) or both our side
 	 * and our peer have sent timestamps in our SYN's.
  	 */
@@ -322,7 +322,7 @@
  *	}
  */
  	hdrlen += optlen;
- 
+
 	/*
 	 * Adjust data length if insertion of options will
 	 * bump the packet length beyond the t_maxseg length.
@@ -356,8 +356,8 @@
 		}
 		m->m_data += if_maxlinkhdr;
 		m->m_len = hdrlen;
-		
-		/* 
+
+		/*
 		 * This will always succeed, since we make sure our mbufs
 		 * are big enough to hold one MSS packet + header + ... etc.
 		 */
@@ -401,7 +401,7 @@
 	}
 
 	ti = mtod(m, struct tcpiphdr *);
-	
+
 	memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr));
 
 	/*
@@ -409,7 +409,7 @@
 	 * window for use in delaying messages about window sizes.
 	 * If resending a FIN, be sure not to use a new sequence number.
 	 */
-	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && 
+	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
 	    tp->snd_nxt == tp->snd_max)
 		tp->snd_nxt--;
 	/*
@@ -446,10 +446,10 @@
 	if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
 		win = (long)(tp->rcv_adv - tp->rcv_nxt);
 	ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale));
-	
+
 	if (SEQ_GT(tp->snd_up, tp->snd_una)) {
 		ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq)));
-#ifdef notdef		
+#ifdef notdef
 	if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
 		ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt));
 #endif
@@ -531,14 +531,14 @@
 	 * the template, but need a way to checksum without them.
 	 */
 	m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
-	
+
     {
-	    
+
 	((struct ip *)ti)->ip_len = m->m_len;
 
 	((struct ip *)ti)->ip_ttl = ip_defttl;
 	((struct ip *)ti)->ip_tos = so->so_iptos;
-	    
+
 /* #if BSD >= 43 */
 	/* Don't do IP options... */
 /*	error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
@@ -547,7 +547,7 @@
 	error = ip_output(so, m);
 
 /* #else
- *	error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, 
+ *	error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route,
  *	    so->so_options & SO_DONTROUTE);
  * #endif
  */
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index 2526bff..3814ec1 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -37,8 +37,8 @@
 /*
  * Changes and additions relating to SLiRP
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -60,11 +60,11 @@
 {
 	tcp_iss = 1;		/* wrong */
 	tcb.so_next = tcb.so_prev = &tcb;
-	
+
 	/* tcp_rcvspace = our Window we advertise to the remote */
 	tcp_rcvspace = TCP_RCVSPACE;
 	tcp_sndspace = TCP_SNDSPACE;
-	
+
 	/* Make sure tcp_sndspace is at least 2*MSS */
 	if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)))
 		tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr));
@@ -92,7 +92,7 @@
 	n->ti_dst = so->so_laddr;
 	n->ti_sport = so->so_fport;
 	n->ti_dport = so->so_lport;
-	
+
 	n->ti_seq = 0;
 	n->ti_ack = 0;
 	n->ti_x2 = 0;
@@ -134,7 +134,7 @@
 	DEBUG_ARG("ack = %u", ack);
 	DEBUG_ARG("seq = %u", seq);
 	DEBUG_ARG("flags = %x", flags);
-	
+
 	if (tp)
 		win = sbspace(&tp->t_socket->so_rcv);
 	if (m == 0) {
@@ -150,12 +150,12 @@
 		ti = mtod(m, struct tcpiphdr *);
 		flags = TH_ACK;
 	} else {
-		/* 
+		/*
 		 * ti points into m so the next line is just making
 		 * the mbuf point to ti
 		 */
 		m->m_data = (caddr_t)ti;
-		
+
 		m->m_len = sizeof (struct tcpiphdr);
 		tlen = 0;
 #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
@@ -183,11 +183,11 @@
 	ti->ti_sum = cksum(m, tlen);
 	((struct ip *)ti)->ip_len = tlen;
 
-	if(flags & TH_RST) 
+	if(flags & TH_RST)
 	  ((struct ip *)ti)->ip_ttl = MAXTTL;
-	else 
+	else
 	  ((struct ip *)ti)->ip_ttl = ip_defttl;
-	
+
 	(void) ip_output((struct socket *)0, m);
 }
 
@@ -201,18 +201,18 @@
 	struct socket *so;
 {
 	register struct tcpcb *tp;
-	
+
 	tp = (struct tcpcb *)malloc(sizeof(*tp));
 	if (tp == NULL)
 		return ((struct tcpcb *)0);
-	
+
 	memset((char *) tp, 0, sizeof(struct tcpcb));
 	tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp;
 	tp->t_maxseg = tcp_mssdflt;
-	
+
 	tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
 	tp->t_socket = so;
-	
+
 	/*
 	 * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
 	 * rtt estimate.  Set rttvar so that srtt + 2 * rttvar gives
@@ -222,14 +222,14 @@
 	tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
 	tp->t_rttmin = TCPTV_MIN;
 
-	TCPT_RANGESET(tp->t_rxtcur, 
+	TCPT_RANGESET(tp->t_rxtcur,
 	    ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
 	    TCPTV_MIN, TCPTV_REXMTMAX);
 
 	tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
 	tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
 	tp->t_state = TCPS_CLOSED;
-	
+
 	so->so_tcpcb = tp;
 
 	return (tp);
@@ -240,7 +240,7 @@
  * the specified error.  If connection is synchronized,
  * then send a RST to peer.
  */
-struct tcpcb *tcp_drop(struct tcpcb *tp, int err) 
+struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
 {
 /* tcp_drop(tp, errno)
 	register struct tcpcb *tp;
@@ -251,7 +251,7 @@
 	DEBUG_CALL("tcp_drop");
 	DEBUG_ARG("tp = %lx", (long)tp);
 	DEBUG_ARG("errno = %d", errno);
-	
+
 	if (TCPS_HAVERCVDSYN(tp->t_state)) {
 		tp->t_state = TCPS_CLOSED;
 		(void) tcp_output(tp);
@@ -281,7 +281,7 @@
 
 	DEBUG_CALL("tcp_close");
 	DEBUG_ARG("tp = %lx", (long )tp);
-	
+
 	/* free the reassembly queue, if any */
 	t = (struct tcpiphdr *) tp->seg_next;
 	while (t != (struct tcpiphdr *)tp) {
@@ -356,7 +356,7 @@
 
 	DEBUG_CALL("tcp_sockclosed");
 	DEBUG_ARG("tp = %lx", (long)tp);
-	
+
 	switch (tp->t_state) {
 
 	case TCPS_CLOSED:
@@ -382,21 +382,21 @@
 		tcp_output(tp);
 }
 
-/* 
+/*
  * Connect to a host on the Internet
  * Called by tcp_input
  * Only do a connect, the tcp fields will be set in tcp_input
  * return 0 if there's a result of the connect,
  * else return -1 means we're still connecting
  * The return value is almost always -1 since the socket is
- * nonblocking.  Connect returns after the SYN is sent, and does 
+ * nonblocking.  Connect returns after the SYN is sent, and does
  * not wait for ACK+SYN.
  */
 int tcp_fconnect(so)
      struct socket *so;
 {
   int ret=0;
-  
+
   DEBUG_CALL("tcp_fconnect");
   DEBUG_ARG("so = %lx", (long )so);
 
@@ -409,7 +409,7 @@
     setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
     opt = 1;
     setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
-    
+
     addr.sin_family = AF_INET;
     if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
       /* It's an alias */
@@ -425,13 +425,13 @@
     } else
       addr.sin_addr = so->so_faddr;
     addr.sin_port = so->so_fport;
-    
+
     DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
-		"addr.sin_addr.s_addr=%.16s\n", 
+		"addr.sin_addr.s_addr=%.16s\n",
 		ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
     /* We don't care what port we get */
     ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
-    
+
     /*
      * If it's not in progress, it failed, so we just return 0,
      * without clearing SS_NOFDREF
@@ -444,16 +444,16 @@
 
 /*
  * Accept the socket and connect to the local-host
- * 
+ *
  * We have a problem. The correct thing to do would be
  * to first connect to the local-host, and only if the
  * connection is accepted, then do an accept() here.
- * But, a) we need to know who's trying to connect 
+ * But, a) we need to know who's trying to connect
  * to the socket to be able to SYN the local-host, and
  * b) we are already connected to the foreign host by
  * the time it gets to accept(), so... We simply accept
  * here and SYN the local-host.
- */ 
+ */
 void
 tcp_connect(inso)
 	struct socket *inso;
@@ -466,7 +466,7 @@
 
 	DEBUG_CALL("tcp_connect");
 	DEBUG_ARG("inso = %lx", (long)inso);
-	
+
 	/*
 	 * If it's an SS_ACCEPTONCE socket, no need to socreate()
 	 * another socket, just use the accept() socket.
@@ -487,7 +487,7 @@
 		so->so_laddr = inso->so_laddr;
 		so->so_lport = inso->so_lport;
 	}
-	
+
 	(void) tcp_mss(sototcpcb(so), 0);
 
 	if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
@@ -501,13 +501,13 @@
 	setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
 	opt = 1;
 	setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int));
-	
+
 	so->so_fport = addr.sin_port;
 	so->so_faddr = addr.sin_addr;
 	/* Translate connections from localhost to the real hostname */
 	if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
 	   so->so_faddr = alias_addr;
-	
+
 	/* Close the accept() socket, set right state */
 	if (inso->so_state & SS_FACCEPTONCE) {
 		closesocket(so->s); /* If we only accept once, close the accept() socket */
@@ -515,12 +515,12 @@
 					   /* if it's not FACCEPTONCE, it's already NOFDREF */
 	}
 	so->s = s;
-	
+
 	so->so_iptos = tcp_tos(so);
 	tp = sototcpcb(so);
 
 	tcp_template(tp);
-	
+
 	/* Compute window scaling to request.  */
 /*	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
  *		(TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
@@ -529,10 +529,10 @@
 
 /*	soisconnecting(so); */ /* NOFDREF used instead */
 	tcpstat.tcps_connattempt++;
-	
+
 	tp->t_state = TCPS_SYN_SENT;
 	tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
-	tp->iss = tcp_iss; 
+	tp->iss = tcp_iss;
 	tcp_iss += TCP_ISSINCR/2;
 	tcp_sendseqinit(tp);
 	tcp_output(tp);
@@ -547,7 +547,7 @@
 {
 	if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
 	   return -1;
-	
+
 	insque(so, &tcb);
 
 	return 0;
@@ -573,7 +573,7 @@
 };
 
 struct emu_t *tcpemu = 0;
-		
+
 /*
  * Return TOS according to the above table
  */
@@ -583,7 +583,7 @@
 {
 	int i = 0;
 	struct emu_t *emup;
-	
+
 	while(tcptos[i].tos) {
 		if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
 		    (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
@@ -592,7 +592,7 @@
 		}
 		i++;
 	}
-	
+
 	/* Nope, lets see if there's a user-added one */
 	for (emup = tcpemu; emup; emup = emup->next) {
 		if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
@@ -601,7 +601,7 @@
 			return emup->tos;
 		}
 	}
-	
+
 	return 0;
 }
 
@@ -612,23 +612,23 @@
  * This includes ftp (the data connection is
  * initiated by the server) and IRC (DCC CHAT and
  * DCC SEND) for now
- * 
+ *
  * NOTE: It's possible to crash SLiRP by sending it
  * unstandard strings to emulate... if this is a problem,
  * more checks are needed here
  *
  * XXX Assumes the whole command came in one packet
- *					    
+ *
  * XXX Some ftp clients will have their TOS set to
  * LOWDELAY and so Nagel will kick in.  Because of this,
  * we'll get the first letter, followed by the rest, so
  * we simply scan for ORT instead of PORT...
  * DCC doesn't have this problem because there's other stuff
  * in the packet before the DCC command.
- * 
- * Return 1 if the mbuf m is still valid and should be 
+ *
+ * Return 1 if the mbuf m is still valid and should be
  * sbappend()ed
- * 
+ *
  * NOTE: if you return 0 you MUST m_free() the mbuf!
  */
 int
@@ -641,25 +641,25 @@
 	u_int32_t laddr;
 	u_int lport;
 	char *bptr;
-	
+
 	DEBUG_CALL("tcp_emu");
 	DEBUG_ARG("so = %lx", (long)so);
 	DEBUG_ARG("m = %lx", (long)m);
-	
+
 	switch(so->so_emu) {
 		int x, i;
-		
+
 	 case EMU_IDENT:
 		/*
 		 * Identification protocol as per rfc-1413
 		 */
-		
+
 		{
 			struct socket *tmpso;
 			struct sockaddr_in addr;
 			int addrlen = sizeof(struct sockaddr_in);
 			struct sbuf *so_rcv = &so->so_rcv;
-			
+
 			memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
 			so_rcv->sb_wptr += m->m_len;
 			so_rcv->sb_rptr += m->m_len;
@@ -688,7 +688,7 @@
 			m_free(m);
 			return 0;
 		}
-		
+
 #if 0
 	 case EMU_RLOGIN:
 		/*
@@ -703,7 +703,7 @@
 			char term[100];
 			struct sbuf *so_snd = &so->so_snd;
 			struct sbuf *so_rcv = &so->so_rcv;
-			
+
 			/* First check if they have a priveladged port, or too much data has arrived */
 			if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
 			    (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
@@ -714,13 +714,13 @@
 				m_free(m);
 				return 0;
 			}
-			
+
 			/* Append the current data */
 			memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
 			so_rcv->sb_wptr += m->m_len;
 			so_rcv->sb_rptr += m->m_len;
 			m_free(m);
-			
+
 			/*
 			 * Check if we have all the initial options,
 			 * and build argument list to rlogin while we're here
@@ -752,10 +752,10 @@
 					}
 				}
 			}
-			
+
 			if (n != 4)
 			   return 0;
-			
+
 			/* We have it, set our term variable and fork_exec() */
 #ifdef HAVE_SETENV
 			setenv("TERM", term, 1);
@@ -765,15 +765,15 @@
 			fork_exec(so, args, 2);
 			term[0] = 0;
 			so->so_emu = 0;
-			
+
 			/* And finally, send the client a 0 character */
 			so_snd->sb_wptr[0] = 0;
 			so_snd->sb_wptr++;
 			so_snd->sb_cc++;
-			
+
 			return 0;
 		}
-		
+
 	 case EMU_RSH:
 		/*
 		 * rsh emulation
@@ -787,7 +787,7 @@
 			char *args;
 			struct sbuf *so_snd = &so->so_snd;
 			struct sbuf *so_rcv = &so->so_rcv;
-			
+
 			/* First check if they have a priveladged port, or too much data has arrived */
 			if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
 			    (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
@@ -798,13 +798,13 @@
 				m_free(m);
 				return 0;
 			}
-			
+
 			/* Append the current data */
 			memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
 			so_rcv->sb_wptr += m->m_len;
 			so_rcv->sb_rptr += m->m_len;
 			m_free(m);
-			
+
 			/*
 			 * Check if we have all the initial options,
 			 * and build argument list to rlogin while we're here
@@ -840,15 +840,15 @@
 				ns->so_faddr=so->so_faddr;
 				ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */
 
-				if (ns->so_faddr.s_addr == 0 || 
+				if (ns->so_faddr.s_addr == 0 ||
 					ns->so_faddr.s_addr == loopback_addr.s_addr)
                   ns->so_faddr = alias_addr;
 
 				ns->so_iptos = tcp_tos(ns);
 				tp = sototcpcb(ns);
-                
+
 				tcp_template(tp);
-                
+
 				/* Compute window scaling to request.  */
 				/*	while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
 				 *		(TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
@@ -858,10 +858,10 @@
                 /*soisfconnecting(ns);*/
 
 				tcpstat.tcps_connattempt++;
-					
+
 				tp->t_state = TCPS_SYN_SENT;
 				tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
-				tp->iss = tcp_iss; 
+				tp->iss = tcp_iss;
 				tcp_iss += TCP_ISSINCR/2;
 				tcp_sendseqinit(tp);
 				tcp_output(tp);
@@ -877,19 +877,19 @@
                 }
               }
 			}
-			
+
 			if (n != 4)
               return 0;
-			
+
 			rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args);
 			so->so_emu = 0;
 			so->extra=NULL;
-			
+
 			/* And finally, send the client a 0 character */
 			so_snd->sb_wptr[0] = 0;
 			so_snd->sb_wptr++;
 			so_snd->sb_cc++;
-			
+
 			return 0;
 		}
 
@@ -898,7 +898,7 @@
 			int num;
 			struct sbuf *so_snd = &so->so_snd;
 			struct sbuf *so_rcv = &so->so_rcv;
-			
+
 			/*
 			 * If there is binary data here, we save it in so->so_m
 			 */
@@ -913,16 +913,16 @@
 			    }
 			  }
 			} /* if(so->so_m==NULL) */
-			
+
 			/*
 			 * Append the line
 			 */
 			sbappendsb(so_rcv, m);
-			
+
 			/* To avoid going over the edge of the buffer, we reset it */
 			if (so_snd->sb_cc == 0)
 			   so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data;
-			
+
 			/*
 			 * A bit of a hack:
 			 * If the first packet we get here is 1 byte long, then it
@@ -941,13 +941,13 @@
 			  tcp_output(sototcpcb(so)); /* XXX */
 			} else
 			  m_free(m);
-			
+
 			num = 0;
 			while (num < so->so_rcv.sb_cc) {
 				if (*(so->so_rcv.sb_rptr + num) == '\n' ||
 				    *(so->so_rcv.sb_rptr + num) == '\r') {
 					int n;
-					
+
 					*(so_rcv->sb_rptr + num) = 0;
 					if (ctl_password && !ctl_password_ok) {
 						/* Need a password */
@@ -984,38 +984,38 @@
 			}
 			return 0;
 		}
-#endif		
+#endif
         case EMU_FTP: /* ftp */
 		*(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */
 		if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
 			/*
 			 * Need to emulate the PORT command
-			 */			
-			x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", 
+			 */
+			x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]",
 				   &n1, &n2, &n3, &n4, &n5, &n6, buff);
 			if (x < 6)
 			   return 1;
-			
+
 			laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
 			lport = htons((n5 << 8) | (n6));
-			
+
 			if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
 			   return 1;
-			
+
 			n6 = ntohs(so->so_fport);
-			
+
 			n5 = (n6 >> 8) & 0xff;
 			n6 &= 0xff;
-			
+
 			laddr = ntohl(so->so_faddr.s_addr);
-			
+
 			n1 = ((laddr >> 24) & 0xff);
 			n2 = ((laddr >> 16) & 0xff);
 			n3 = ((laddr >> 8)  & 0xff);
 			n4 =  (laddr & 0xff);
-			
+
 			m->m_len = bptr - m->m_data; /* Adjust length */
-			m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", 
+			m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s",
 					    n1, n2, n3, n4, n5, n6, x==7?buff:"");
 			return 1;
 		} else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
@@ -1026,34 +1026,34 @@
 				   &n1, &n2, &n3, &n4, &n5, &n6, buff);
 			if (x < 6)
 			   return 1;
-			
+
 			laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
 			lport = htons((n5 << 8) | (n6));
-			
+
 			if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
 			   return 1;
-			
+
 			n6 = ntohs(so->so_fport);
-			
+
 			n5 = (n6 >> 8) & 0xff;
 			n6 &= 0xff;
-			
+
 			laddr = ntohl(so->so_faddr.s_addr);
-			
+
 			n1 = ((laddr >> 24) & 0xff);
 			n2 = ((laddr >> 16) & 0xff);
 			n3 = ((laddr >> 8)  & 0xff);
 			n4 =  (laddr & 0xff);
-			
+
 			m->m_len = bptr - m->m_data; /* Adjust length */
 			m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
 					    n1, n2, n3, n4, n5, n6, x==7?buff:"");
-			
+
 			return 1;
 		}
-		
+
 		return 1;
-				   
+
 	 case EMU_KSH:
 		/*
 		 * The kshell (Kerberos rsh) and shell services both pass
@@ -1072,7 +1072,7 @@
 		    (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
 			m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1;
 		return 1;
-		
+
 	 case EMU_IRC:
 		/*
 		 * Need to emulate DCC CHAT, DCC SEND and DCC MOVE
@@ -1080,12 +1080,12 @@
 		*(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
 		if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
 			 return 1;
-		
+
 		/* The %256s is for the broken mIRC */
 		if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
 			if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
 				return 1;
-			
+
 			m->m_len = bptr - m->m_data; /* Adjust length */
 			m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n",
 			     (unsigned long)ntohl(so->so_faddr.s_addr),
@@ -1093,15 +1093,15 @@
 		} else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
 			if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
 				return 1;
-			
+
 			m->m_len = bptr - m->m_data; /* Adjust length */
-			m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", 
+			m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n",
 			      buff, (unsigned long)ntohl(so->so_faddr.s_addr),
 			      ntohs(so->so_fport), n1, 1);
 		} else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
 			if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
 				return 1;
-			
+
 			m->m_len = bptr - m->m_data; /* Adjust length */
 			m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n",
 			      buff, (unsigned long)ntohl(so->so_faddr.s_addr),
@@ -1110,7 +1110,7 @@
 		return 1;
 
 	 case EMU_REALAUDIO:
-                /* 
+                /*
 		 * RealAudio emulation - JP. We must try to parse the incoming
 		 * data and try to find the two characters that contain the
 		 * port number. Then we redirect an udp port and replace the
@@ -1118,45 +1118,45 @@
 		 *
 		 * The 1.0 beta versions of the player are not supported
 		 * any more.
-		 * 
+		 *
 		 * A typical packet for player version 1.0 (release version):
-		 *        
-		 * 0000:50 4E 41 00 05 
+		 *
+		 * 0000:50 4E 41 00 05
 		 * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P
 		 * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
 		 * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
 		 * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
-		 *         
+		 *
 		 * Now the port number 0x1BD7 is found at offset 0x04 of the
 		 * Now the port number 0x1BD7 is found at offset 0x04 of the
 		 * second packet. This time we received five bytes first and
 		 * then the rest. You never know how many bytes you get.
 		 *
 		 * A typical packet for player version 2.0 (beta):
-		 *        
+		 *
 		 * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á.
 		 * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0
 		 * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
 		 * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
 		 * 0040:65 2E 72 61 79 53 00 00 06 36 42                e.rayS...6B
-		 *        
+		 *
 		 * Port number 0x1BC1 is found at offset 0x0d.
-		 *      
+		 *
 		 * This is just a horrible switch statement. Variable ra tells
 		 * us where we're going.
 		 */
-		
+
 		bptr = m->m_data;
 		while (bptr < m->m_data + m->m_len) {
 			u_short p;
 			static int ra = 0;
-			char ra_tbl[4]; 
-			
+			char ra_tbl[4];
+
 			ra_tbl[0] = 0x50;
 			ra_tbl[1] = 0x4e;
 			ra_tbl[2] = 0x41;
 			ra_tbl[3] = 0;
-			
+
 			switch (ra) {
 			 case 0:
 			 case 2:
@@ -1166,7 +1166,7 @@
 					continue;
 				}
 				break;
-				
+
 			 case 1:
 				/*
 				 * We may get 0x50 several times, ignore them
@@ -1180,15 +1180,15 @@
 					continue;
 				}
 				break;
-				
-			 case 4: 
-				/* 
+
+			 case 4:
+				/*
 				 * skip version number
 				 */
 				bptr++;
 				break;
-				
-			 case 5: 
+
+			 case 5:
 				/*
 				 * The difference between versions 1.0 and
 				 * 2.0 is here. For future versions of
@@ -1198,19 +1198,19 @@
 				   bptr += 8;
 				else
 				   bptr += 4;
-				break;                          
-				
+				break;
+
 			 case 6:
 				/* This is the field containing the port
 				 * number that RA-player is listening to.
 				 */
-				lport = (((u_char*)bptr)[0] << 8) 
+				lport = (((u_char*)bptr)[0] << 8)
 				+ ((u_char *)bptr)[1];
-				if (lport < 6970)      
+				if (lport < 6970)
 				   lport += 256;   /* don't know why */
 				if (lport < 6970 || lport > 7170)
 				   return 1;       /* failed */
-				
+
 				/* try to get udp port between 6970 - 7170 */
 				for (p = 6970; p < 7071; p++) {
 					if (udp_listen( htons(p),
@@ -1224,17 +1224,17 @@
 				   p = 0;
 				*(u_char *)bptr++ = (p >> 8) & 0xff;
 				*(u_char *)bptr++ = p & 0xff;
-				ra = 0; 
+				ra = 0;
 				return 1;   /* port redirected, we're done */
-				break;  
-				
+				break;
+
 			 default:
-				ra = 0;                         
+				ra = 0;
 			}
 			ra++;
 		}
-		return 1;                                
-		
+		return 1;
+
 	 default:
 		/* Ooops, not emulated, won't call tcp_emu again */
 		so->so_emu = 0;
@@ -1256,10 +1256,10 @@
  	struct ex_list *ex_ptr;
 	int do_pty;
         //	struct socket *tmpso;
-	
+
 	DEBUG_CALL("tcp_ctl");
 	DEBUG_ARG("so = %lx", (long )so);
-	
+
 #if 0
 	/*
 	 * Check if they're authorised
@@ -1269,12 +1269,12 @@
 		sb->sb_wptr += sb->sb_cc;
 		return 0;
 	}
-#endif	
+#endif
 	command = (ntohl(so->so_faddr.s_addr) & 0xff);
-	
+
 	switch(command) {
 	default: /* Check for exec's */
-		
+
 		/*
 		 * Check if it's pty_exec
 		 */
@@ -1285,12 +1285,12 @@
 				goto do_exec;
 			}
 		}
-		
+
 		/*
 		 * Nothing bound..
 		 */
 		/* tcp_fconnect(so); */
-		
+
 		/* FALLTHROUGH */
 	case CTL_ALIAS:
 	  sb->sb_cc = sprintf(sb->sb_wptr,
@@ -1301,12 +1301,12 @@
 	do_exec:
 		DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
 		return(fork_exec(so, ex_ptr->ex_exec, do_pty));
-		
+
 #if 0
 	case CTL_CMD:
 	   for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
-	     if (tmpso->so_emu == EMU_CTL && 
-		 !(tmpso->so_tcpcb? 
+	     if (tmpso->so_emu == EMU_CTL &&
+		 !(tmpso->so_tcpcb?
 		   (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK))
 		   :0)) {
 	       /* Ooops, control connection already active */
diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c
index d3146db..cc1bd50 100644
--- a/slirp/tcp_timer.c
+++ b/slirp/tcp_timer.c
@@ -54,7 +54,7 @@
 	register struct tcpcb *tp;
 
 	DEBUG_CALL("tcp_fasttimo");
-	
+
 	so = tcb.so_next;
 	if (so)
 	for (; so != &tcb; so = so->so_next)
@@ -80,7 +80,7 @@
 	register int i;
 
 	DEBUG_CALL("tcp_slowtimo");
-	
+
 	tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
 	/*
 	 * Search through tcb's and update active timers.
@@ -139,9 +139,9 @@
 	int timer;
 {
 	register int rexmt;
-	
+
 	DEBUG_CALL("tcp_timers");
-	
+
 	switch (timer) {
 
 	/*
@@ -164,12 +164,12 @@
 	 * to a longer retransmit interval and retransmit one segment.
 	 */
 	case TCPT_REXMT:
-		
+
 		/*
 		 * XXXXX If a packet has timed out, then remove all the queued
 		 * packets for that session.
 		 */
-		
+
 		if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
 			/*
 			 * This is a hack to suit our terminal server here at the uni of canberra
@@ -178,14 +178,14 @@
 			 * keep retransmitting it, it'll keep eating the zeroes, so we keep
 			 * retransmitting, and eventually the connection dies...
 			 * (this only happens on incoming data)
-			 * 
+			 *
 			 * So, if we were gonna drop the connection from too many retransmits,
 			 * don't... instead halve the t_maxseg, which might break up the NULLs and
 			 * let them through
-			 * 
+			 *
 			 * *sigh*
 			 */
-			
+
 			tp->t_maxseg >>= 1;
 			if (tp->t_maxseg < 32) {
 				/*
@@ -197,7 +197,7 @@
 				/* tp->t_softerror : ETIMEDOUT); */ /* XXX */
 				return (tp); /* XXX */
 			}
-			
+
 			/*
 			 * Set rxtshift to 6, which is still at the maximum
 			 * backoff time
@@ -240,7 +240,7 @@
 		 * size increase exponentially with time.  If the
 		 * window is larger than the path can handle, this
 		 * exponential growth results in dropped packet(s)
-		 * almost immediately.  To get more time between 
+		 * almost immediately.  To get more time between
 		 * drops but still "push" the network to take advantage
 		 * of improving conditions, we switch from exponential
 		 * to linear window opening at some threshold size.
diff --git a/slirp/tftp.c b/slirp/tftp.c
index c9946d6..2b2bf2c 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -1,8 +1,8 @@
 /*
  * tftp.c - a simple, read-only tftp server for qemu
- * 
+ *
  * Copyright (c) 2004 Magnus Damm <damm@opensource.se>
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -27,10 +27,10 @@
 struct tftp_session {
     int in_use;
     unsigned char filename[TFTP_FILENAME_MAX];
-    
+
     struct in_addr client_ip;
     u_int16_t client_port;
-    
+
     int timestamp;
 };
 
@@ -102,8 +102,15 @@
 {
   int fd;
   int bytes_read = 0;
+  char buffer[1024];
+  int n;
 
-  fd = open(spt->filename, O_RDONLY | O_BINARY);
+  n = snprintf(buffer, sizeof(buffer), "%s/%s",
+	       tftp_prefix, spt->filename);
+  if (n >= sizeof(buffer))
+    return -1;
+
+  fd = open(buffer, O_RDONLY | O_BINARY);
 
   if (fd < 0) {
     return -1;
@@ -120,7 +127,46 @@
   return bytes_read;
 }
 
-static int tftp_send_error(struct tftp_session *spt, 
+static int tftp_send_oack(struct tftp_session *spt,
+                          const char *key, uint32_t value,
+                          struct tftp_t *recv_tp)
+{
+    struct sockaddr_in saddr, daddr;
+    struct mbuf *m;
+    struct tftp_t *tp;
+    int n = 0;
+
+    m = m_get();
+
+    if (!m)
+	return -1;
+
+    memset(m->m_data, 0, m->m_size);
+
+    m->m_data += if_maxlinkhdr;
+    tp = (void *)m->m_data;
+    m->m_data += sizeof(struct udpiphdr);
+
+    tp->tp_op = htons(TFTP_OACK);
+    n += sprintf(tp->x.tp_buf + n, "%s", key) + 1;
+    n += sprintf(tp->x.tp_buf + n, "%u", value) + 1;
+
+    saddr.sin_addr = recv_tp->ip.ip_dst;
+    saddr.sin_port = recv_tp->udp.uh_dport;
+
+    daddr.sin_addr = spt->client_ip;
+    daddr.sin_port = spt->client_port;
+
+    m->m_len = sizeof(struct tftp_t) - 514 + n -
+        sizeof(struct ip) - sizeof(struct udphdr);
+    udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+
+    return 0;
+}
+
+
+
+static int tftp_send_error(struct tftp_session *spt,
 			   u_int16_t errorcode, const char *msg,
 			   struct tftp_t *recv_tp)
 {
@@ -140,7 +186,7 @@
   m->m_data += if_maxlinkhdr;
   tp = (void *)m->m_data;
   m->m_data += sizeof(struct udpiphdr);
-  
+
   tp->tp_op = htons(TFTP_ERROR);
   tp->x.tp_error.tp_error_code = htons(errorcode);
   strcpy(tp->x.tp_error.tp_msg, msg);
@@ -153,7 +199,7 @@
 
   nobytes = 2;
 
-  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - 
+  m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
         sizeof(struct ip) - sizeof(struct udphdr);
 
   udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
@@ -163,7 +209,7 @@
   return 0;
 }
 
-static int tftp_send_data(struct tftp_session *spt, 
+static int tftp_send_data(struct tftp_session *spt,
 			  u_int16_t block_nr,
 			  struct tftp_t *recv_tp)
 {
@@ -187,7 +233,7 @@
   m->m_data += if_maxlinkhdr;
   tp = (void *)m->m_data;
   m->m_data += sizeof(struct udpiphdr);
-  
+
   tp->tp_op = htons(TFTP_DATA);
   tp->x.tp_data.tp_block_nr = htons(block_nr);
 
@@ -209,7 +255,7 @@
     return -1;
   }
 
-  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - 
+  m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
         sizeof(struct ip) - sizeof(struct udphdr);
 
   udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
@@ -251,28 +297,30 @@
     else {
       return;
     }
-    
+
     if (src[k] == '\0') {
       break;
     }
   }
-      
+
   if (k >= n) {
     return;
   }
-  
+
   k++;
-  
+
   /* check mode */
   if ((n - k) < 6) {
     return;
   }
-  
+
   if (memcmp(&src[k], "octet\0", 6) != 0) {
       tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
       return;
   }
 
+  k += 6; /* skipping octet */
+
   /* do sanity checks on the filename */
 
   if ((spt->filename[0] != '/')
@@ -284,19 +332,60 @@
 
   /* only allow exported prefixes */
 
-  if (!tftp_prefix
-      || (strncmp(spt->filename, tftp_prefix, strlen(tftp_prefix)) != 0)) {
+  if (!tftp_prefix) {
       tftp_send_error(spt, 2, "Access violation", tp);
       return;
   }
 
   /* check if the file exists */
-  
+
   if (tftp_read_data(spt, 0, spt->filename, 0) < 0) {
       tftp_send_error(spt, 1, "File not found", tp);
       return;
   }
 
+  if (src[n - 1] != 0) {
+      tftp_send_error(spt, 2, "Access violation", tp);
+      return;
+  }
+
+  while (k < n) {
+      const char *key, *value;
+
+      key = src + k;
+      k += strlen(key) + 1;
+
+      if (k >= n) {
+	  tftp_send_error(spt, 2, "Access violation", tp);
+	  return;
+      }
+
+      value = src + k;
+      k += strlen(value) + 1;
+
+      if (strcmp(key, "tsize") == 0) {
+	  int tsize = atoi(value);
+	  struct stat stat_p;
+
+	  if (tsize == 0 && tftp_prefix) {
+	      char buffer[1024];
+	      int len;
+
+	      len = snprintf(buffer, sizeof(buffer), "%s/%s",
+			     tftp_prefix, spt->filename);
+
+	      if (stat(buffer, &stat_p) == 0)
+		  tsize = stat_p.st_size;
+	      else {
+		  tftp_send_error(spt, 1, "File not found", tp);
+		  return;
+	      }
+	  }
+
+	  tftp_send_oack(spt, "tsize", tsize, tp);
+      }
+  }
+
   tftp_send_data(spt, 1, tp);
 }
 
@@ -310,8 +399,8 @@
     return;
   }
 
-  if (tftp_send_data(&tftp_sessions[s], 
-		     ntohs(tp->x.tp_data.tp_block_nr) + 1, 
+  if (tftp_send_data(&tftp_sessions[s],
+		     ntohs(tp->x.tp_data.tp_block_nr) + 1,
 		     tp) < 0) {
     return;
   }
diff --git a/slirp/tftp.h b/slirp/tftp.h
index f0560b6..8f2675e 100644
--- a/slirp/tftp.h
+++ b/slirp/tftp.h
@@ -9,6 +9,7 @@
 #define TFTP_DATA   3
 #define TFTP_ACK    4
 #define TFTP_ERROR  5
+#define TFTP_OACK   6
 
 #define TFTP_FILENAME_MAX 512
 
@@ -17,11 +18,11 @@
   struct udphdr udp;
   u_int16_t tp_op;
   union {
-    struct { 
+    struct {
       u_int16_t tp_block_nr;
       u_int8_t tp_buf[512];
     } tp_data;
-    struct { 
+    struct {
       u_int16_t tp_error_code;
       u_int8_t tp_msg[512];
     } tp_error;
diff --git a/slirp/udp.c b/slirp/udp.c
index 8cf4cbd..44900ff 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -37,8 +37,8 @@
 /*
  * Changes and additions relating to SLiRP
  * Copyright (c) 1995 Danny Gasparovski.
- * 
- * Please read the file COPYRIGHT for the 
+ *
+ * Please read the file COPYRIGHT for the
  * terms and conditions of the copyright.
  */
 
@@ -66,8 +66,8 @@
 {
 	udb.so_next = udb.so_prev = &udb;
 }
-/* m->m_data  points at ip packet header 
- * m->m_len   length ip packet 
+/* m->m_data  points at ip packet header
+ * m->m_len   length ip packet
  * ip->ip_len length data (IPDU)
  */
 void
@@ -79,13 +79,13 @@
 	register struct udphdr *uh;
 /*	struct mbuf *opts = 0;*/
 	int len;
-	struct ip save_ip; 
+	struct ip save_ip;
 	struct socket *so;
-	
+
 	DEBUG_CALL("udp_input");
 	DEBUG_ARG("m = %lx", (long)m);
 	DEBUG_ARG("iphlen = %d", iphlen);
-	
+
 	udpstat.udps_ipackets++;
 
 	/*
@@ -119,12 +119,12 @@
 		m_adj(m, len - ip->ip_len);
 		ip->ip_len = len;
 	}
-	
+
 	/*
 	 * Save a copy of the IP header in case we want restore it
 	 * for sending an ICMP error message in response.
 	 */
-	save_ip = *ip; 
+	save_ip = *ip;
 	save_ip.ip_len+= iphlen;         /* tcp_input subtracts this */
 
 	/*
@@ -136,8 +136,8 @@
 	  ((struct ipovly *)ip)->ih_x1 = 0;
 	  ((struct ipovly *)ip)->ih_len = uh->uh_ulen;
 	  /* keep uh_sum for ICMP reply
-	   * uh->uh_sum = cksum(m, len + sizeof (struct ip)); 
-	   * if (uh->uh_sum) { 
+	   * uh->uh_sum = cksum(m, len + sizeof (struct ip));
+	   * if (uh->uh_sum) {
 	   */
 	  if(cksum(m, len + sizeof(struct ip))) {
 	    udpstat.udps_badsum++;
@@ -168,7 +168,7 @@
 	if (so->so_lport != uh->uh_sport ||
 	    so->so_laddr.s_addr != ip->ip_src.s_addr) {
 		struct socket *tmp;
-		
+
 		for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
 			if (tmp->so_lport == uh->uh_sport &&
 			    tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
@@ -185,7 +185,7 @@
 		  udp_last_so = so;
 		}
 	}
-	
+
 	if (so == NULL) {
 	  /*
 	   * If there's no socket for this packet,
@@ -193,22 +193,22 @@
 	   */
 	  if ((so = socreate()) == NULL) goto bad;
 	  if(udp_attach(so) == -1) {
-	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", 
+	    DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
 			errno,strerror(errno)));
 	    sofree(so);
 	    goto bad;
 	  }
-	  
+
 	  /*
 	   * Setup fields
 	   */
 	  /* udp_last_so = so; */
 	  so->so_laddr = ip->ip_src;
 	  so->so_lport = uh->uh_sport;
-	  
+
 	  if ((so->so_iptos = udp_tos(so)) == 0)
 	    so->so_iptos = ip->ip_tos;
-	  
+
 	  /*
 	   * XXXXX Here, check if it's in udpexec_list,
 	   * and if it is, do the fork_exec() etc.
@@ -233,7 +233,7 @@
 	  m->m_data -= iphlen;
 	  *ip=save_ip;
 	  DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
-	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));  
+	  icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
 	}
 
 	m_free(so->so_m);   /* used for ICMP if error on sorecvfrom */
@@ -251,7 +251,7 @@
 	return;
 }
 
-int udp_output2(struct socket *so, struct mbuf *m, 
+int udp_output2(struct socket *so, struct mbuf *m,
                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
                 int iptos)
 {
@@ -269,7 +269,7 @@
 	 */
 	m->m_data -= sizeof(struct udpiphdr);
 	m->m_len += sizeof(struct udpiphdr);
-	
+
 	/*
 	 * Fill in mbuf with extended UDP header
 	 * and addresses and length put into network format.
@@ -298,15 +298,15 @@
 
 	((struct ip *)ui)->ip_ttl = ip_defttl;
 	((struct ip *)ui)->ip_tos = iptos;
-	
+
 	udpstat.udps_opackets++;
-	
+
 	error = ip_output(so, m);
-	
+
 	return (error);
 }
 
-int udp_output(struct socket *so, struct mbuf *m, 
+int udp_output(struct socket *so, struct mbuf *m,
                struct sockaddr_in *addr)
 
 {
@@ -320,7 +320,7 @@
     }
     daddr.sin_addr = so->so_laddr;
     daddr.sin_port = so->so_lport;
-    
+
     return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
 }
 
@@ -329,7 +329,7 @@
      struct socket *so;
 {
   struct sockaddr_in addr;
-	
+
   if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
     /*
      * Here, we bind() the socket.  Although not really needed
@@ -380,7 +380,7 @@
 	struct socket *so;
 {
 	int i = 0;
-	
+
 	while(udptos[i].tos) {
 		if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
 		    (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
@@ -389,7 +389,7 @@
 		}
 		i++;
 	}
-	
+
 	return 0;
 }
 
@@ -412,17 +412,17 @@
 	CTL_MSG *nmsg;
 	char buff[sizeof(CTL_MSG)];
 	u_char type;
-	
+
 struct talk_request {
 	struct talk_request *next;
 	struct socket *udp_so;
 	struct socket *tcp_so;
 } *req;
-	
-	static struct talk_request *req_tbl = 0;	
-	
+
+	static struct talk_request *req_tbl = 0;
+
 #endif
-	
+
 struct cu_header {
 	uint16_t	d_family;		// destination family
 	uint16_t	d_port;			// destination port
@@ -449,7 +449,7 @@
 		 */
 		if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
 			return;
-		
+
 #define	IS_OLD	(so->so_emu == EMU_TALK)
 
 #define COPY_MSG(dest, src) { dest->type = src->type; \
@@ -472,7 +472,7 @@
 			OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
 			OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
 			strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD);
-		} else {		/* new talk */	
+		} else {		/* new talk */
 			omsg = (CTL_MSG_OLD *) buff;
 			nmsg = mtod(m, CTL_MSG *);
 			type = nmsg->type;
@@ -480,10 +480,10 @@
 			OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
 			strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD);
 		}
-		
-		if (type == LOOK_UP) 
+
+		if (type == LOOK_UP)
 			return;		/* for LOOK_UP this is enough */
-			
+
 		if (IS_OLD) {		/* make a copy of the message */
 			COPY_MSG(nmsg, omsg);
 			nmsg->vers = 1;
@@ -502,75 +502,75 @@
 		 * ports, 517 and 518. This is why we have two copies
 		 * of the message, one in old talk and one in new talk
 		 * format.
-		 */ 
+		 */
 
 		if (type == ANNOUNCE) {
 			int s;
 			u_short temp_port;
-			
+
 			for(req = req_tbl; req; req = req->next)
 				if (so == req->udp_so)
 					break;  	/* found it */
-					
+
 			if (!req) {	/* no entry for so, create new */
 				req = (struct talk_request *)
 					malloc(sizeof(struct talk_request));
 				req->udp_so = so;
-				req->tcp_so = solisten(0,		
-					OTOSIN(omsg, addr)->sin_addr.s_addr,	
+				req->tcp_so = solisten(0,
+					OTOSIN(omsg, addr)->sin_addr.s_addr,
 					OTOSIN(omsg, addr)->sin_port,
 					SS_FACCEPTONCE);
 				req->next = req_tbl;
 				req_tbl = req;
-			}			
-			
+			}
+
 			/* replace port number in addr field */
 			addrlen = sizeof(addr);
-			getsockname(req->tcp_so->s, 
+			getsockname(req->tcp_so->s,
 					(struct sockaddr *) &addr,
-					&addrlen);		
+					&addrlen);
 			OTOSIN(omsg, addr)->sin_port = addr.sin_port;
 			OTOSIN(omsg, addr)->sin_addr = our_addr;
 			OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
-			OTOSIN(nmsg, addr)->sin_addr = our_addr;		
-			
+			OTOSIN(nmsg, addr)->sin_addr = our_addr;
+
 			/* send LEAVE_INVITEs */
 			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
 			OTOSIN(omsg, ctl_addr)->sin_port = 0;
 			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
-			omsg->type = nmsg->type = LEAVE_INVITE;			
-			
+			omsg->type = nmsg->type = LEAVE_INVITE;
+
 			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
 			addr.sin_addr = our_addr;
 			addr.sin_family = AF_INET;
 			addr.sin_port = htons(517);
-			sendto(s, (char *)omsg, sizeof(*omsg), 0, 
+			sendto(s, (char *)omsg, sizeof(*omsg), 0,
 				(struct sockaddr *)&addr, sizeof(addr));
 			addr.sin_port = htons(518);
 			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
 				(struct sockaddr *) &addr, sizeof(addr));
 			closesocket(s) ;
 
-			omsg->type = nmsg->type = ANNOUNCE; 
+			omsg->type = nmsg->type = ANNOUNCE;
 			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
 			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
 		}
-		
-		/*	
+
+		/*
 		 * If it is a DELETE message, we send a copy to the
 		 * local daemons. Then we delete the entry corresponding
 		 * to our socket from the request table.
 		 */
-		
+
 		if (type == DELETE) {
 			struct talk_request *temp_req, *req_next;
 			int s;
 			u_short temp_port;
-			
+
 			temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
 			OTOSIN(omsg, ctl_addr)->sin_port = 0;
 			OTOSIN(nmsg, ctl_addr)->sin_port = 0;
-			
+
 			s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
 			addr.sin_addr = our_addr;
 			addr.sin_family = AF_INET;
@@ -581,7 +581,7 @@
 			sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
 				(struct sockaddr *)&addr, sizeof(addr));
 			closesocket(s);
-			
+
 			OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
 			OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
 
@@ -604,18 +604,18 @@
 				}
 			}
 		}
-		
-		return;		
+
+		return;
 #endif
-		
+
 	case EMU_CUSEEME:
-	
+
 		/*
 		 * Cu-SeeMe emulation.
 		 * Hopefully the packet is more that 16 bytes long. We don't
 		 * do any other tests, just replace the address and port
 		 * fields.
-		 */ 
+		 */
 		if (m->m_len >= sizeof (*cu_head)) {
 			if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
 				return;
@@ -623,7 +623,7 @@
 			cu_head->s_port = addr.sin_port;
 			cu_head->so_addr = our_addr.s_addr;
 		}
-		
+
 		return;
 	}
 }
@@ -638,7 +638,7 @@
 	struct sockaddr_in addr;
 	struct socket *so;
 	int addrlen = sizeof(struct sockaddr_in), opt = 1;
-	
+
 	if ((so = socreate()) == NULL) {
 		free(so);
 		return NULL;
@@ -657,20 +657,20 @@
 	}
 	setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
 /*	setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */
-	
+
 	getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
 	so->so_fport = addr.sin_port;
 	if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
 	   so->so_faddr = alias_addr;
 	else
 	   so->so_faddr = addr.sin_addr;
-	
+
 	so->so_lport = lport;
 	so->so_laddr.s_addr = laddr;
 	if (flags != SS_FACCEPTONCE)
 	   so->so_expire = 0;
-	
+
 	so->so_state = SS_ISFCONNECTED;
-	
+
 	return so;
 }
diff --git a/slirp/udp.h b/slirp/udp.h
index 24c11bb..67da6cd 100644
--- a/slirp/udp.h
+++ b/slirp/udp.h
@@ -104,7 +104,7 @@
 u_int8_t udp_tos _P((struct socket *));
 void udp_emu _P((struct socket *, struct mbuf *));
 struct socket * udp_listen _P((u_int, u_int32_t, u_int, int));
-int udp_output2(struct socket *so, struct mbuf *m, 
+int udp_output2(struct socket *so, struct mbuf *m,
                 struct sockaddr_in *saddr, struct sockaddr_in *daddr,
                 int iptos);
 #endif
diff --git a/softmmu-semi.h b/softmmu-semi.h
new file mode 100644
index 0000000..13c528b
--- /dev/null
+++ b/softmmu-semi.h
@@ -0,0 +1,67 @@
+/*
+ * Helper routines to provide target memory access for semihosting
+ * syscalls in system emulation mode.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * This code is licenced under the GPL
+ */
+
+static inline uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
+{
+    uint32_t val;
+
+    cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
+    return tswap32(val);
+}
+static inline uint32_t softmmu_tget8(CPUState *env, uint32_t addr)
+{
+    uint8_t val;
+
+    cpu_memory_rw_debug(env, addr, &val, 1, 0);
+    return val;
+}
+#define tget32(p) softmmu_tget32(env, p)
+#define tget8(p) softmmu_tget8(env, p)
+
+static inline void softmmu_tput32(CPUState *env, uint32_t addr, uint32_t val)
+{
+    val = tswap32(val);
+    cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 1);
+}
+#define tput32(p, val) softmmu_tput32(env, p, val)
+
+static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
+                               int copy)
+{
+    char *p;
+    /* TODO: Make this something that isn't fixed size.  */
+    p = malloc(len);
+    if (copy)
+        cpu_memory_rw_debug(env, addr, p, len, 0);
+    return p;
+}
+#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy)
+static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
+{
+    char *p;
+    char *s;
+    uint8_t c;
+    /* TODO: Make this something that isn't fixed size.  */
+    s = p = malloc(1024);
+    do {
+        cpu_memory_rw_debug(env, addr, &c, 1, 0);
+        addr++;
+        *(p++) = c;
+    } while (c);
+    return s;
+}
+#define lock_user_string(p) softmmu_lock_user_string(env, p)
+static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
+                                target_ulong len)
+{
+    if (len)
+        cpu_memory_rw_debug(env, addr, p, len, 1);
+    free(p);
+}
+#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
diff --git a/softmmu_header.h b/softmmu_header.h
index d5b3deb..768b877 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -1,6 +1,6 @@
 /*
  *  Software MMU support
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -63,6 +63,10 @@
 #define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
 #elif defined (TARGET_SH4)
 #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
@@ -82,6 +86,10 @@
 #define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
 #elif defined (TARGET_SH4)
 #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
@@ -143,9 +151,9 @@
 #endif
                   "2:\n"
                   : "=r" (res)
-                  : "r" (ptr), 
-                  "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), 
-                  "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), 
+                  : "r" (ptr),
+                  "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS),
+                  "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS),
                   "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)),
                   "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)),
                   "i" (CPU_MEM_INDEX),
@@ -190,9 +198,9 @@
 #endif
                   "2:\n"
                   : "=r" (res)
-                  : "r" (ptr), 
-                  "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), 
-                  "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), 
+                  : "r" (ptr),
+                  "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS),
+                  "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS),
                   "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)),
                   "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)),
                   "i" (CPU_MEM_INDEX),
@@ -238,13 +246,13 @@
 #error unsupported size
 #endif
                   "2:\n"
-                  : 
-                  : "r" (ptr), 
+                  :
+                  : "r" (ptr),
 /* NOTE: 'q' would be needed as constraint, but we could not use it
    with T1 ! */
-                  "r" (v), 
-                  "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS), 
-                  "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS), 
+                  "r" (v),
+                  "i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS),
+                  "i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS),
                   "i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)),
                   "m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)),
                   "i" (CPU_MEM_INDEX),
@@ -267,7 +275,7 @@
     addr = ptr;
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     is_user = CPU_MEM_INDEX;
-    if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != 
+    if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ !=
                          (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
         res = glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
     } else {
@@ -288,7 +296,7 @@
     addr = ptr;
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     is_user = CPU_MEM_INDEX;
-    if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ != 
+    if (__builtin_expect(env->tlb_table[is_user][index].ADDR_READ !=
                          (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
         res = (DATA_STYPE)glue(glue(__ld, SUFFIX), MMUSUFFIX)(addr, is_user);
     } else {
@@ -313,7 +321,7 @@
     addr = ptr;
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
     is_user = CPU_MEM_INDEX;
-    if (__builtin_expect(env->tlb_table[is_user][index].addr_write != 
+    if (__builtin_expect(env->tlb_table[is_user][index].addr_write !=
                          (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))), 0)) {
         glue(glue(__st, SUFFIX), MMUSUFFIX)(addr, v, is_user);
     } else {
diff --git a/softmmu_template.h b/softmmu_template.h
index 1c12c42..ce6e4bd 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -1,6 +1,6 @@
 /*
  *  Software MMU support
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -47,10 +47,10 @@
 #define ADDR_READ addr_read
 #endif
 
-static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, 
+static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
                                                         int is_user,
                                                         void *retaddr);
-static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr, 
+static inline DATA_TYPE glue(io_read, SUFFIX)(target_phys_addr_t physaddr,
                                               target_ulong tlb_addr)
 {
     DATA_TYPE res;
@@ -83,7 +83,7 @@
     target_ulong tlb_addr;
     target_phys_addr_t physaddr;
     void *retaddr;
-    
+
     /* test if there is match for unaligned or IO access */
     /* XXX: could done more in memory macro in a non portable way */
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
@@ -103,7 +103,7 @@
 #ifdef ALIGNED_ONLY
             do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
 #endif
-            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, 
+            res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr,
                                                          is_user, retaddr);
         } else {
             /* unaligned/aligned access in the same page */
@@ -129,7 +129,7 @@
 }
 
 /* handle all unaligned cases */
-static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr, 
+static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
                                                         int is_user,
                                                         void *retaddr)
 {
@@ -153,9 +153,9 @@
             /* slow unaligned access (it spans two pages) */
             addr1 = addr & ~(DATA_SIZE - 1);
             addr2 = addr1 + DATA_SIZE;
-            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1, 
+            res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr1,
                                                           is_user, retaddr);
-            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2, 
+            res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr2,
                                                           is_user, retaddr);
             shift = (addr & (DATA_SIZE - 1)) * 8;
 #ifdef TARGET_WORDS_BIGENDIAN
@@ -178,12 +178,12 @@
 
 #ifndef SOFTMMU_CODE_ACCESS
 
-static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, 
-                                                   DATA_TYPE val, 
+static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
+                                                   DATA_TYPE val,
                                                    int is_user,
                                                    void *retaddr);
 
-static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr, 
+static inline void glue(io_write, SUFFIX)(target_phys_addr_t physaddr,
                                           DATA_TYPE val,
                                           target_ulong tlb_addr,
                                           void *retaddr)
@@ -209,7 +209,7 @@
 #endif
 }
 
-void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, 
+void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
                                                     DATA_TYPE val,
                                                     int is_user)
 {
@@ -217,7 +217,7 @@
     target_ulong tlb_addr;
     void *retaddr;
     int index;
-    
+
     index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
  redo:
     tlb_addr = env->tlb_table[is_user][index].addr_write;
@@ -235,7 +235,7 @@
 #ifdef ALIGNED_ONLY
             do_unaligned_access(addr, 1, is_user, retaddr);
 #endif
-            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, 
+            glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val,
                                                    is_user, retaddr);
         } else {
             /* aligned/unaligned access in the same page */
@@ -260,7 +260,7 @@
 }
 
 /* handles all unaligned cases */
-static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr, 
+static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(target_ulong addr,
                                                    DATA_TYPE val,
                                                    int is_user,
                                                    void *retaddr)
@@ -284,10 +284,10 @@
             /* XXX: not efficient, but simple */
             for(i = 0;i < DATA_SIZE; i++) {
 #ifdef TARGET_WORDS_BIGENDIAN
-                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)), 
+                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (((DATA_SIZE - 1) * 8) - (i * 8)),
                                           is_user, retaddr);
 #else
-                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8), 
+                glue(slow_stb, MMUSUFFIX)(addr + i, val >> (i * 8),
                                           is_user, retaddr);
 #endif
             }
diff --git a/sparc-dis.c b/sparc-dis.c
index 2be874a..4d2020f 100644
--- a/sparc-dis.c
+++ b/sparc-dis.c
@@ -276,7 +276,7 @@
   { "v8", MASK_V6 | MASK_V7 | MASK_V8 },
   { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET },
   { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE },
-  /* ??? Don't some v8 priviledged insns conflict with v9?  */
+  /* ??? Don't some v8 privileged insns conflict with v9?  */
   { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 },
   /* v9 with ultrasparc additions */
   { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A },
@@ -359,7 +359,7 @@
 #define FBFCC(x)	(((x)&0x3)<<20)	/* v9 */
 
 /* The order of the opcodes in the table is significant:
-	
+
 	* The assembler requires that all instances of the same mnemonic must
 	be consecutive.	If they aren't, the assembler will bomb at runtime.
 
@@ -2206,7 +2206,7 @@
 
 /* Handle membar masks.  */
 
-static arg membar_table[] =
+static const arg membar_table[] =
 {
   { 0x40, "#Sync" },
   { 0x20, "#MemIssue" },
@@ -2238,7 +2238,7 @@
 
 /* Handle prefetch args.  */
 
-static arg prefetch_table[] =
+static const arg prefetch_table[] =
 {
   { 0, "#n_reads" },
   { 1, "#one_read" },
@@ -2269,7 +2269,7 @@
 
 /* Handle sparclet coprocessor registers.  */
 
-static arg sparclet_cpreg_table[] =
+static const arg sparclet_cpreg_table[] =
 {
   { 0, "%ccsr" },
   { 1, "%ccfr" },
@@ -2320,7 +2320,7 @@
 /* It is important that we only look at insn code bits as that is how the
    opcode table is hashed.  OPCODE_BITS is a table of valid bits for each
    of the main types (0,1,2,3).  */
-static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
+static const int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
 #define HASH_INSN(INSN) \
   ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))
 struct opcode_hash {
@@ -2340,17 +2340,17 @@
 	((((int)(value)) << ((8 * sizeof (int)) - bits))	\
 			 >> ((8 * sizeof (int)) - bits) )
 
-static  char *reg_names[] =
-{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",	
-  "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",	
-  "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",	
-  "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",	
-  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",	
-  "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",	
+static const char * const reg_names[] =
+{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
+  "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
+  "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
+  "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
+  "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+  "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
   "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
   "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
-  "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",	
-  "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",	
+  "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
+  "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
   "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
   "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
 /* psr, wim, tbr, fpsr, cpsr are v8 only.  */
@@ -2361,7 +2361,7 @@
 
 /* These are ordered according to there register number in
    rdpr and wrpr insns.  */
-static char *v9_priv_reg_names[] =
+static const char * const v9_priv_reg_names[] =
 {
   "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
   "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
@@ -2371,7 +2371,7 @@
 
 /* These are ordered according to there register number in
    rd and wr insns (-16).  */
-static char *v9a_asr_reg_names[] =
+static const char * const v9a_asr_reg_names[] =
 {
   "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint",
   "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr"
@@ -2566,7 +2566,7 @@
 	  /* Nonzero means that we have found a plus sign in the args
 	     field of the opcode table.  */
 	  int found_plus = 0;
-	  
+
 	  /* Nonzero means we have an annulled branch.  */
 	  int is_annulled = 0;
 
@@ -2621,7 +2621,7 @@
 		  }		/* while there are comma started args */
 
 		(*info->fprintf_func) (stream, " ");
-			
+
 		switch (*s)
 		  {
 		  case '+':
@@ -2722,7 +2722,7 @@
 			 not before it.  */
 		      if (found_plus)
 			imm_added_to_rs1 = 1;
-		      
+
 		      if (imm <= 9)
 			(*info->fprintf_func) (stream, "%d", imm);
 		      else
@@ -2806,7 +2806,7 @@
 		  case 'o':
 		    (*info->fprintf_func) (stream, "%%asi");
 		    break;
-		    
+
 		  case 'W':
 		    (*info->fprintf_func) (stream, "%%tick");
 		    break;
@@ -2859,15 +2859,15 @@
 			(*info->fprintf_func) (stream, "%d", X_RD (insn));
 		      break;
 		    }
-		    
+
 		  case 'M':
 		    (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn));
 		    break;
-		    
+
 		  case 'm':
 		    (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn));
 		    break;
-		    
+
 		  case 'L':
 		    info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;
 		    (*info->print_address_func) (info->target, info);
@@ -2999,7 +2999,7 @@
 		      && X_RD (prev_insn) == X_RS1 (insn))
 		    {
 		      (*info->fprintf_func) (stream, "\t! ");
-		      info->target = 
+		      info->target =
 			((unsigned) 0xFFFFFFFF
 			 & ((int) X_IMM22 (prev_insn) << 10));
 		      if (imm_added_to_rs1)
diff --git a/sparc.ld b/sparc.ld
index 6333928..2b19d57 100644
--- a/sparc.ld
+++ b/sparc.ld
@@ -64,6 +64,8 @@
     CONSTRUCTORS
   }
   .data1   : { *(.data1) }
+  .tdata    : { *(.tdata) }
+  .tbss    : { *(.tbss) }
   .ctors         :
   {
     *(.ctors)
@@ -125,4 +127,5 @@
   .debug_typenames 0 : { *(.debug_typenames) }
   .debug_varnames  0 : { *(.debug_varnames) }
   /* These must appear regardless of  .  */
+  /DISCARD/ : { *(.note.GNU-stack) *(.note.ABI-tag) }
 }
diff --git a/tap-win32.c b/tap-win32.c
index d84a622..c900b4b 100644
--- a/tap-win32.c
+++ b/tap-win32.c
@@ -110,7 +110,7 @@
 
 static tap_win32_overlapped_t tap_overlapped;
 
-static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped) 
+static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped)
 {
     tun_buffer_t* buffer = NULL;
     WaitForSingleObject(overlapped->free_list_semaphore, INFINITE);
@@ -132,18 +132,18 @@
     ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL);
 }
 
-static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block) 
+static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block)
 {
     tun_buffer_t* buffer = NULL;
     DWORD result, timeout = block ? INFINITE : 0L;
 
     // Non-blocking call
-    result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout); 
+    result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout);
 
-    switch (result) 
-    { 
+    switch (result)
+    {
         // The semaphore object was signaled.
-        case WAIT_OBJECT_0: 
+        case WAIT_OBJECT_0:
             EnterCriticalSection(&overlapped->output_queue_cs);
 
             buffer = overlapped->output_queue_front;
@@ -154,18 +154,18 @@
             }
 
             LeaveCriticalSection(&overlapped->output_queue_cs);
-            break; 
+            break;
 
         // Semaphore was nonsignaled, so a time-out occurred.
-        case WAIT_TIMEOUT: 
+        case WAIT_TIMEOUT:
             // Cannot open another window.
-            break; 
+            break;
     }
 
     return buffer;
 }
 
-static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped) 
+static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped)
 {
     return get_buffer_from_output_queue(overlapped, 0);
 }
@@ -332,7 +332,7 @@
             return -1;
         }
 
-        snprintf(connection_string, 
+        snprintf(connection_string,
              sizeof(connection_string),
              "%s\\%s\\Connection",
              NETWORK_CONNECTIONS_KEY, enum_name);
@@ -343,7 +343,7 @@
             0,
             KEY_READ,
             &connection_key);
-        
+
         if (status == ERROR_SUCCESS) {
             len = sizeof (name_data);
             status = RegQueryValueEx(
@@ -416,7 +416,7 @@
     InitializeCriticalSection(&overlapped->output_queue_cs);
     InitializeCriticalSection(&overlapped->free_list_cs);
 
-    overlapped->output_queue_semaphore = CreateSemaphore( 
+    overlapped->output_queue_semaphore = CreateSemaphore(
         NULL,   // default security attributes
         0,   // initial count
         TUN_MAX_BUFFER_COUNT,   // maximum count
@@ -426,7 +426,7 @@
         fprintf(stderr, "error creating output queue semaphore!\n");
     }
 
-    overlapped->free_list_semaphore = CreateSemaphore( 
+    overlapped->free_list_semaphore = CreateSemaphore(
         NULL,   // default security attributes
         TUN_MAX_BUFFER_COUNT,   // initial count
         TUN_MAX_BUFFER_COUNT,   // maximum count
@@ -452,7 +452,7 @@
         fprintf(stderr, "error creating tap_semaphore.\n");
 }
 
-static int tap_win32_write(tap_win32_overlapped_t *overlapped, 
+static int tap_win32_write(tap_win32_overlapped_t *overlapped,
                            const void *buffer, unsigned long size)
 {
     unsigned long write_size;
@@ -467,18 +467,18 @@
 
     result = WriteFile(overlapped->handle, buffer, size,
                        &write_size, &overlapped->write_overlapped);
-    
-    if (!result) { 
+
+    if (!result) {
         switch (error = GetLastError())
-        { 
-        case ERROR_IO_PENDING: 
+        {
+        case ERROR_IO_PENDING:
 #ifndef TUN_ASYNCHRONOUS_WRITES
             WaitForSingleObject(overlapped->write_event, INFINITE);
 #endif
             break;
         default:
             return -1;
-        } 
+        }
     }
 
     return 0;
@@ -539,7 +539,7 @@
     return 0;
 }
 
-static int tap_win32_read(tap_win32_overlapped_t *overlapped, 
+static int tap_win32_read(tap_win32_overlapped_t *overlapped,
                           uint8_t **pbuf, int max_size)
 {
     int size = 0;
@@ -557,14 +557,14 @@
     return size;
 }
 
-static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, 
-                                  char* pbuf) 
+static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
+                                  char* pbuf)
 {
     tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
     put_buffer_on_free_list(overlapped, buffer);
 }
 
-static int tap_win32_open(tap_win32_overlapped_t **phandle, 
+static int tap_win32_open(tap_win32_overlapped_t **phandle,
                           const char *prefered_name)
 {
     char device_path[256];
@@ -660,7 +660,7 @@
 int tap_win32_init(VLANState *vlan, const char *ifname)
 {
     TAPState *s;
-    
+
     s = qemu_mallocz(sizeof(TAPState));
     if (!s)
         return -1;
@@ -670,7 +670,7 @@
     }
 
     s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s);
-    
+
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "tap: ifname=%s", ifname);
 
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
new file mode 100644
index 0000000..3f517e6
--- /dev/null
+++ b/target-alpha/cpu.h
@@ -0,0 +1,400 @@
+/*
+ *  Alpha emulation cpu definitions for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+#if !defined (__CPU_ALPHA_H__)
+#define __CPU_ALPHA_H__
+
+#include "config.h"
+
+#define TARGET_LONG_BITS 64
+
+#include "cpu-defs.h"
+
+
+#include <setjmp.h>
+
+#include "softfloat.h"
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE	EM_ALPHA
+
+#define ICACHE_LINE_SIZE 32
+#define DCACHE_LINE_SIZE 32
+
+#define TARGET_PAGE_BITS 12
+
+#define VA_BITS 43
+
+/* Alpha major type */
+enum {
+    ALPHA_EV3  = 1,
+    ALPHA_EV4  = 2,
+    ALPHA_SIM  = 3,
+    ALPHA_LCA  = 4,
+    ALPHA_EV5  = 5, /* 21164 */
+    ALPHA_EV45 = 6, /* 21064A */
+    ALPHA_EV56 = 7, /* 21164A */
+};
+
+/* EV4 minor type */
+enum {
+    ALPHA_EV4_2 = 0,
+    ALPHA_EV4_3 = 1,
+};
+
+/* LCA minor type */
+enum {
+    ALPHA_LCA_1 = 1, /* 21066 */
+    ALPHA_LCA_2 = 2, /* 20166 */
+    ALPHA_LCA_3 = 3, /* 21068 */
+    ALPHA_LCA_4 = 4, /* 21068 */
+    ALPHA_LCA_5 = 5, /* 21066A */
+    ALPHA_LCA_6 = 6, /* 21068A */
+};
+
+/* EV5 minor type */
+enum {
+    ALPHA_EV5_1 = 1, /* Rev BA, CA */
+    ALPHA_EV5_2 = 2, /* Rev DA, EA */
+    ALPHA_EV5_3 = 3, /* Pass 3 */
+    ALPHA_EV5_4 = 4, /* Pass 3.2 */
+    ALPHA_EV5_5 = 5, /* Pass 4 */
+};
+
+/* EV45 minor type */
+enum {
+    ALPHA_EV45_1 = 1, /* Pass 1 */
+    ALPHA_EV45_2 = 2, /* Pass 1.1 */
+    ALPHA_EV45_3 = 3, /* Pass 2 */
+};
+
+/* EV56 minor type */
+enum {
+    ALPHA_EV56_1 = 1, /* Pass 1 */
+    ALPHA_EV56_2 = 2, /* Pass 2 */
+};
+
+enum {
+    IMPLVER_2106x = 0, /* EV4, EV45 & LCA45 */
+    IMPLVER_21164 = 1, /* EV5, EV56 & PCA45 */
+    IMPLVER_21264 = 2, /* EV6, EV67 & EV68x */
+    IMPLVER_21364 = 3, /* EV7 & EV79 */
+};
+
+enum {
+    AMASK_BWX      = 0x00000001,
+    AMASK_FIX      = 0x00000002,
+    AMASK_CIX      = 0x00000004,
+    AMASK_MVI      = 0x00000100,
+    AMASK_TRAP     = 0x00000200,
+    AMASK_PREFETCH = 0x00001000,
+};
+
+enum {
+    VAX_ROUND_NORMAL = 0,
+    VAX_ROUND_CHOPPED,
+};
+
+enum {
+    IEEE_ROUND_NORMAL = 0,
+    IEEE_ROUND_DYNAMIC,
+    IEEE_ROUND_PLUS,
+    IEEE_ROUND_MINUS,
+    IEEE_ROUND_CHOPPED,
+};
+
+/* IEEE floating-point operations encoding */
+/* Trap mode */
+enum {
+    FP_TRAP_I   = 0x0,
+    FP_TRAP_U   = 0x1,
+    FP_TRAP_S  = 0x4,
+    FP_TRAP_SU  = 0x5,
+    FP_TRAP_SUI = 0x7,
+};
+
+/* Rounding mode */
+enum {
+    FP_ROUND_CHOPPED = 0x0,
+    FP_ROUND_MINUS   = 0x1,
+    FP_ROUND_NORMAL  = 0x2,
+    FP_ROUND_DYNAMIC = 0x3,
+};
+
+/* Internal processor registers */
+/* XXX: TOFIX: most of those registers are implementation dependant */
+enum {
+    /* Ebox IPRs */
+    IPR_CC           = 0xC0,
+    IPR_CC_CTL       = 0xC1,
+    IPR_VA           = 0xC2,
+    IPR_VA_CTL       = 0xC4,
+    IPR_VA_FORM      = 0xC3,
+    /* Ibox IPRs */
+    IPR_ITB_TAG      = 0x00,
+    IPR_ITB_PTE      = 0x01,
+    IPT_ITB_IAP      = 0x02,
+    IPT_ITB_IA       = 0x03,
+    IPT_ITB_IS       = 0x04,
+    IPR_PMPC         = 0x05,
+    IPR_EXC_ADDR     = 0x06,
+    IPR_IVA_FORM     = 0x07,
+    IPR_CM           = 0x09,
+    IPR_IER          = 0x0A,
+    IPR_SIRR         = 0x0C,
+    IPR_ISUM         = 0x0D,
+    IPR_HW_INT_CLR   = 0x0E,
+    IPR_EXC_SUM      = 0x0F,
+    IPR_PAL_BASE     = 0x10,
+    IPR_I_CTL        = 0x11,
+    IPR_I_STAT       = 0x16,
+    IPR_IC_FLUSH     = 0x13,
+    IPR_IC_FLUSH_ASM = 0x12,
+    IPR_CLR_MAP      = 0x15,
+    IPR_SLEEP        = 0x17,
+    IPR_PCTX         = 0x40,
+    IPR_PCTR_CTL     = 0x14,
+    /* Mbox IPRs */
+    IPR_DTB_TAG0     = 0x20,
+    IPR_DTB_TAG1     = 0xA0,
+    IPR_DTB_PTE0     = 0x21,
+    IPR_DTB_PTE1     = 0xA1,
+    IPR_DTB_ALTMODE  = 0xA6,
+    IPR_DTB_IAP      = 0xA2,
+    IPR_DTB_IA       = 0xA3,
+    IPR_DTB_IS0      = 0x24,
+    IPR_DTB_IS1      = 0xA4,
+    IPR_DTB_ASN0     = 0x25,
+    IPR_DTB_ASN1     = 0xA5,
+    IPR_MM_STAT      = 0x27,
+    IPR_M_CTL        = 0x28,
+    IPR_DC_CTL       = 0x29,
+    IPR_DC_STAT      = 0x2A,
+    /* Cbox IPRs */
+    IPR_C_DATA       = 0x2B,
+    IPR_C_SHIFT      = 0x2C,
+
+    IPR_ASN,
+    IPR_ASTEN,
+    IPR_ASTSR,
+    IPR_DATFX,
+    IPR_ESP,
+    IPR_FEN,
+    IPR_IPIR,
+    IPR_IPL,
+    IPR_KSP,
+    IPR_MCES,
+    IPR_PERFMON,
+    IPR_PCBB,
+    IPR_PRBR,
+    IPR_PTBR,
+    IPR_SCBB,
+    IPR_SISR,
+    IPR_SSP,
+    IPR_SYSPTBR,
+    IPR_TBCHK,
+    IPR_TBIA,
+    IPR_TBIAP,
+    IPR_TBIS,
+    IPR_TBISD,
+    IPR_TBISI,
+    IPR_USP,
+    IPR_VIRBND,
+    IPR_VPTB,
+    IPR_WHAMI,
+    IPR_ALT_MODE,
+    IPR_LAST,
+};
+
+typedef struct CPUAlphaState CPUAlphaState;
+
+typedef struct pal_handler_t pal_handler_t;
+struct pal_handler_t {
+    /* Reset */
+    void (*reset)(CPUAlphaState *env);
+    /* Uncorrectable hardware error */
+    void (*machine_check)(CPUAlphaState *env);
+    /* Arithmetic exception */
+    void (*arithmetic)(CPUAlphaState *env);
+    /* Interrupt / correctable hardware error */
+    void (*interrupt)(CPUAlphaState *env);
+    /* Data fault */
+    void (*dfault)(CPUAlphaState *env);
+    /* DTB miss pal */
+    void (*dtb_miss_pal)(CPUAlphaState *env);
+    /* DTB miss native */
+    void (*dtb_miss_native)(CPUAlphaState *env);
+    /* Unaligned access */
+    void (*unalign)(CPUAlphaState *env);
+    /* ITB miss */
+    void (*itb_miss)(CPUAlphaState *env);
+    /* Instruction stream access violation */
+    void (*itb_acv)(CPUAlphaState *env);
+    /* Reserved or privileged opcode */
+    void (*opcdec)(CPUAlphaState *env);
+    /* Floating point exception */
+    void (*fen)(CPUAlphaState *env);
+    /* Call pal instruction */
+    void (*call_pal)(CPUAlphaState *env, uint32_t palcode);
+};
+
+struct CPUAlphaState {
+    uint64_t ir[31];
+    float64  fir[31];
+    float_status fp_status;
+    uint64_t fpcr;
+    uint64_t pc;
+    uint64_t lock;
+    uint32_t pcc[2];
+    uint64_t ipr[IPR_LAST];
+    uint64_t ps;
+    uint64_t unique;
+    int saved_mode; /* Used for HW_LD / HW_ST */
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+    /* temporary fixed-point registers
+     * used to emulate 64 bits target on 32 bits hosts
+     */
+    target_ulong t0, t1, t2;
+#endif
+    /* */
+    double ft0, ft1, ft2;
+
+    /* Those resources are used only in Qemu core */
+    CPU_COMMON
+
+    jmp_buf jmp_env;
+    int user_mode_only; /* user mode only simulation */
+    uint32_t hflags;
+    int halted;
+
+    int exception_index;
+    int error_code;
+    int interrupt_request;
+
+    uint32_t features;
+    uint32_t amask;
+    int implver;
+    pal_handler_t *pal_handler;
+};
+
+#define CPUState CPUAlphaState
+#define cpu_init cpu_alpha_init
+#define cpu_exec cpu_alpha_exec
+#define cpu_gen_code cpu_alpha_gen_code
+#define cpu_signal_handler cpu_alpha_signal_handler
+
+#include "cpu-all.h"
+
+enum {
+    FEATURE_ASN    = 0x00000001,
+    FEATURE_SPS    = 0x00000002,
+    FEATURE_VIRBND = 0x00000004,
+    FEATURE_TBCHK  = 0x00000008,
+};
+
+enum {
+    EXCP_RESET            = 0x0000,
+    EXCP_MCHK             = 0x0020,
+    EXCP_ARITH            = 0x0060,
+    EXCP_HW_INTERRUPT     = 0x00E0,
+    EXCP_DFAULT           = 0x01E0,
+    EXCP_DTB_MISS_PAL     = 0x09E0,
+    EXCP_ITB_MISS         = 0x03E0,
+    EXCP_ITB_ACV          = 0x07E0,
+    EXCP_DTB_MISS_NATIVE  = 0x08E0,
+    EXCP_UNALIGN          = 0x11E0,
+    EXCP_OPCDEC           = 0x13E0,
+    EXCP_FEN              = 0x17E0,
+    EXCP_CALL_PAL         = 0x2000,
+    EXCP_CALL_PALP        = 0x3000,
+    EXCP_CALL_PALE        = 0x4000,
+    /* Pseudo exception for console */
+    EXCP_CONSOLE_DISPATCH = 0x4001,
+    EXCP_CONSOLE_FIXUP    = 0x4002,
+};
+
+/* Arithmetic exception */
+enum {
+    EXCP_ARITH_OVERFLOW,
+};
+
+enum {
+    PALCODE_CALL = 0x00000000,
+    PALCODE_LD   = 0x01000000,
+    PALCODE_ST   = 0x02000000,
+    PALCODE_MFPR = 0x03000000,
+    PALCODE_MTPR = 0x04000000,
+    PALCODE_REI  = 0x05000000,
+    PALCODE_INIT = 0xF0000000,
+};
+
+enum {
+    IR_V0   = 0,
+    IR_T0   = 1,
+    IR_T1   = 2,
+    IR_T2   = 3,
+    IR_T3   = 4,
+    IR_T4   = 5,
+    IR_T5   = 6,
+    IR_T6   = 7,
+    IR_T7   = 8,
+    IR_S0   = 9,
+    IR_S1   = 10,
+    IR_S2   = 11,
+    IR_S3   = 12,
+    IR_S4   = 13,
+    IR_S5   = 14,
+    IR_S6   = 15,
+#define IR_FP IR_S6
+    IR_A0   = 16,
+    IR_A1   = 17,
+    IR_A2   = 18,
+    IR_A3   = 19,
+    IR_A4   = 20,
+    IR_A5   = 21,
+    IR_T8   = 22,
+    IR_T9   = 23,
+    IR_T10  = 24,
+    IR_T11  = 25,
+    IR_RA   = 26,
+    IR_T12  = 27,
+#define IR_PV IR_T12
+    IR_AT   = 28,
+    IR_GP   = 29,
+    IR_SP   = 30,
+    IR_ZERO = 31,
+};
+
+CPUAlphaState * cpu_alpha_init (void);
+int cpu_alpha_exec(CPUAlphaState *s);
+/* 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.  */
+int cpu_alpha_signal_handler(int host_signum, void *pinfo,
+                             void *puc);
+int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
+int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
+void cpu_loop_exit (void);
+void pal_init (CPUState *env);
+void call_pal (CPUState *env, int palcode);
+
+#endif /* !defined (__CPU_ALPHA_H__) */
diff --git a/target-alpha/exec.h b/target-alpha/exec.h
new file mode 100644
index 0000000..80f358c
--- /dev/null
+++ b/target-alpha/exec.h
@@ -0,0 +1,92 @@
+/*
+ *  Alpha emulation cpu run-time definitions for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+#if !defined (__ALPHA_EXEC_H__)
+#define __ALPHA_EXEC_H__
+
+#include "config.h"
+
+#include "dyngen-exec.h"
+
+#define TARGET_LONG_BITS 64
+
+register struct CPUAlphaState *env asm(AREG0);
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+
+/* no registers can be used */
+#define T0 (env->t0)
+#define T1 (env->t1)
+#define T2 (env->t2)
+
+#else
+
+register uint64_t T0 asm(AREG1);
+register uint64_t T1 asm(AREG2);
+register uint64_t T2 asm(AREG3);
+
+#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
+
+#define PARAM(n) ((uint64_t)PARAM##n)
+#define SPARAM(n) ((int32_t)PARAM##n)
+#define FT0 (env->ft0)
+#define FT1 (env->ft1)
+#define FT2 (env->ft2)
+#define FP_STATUS (env->fp_status)
+
+#if defined (DEBUG_OP)
+#define RETURN() __asm__ __volatile__("nop" : : : "memory");
+#else
+#define RETURN() __asm__ __volatile__("" : : : "memory");
+#endif
+
+#include "cpu.h"
+#include "exec-all.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+static inline void env_to_regs(void)
+{
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw,
+                                int is_user, int is_softmmu);
+int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
+int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
+
+void do_interrupt (CPUState *env);
+
+static inline int cpu_halted(CPUState *env) {
+    if (!env->halted)
+        return 0;
+    if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
+#endif /* !defined (__ALPHA_EXEC_H__) */
diff --git a/target-alpha/helper.c b/target-alpha/helper.c
new file mode 100644
index 0000000..72cae49
--- /dev/null
+++ b/target-alpha/helper.c
@@ -0,0 +1,454 @@
+/*
+ *  Alpha emulation cpu helpers for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                                int is_user, int is_softmmu)
+{
+    if (rw == 2)
+        env->exception_index = EXCP_ITB_MISS;
+    else
+        env->exception_index = EXCP_DFAULT;
+    env->ipr[IPR_EXC_ADDR] = address;
+
+    return 1;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+{
+    return addr;
+}
+
+void do_interrupt (CPUState *env)
+{
+    env->exception_index = -1;
+}
+
+#else
+
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+{
+    return -1;
+}
+
+int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+                                int is_user, int is_softmmu)
+{
+    uint32_t opc;
+
+    if (rw == 2) {
+        /* Instruction translation buffer miss */
+        env->exception_index = EXCP_ITB_MISS;
+    } else {
+        if (env->ipr[IPR_EXC_ADDR] & 1)
+            env->exception_index = EXCP_DTB_MISS_PAL;
+        else
+            env->exception_index = EXCP_DTB_MISS_NATIVE;
+        opc = (ldl_code(env->pc) >> 21) << 4;
+        if (rw) {
+            opc |= 0x9;
+        } else {
+            opc |= 0x4;
+        }
+        env->ipr[IPR_MM_STAT] = opc;
+    }
+
+    return 1;
+}
+
+int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
+{
+    uint64_t hwpcb;
+    int ret = 0;
+
+    hwpcb = env->ipr[IPR_PCBB];
+    switch (iprn) {
+    case IPR_ASN:
+        if (env->features & FEATURE_ASN)
+            *valp = env->ipr[IPR_ASN];
+        else
+            *valp = 0;
+        break;
+    case IPR_ASTEN:
+        *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
+        break;
+    case IPR_ASTSR:
+        *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
+        break;
+    case IPR_DATFX:
+        /* Write only */
+        ret = -1;
+        break;
+    case IPR_ESP:
+        if (env->features & FEATURE_SPS)
+            *valp = env->ipr[IPR_ESP];
+        else
+            *valp = ldq_raw(hwpcb + 8);
+        break;
+    case IPR_FEN:
+        *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
+        break;
+    case IPR_IPIR:
+        /* Write-only */
+        ret = -1;
+        break;
+    case IPR_IPL:
+        *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
+        break;
+    case IPR_KSP:
+        if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
+            ret = -1;
+        } else {
+            if (env->features & FEATURE_SPS)
+                *valp = env->ipr[IPR_KSP];
+            else
+                *valp = ldq_raw(hwpcb + 0);
+        }
+        break;
+    case IPR_MCES:
+        *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
+        break;
+    case IPR_PERFMON:
+        /* Implementation specific */
+        *valp = 0;
+        break;
+    case IPR_PCBB:
+        *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
+        break;
+    case IPR_PRBR:
+        *valp = env->ipr[IPR_PRBR];
+        break;
+    case IPR_PTBR:
+        *valp = env->ipr[IPR_PTBR];
+        break;
+    case IPR_SCBB:
+        *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
+        break;
+    case IPR_SIRR:
+        /* Write-only */
+        ret = -1;
+        break;
+    case IPR_SISR:
+        *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
+    case IPR_SSP:
+        if (env->features & FEATURE_SPS)
+            *valp = env->ipr[IPR_SSP];
+        else
+            *valp = ldq_raw(hwpcb + 16);
+        break;
+    case IPR_SYSPTBR:
+        if (env->features & FEATURE_VIRBND)
+            *valp = env->ipr[IPR_SYSPTBR];
+        else
+            ret = -1;
+        break;
+    case IPR_TBCHK:
+        if ((env->features & FEATURE_TBCHK)) {
+            /* XXX: TODO */
+            *valp = 0;
+            ret = -1;
+        } else {
+            ret = -1;
+        }
+        break;
+    case IPR_TBIA:
+        /* Write-only */
+        ret = -1;
+        break;
+    case IPR_TBIAP:
+        /* Write-only */
+        ret = -1;
+        break;
+    case IPR_TBIS:
+        /* Write-only */
+        ret = -1;
+        break;
+    case IPR_TBISD:
+        /* Write-only */
+        ret = -1;
+        break;
+    case IPR_TBISI:
+        /* Write-only */
+        ret = -1;
+        break;
+    case IPR_USP:
+        if (env->features & FEATURE_SPS)
+            *valp = env->ipr[IPR_USP];
+        else
+            *valp = ldq_raw(hwpcb + 24);
+        break;
+    case IPR_VIRBND:
+        if (env->features & FEATURE_VIRBND)
+            *valp = env->ipr[IPR_VIRBND];
+        else
+            ret = -1;
+        break;
+    case IPR_VPTB:
+        *valp = env->ipr[IPR_VPTB];
+        break;
+    case IPR_WHAMI:
+        *valp = env->ipr[IPR_WHAMI];
+        break;
+    default:
+        /* Invalid */
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
+int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
+{
+    uint64_t hwpcb, tmp64;
+    uint8_t tmp8;
+    int ret = 0;
+
+    hwpcb = env->ipr[IPR_PCBB];
+    switch (iprn) {
+    case IPR_ASN:
+        /* Read-only */
+        ret = -1;
+        break;
+    case IPR_ASTEN:
+        tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
+        *oldvalp = tmp8;
+        tmp8 &= val & 0xF;
+        tmp8 |= (val >> 4) & 0xF;
+        env->ipr[IPR_ASTEN] &= ~0xF;
+        env->ipr[IPR_ASTEN] |= tmp8;
+        ret = 1;
+        break;
+    case IPR_ASTSR:
+        tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
+        *oldvalp = tmp8;
+        tmp8 &= val & 0xF;
+        tmp8 |= (val >> 4) & 0xF;
+        env->ipr[IPR_ASTSR] &= ~0xF;
+        env->ipr[IPR_ASTSR] |= tmp8;
+        ret = 1;
+    case IPR_DATFX:
+        env->ipr[IPR_DATFX] &= ~0x1;
+        env->ipr[IPR_DATFX] |= val & 1;
+        tmp64 = ldq_raw(hwpcb + 56);
+        tmp64 &= ~0x8000000000000000ULL;
+        tmp64 |= (val & 1) << 63;
+        stq_raw(hwpcb + 56, tmp64);
+        break;
+    case IPR_ESP:
+        if (env->features & FEATURE_SPS)
+            env->ipr[IPR_ESP] = val;
+        else
+            stq_raw(hwpcb + 8, val);
+        break;
+    case IPR_FEN:
+        env->ipr[IPR_FEN] = val & 1;
+        tmp64 = ldq_raw(hwpcb + 56);
+        tmp64 &= ~1;
+        tmp64 |= val & 1;
+        stq_raw(hwpcb + 56, tmp64);
+        break;
+    case IPR_IPIR:
+        /* XXX: TODO: Send IRQ to CPU #ir[16] */
+        break;
+    case IPR_IPL:
+        *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
+        env->ipr[IPR_IPL] &= ~0x1F;
+        env->ipr[IPR_IPL] |= val & 0x1F;
+        /* XXX: may issue an interrupt or ASR _now_ */
+        ret = 1;
+        break;
+    case IPR_KSP:
+        if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
+            ret = -1;
+        } else {
+            if (env->features & FEATURE_SPS)
+                env->ipr[IPR_KSP] = val;
+            else
+                stq_raw(hwpcb + 0, val);
+        }
+        break;
+    case IPR_MCES:
+        env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
+        env->ipr[IPR_MCES] |= val & 0x18;
+        break;
+    case IPR_PERFMON:
+        /* Implementation specific */
+        *oldvalp = 0;
+        ret = 1;
+        break;
+    case IPR_PCBB:
+        /* Read-only */
+        ret = -1;
+        break;
+    case IPR_PRBR:
+        env->ipr[IPR_PRBR] = val;
+        break;
+    case IPR_PTBR:
+        /* Read-only */
+        ret = -1;
+        break;
+    case IPR_SCBB:
+        env->ipr[IPR_SCBB] = (uint32_t)val;
+        break;
+    case IPR_SIRR:
+        if (val & 0xF) {
+            env->ipr[IPR_SISR] |= 1 << (val & 0xF);
+            /* XXX: request a software interrupt _now_ */
+        }
+        break;
+    case IPR_SISR:
+        /* Read-only */
+        ret = -1;
+        break;
+    case IPR_SSP:
+        if (env->features & FEATURE_SPS)
+            env->ipr[IPR_SSP] = val;
+        else
+            stq_raw(hwpcb + 16, val);
+        break;
+    case IPR_SYSPTBR:
+        if (env->features & FEATURE_VIRBND)
+            env->ipr[IPR_SYSPTBR] = val;
+        else
+            ret = -1;
+    case IPR_TBCHK:
+        /* Read-only */
+        ret = -1;
+        break;
+    case IPR_TBIA:
+        tlb_flush(env, 1);
+        break;
+    case IPR_TBIAP:
+        tlb_flush(env, 1);
+        break;
+    case IPR_TBIS:
+        tlb_flush_page(env, val);
+        break;
+    case IPR_TBISD:
+        tlb_flush_page(env, val);
+        break;
+    case IPR_TBISI:
+        tlb_flush_page(env, val);
+        break;
+    case IPR_USP:
+        if (env->features & FEATURE_SPS)
+            env->ipr[IPR_USP] = val;
+        else
+            stq_raw(hwpcb + 24, val);
+        break;
+    case IPR_VIRBND:
+        if (env->features & FEATURE_VIRBND)
+            env->ipr[IPR_VIRBND] = val;
+        else
+            ret = -1;
+        break;
+    case IPR_VPTB:
+        env->ipr[IPR_VPTB] = val;
+        break;
+    case IPR_WHAMI:
+        /* Read-only */
+        ret = -1;
+        break;
+    default:
+        /* Invalid */
+        ret = -1;
+        break;
+    }
+
+    return ret;
+}
+
+void do_interrupt (CPUState *env)
+{
+    int excp;
+
+    env->ipr[IPR_EXC_ADDR] = env->pc | 1;
+    excp = env->exception_index;
+    env->exception_index = 0;
+    env->error_code = 0;
+    /* XXX: disable interrupts and memory mapping */
+    if (env->ipr[IPR_PAL_BASE] != -1ULL) {
+        /* We use native PALcode */
+        env->pc = env->ipr[IPR_PAL_BASE] + excp;
+    } else {
+        /* We use emulated PALcode */
+        call_pal(env);
+        /* Emulate REI */
+        env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
+        env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
+        /* XXX: re-enable interrupts and memory mapping */
+    }
+}
+#endif
+
+void cpu_dump_state (CPUState *env, FILE *f,
+                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                     int flags)
+{
+    static unsigned char *linux_reg_names[] = {
+        "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
+        "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
+        "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
+        "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
+    };
+    int i;
+
+    cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  " TARGET_FMT_lx "\n",
+                env->pc, env->ps);
+    for (i = 0; i < 31; i++) {
+        cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
+                    linux_reg_names[i], env->ir[i]);
+        if ((i % 3) == 2)
+            cpu_fprintf(f, "\n");
+    }
+    cpu_fprintf(f, "\n");
+    for (i = 0; i < 31; i++) {
+        cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
+                    *((uint64_t *)(&env->fir[i])));
+        if ((i % 3) == 2)
+            cpu_fprintf(f, "\n");
+    }
+    cpu_fprintf(f, "FT " TARGET_FMT_lx " " TARGET_FMT_lx " " TARGET_FMT_lx,
+                *((uint64_t *)(&env->ft0)), *((uint64_t *)(&env->ft1)),
+                *((uint64_t *)(&env->ft2)));
+    cpu_fprintf(f, "\nMEM " TARGET_FMT_lx " %d %d\n",
+                ldq_raw(0x000000004007df60ULL),
+                (uint8_t *)(&env->ft0), (uint8_t *)(&env->fir[0]));
+}
+
+void cpu_dump_EA (target_ulong EA)
+{
+    FILE *f;
+
+    if (logfile)
+        f = logfile;
+    else
+        f = stdout;
+    fprintf(f, "Memory access at address " TARGET_FMT_lx "\n", EA);
+}
diff --git a/target-alpha/op.c b/target-alpha/op.c
new file mode 100644
index 0000000..529a66d
--- /dev/null
+++ b/target-alpha/op.c
@@ -0,0 +1,1103 @@
+/*
+ *  Alpha emulation cpu micro-operations for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+#define DEBUG_OP
+
+#include "config.h"
+#include "exec.h"
+
+#include "op_helper.h"
+
+#define REG 0
+#include "op_template.h"
+
+#define REG 1
+#include "op_template.h"
+
+#define REG 2
+#include "op_template.h"
+
+#define REG 3
+#include "op_template.h"
+
+#define REG 4
+#include "op_template.h"
+
+#define REG 5
+#include "op_template.h"
+
+#define REG 6
+#include "op_template.h"
+
+#define REG 7
+#include "op_template.h"
+
+#define REG 8
+#include "op_template.h"
+
+#define REG 9
+#include "op_template.h"
+
+#define REG 10
+#include "op_template.h"
+
+#define REG 11
+#include "op_template.h"
+
+#define REG 12
+#include "op_template.h"
+
+#define REG 13
+#include "op_template.h"
+
+#define REG 14
+#include "op_template.h"
+
+#define REG 15
+#include "op_template.h"
+
+#define REG 16
+#include "op_template.h"
+
+#define REG 17
+#include "op_template.h"
+
+#define REG 18
+#include "op_template.h"
+
+#define REG 19
+#include "op_template.h"
+
+#define REG 20
+#include "op_template.h"
+
+#define REG 21
+#include "op_template.h"
+
+#define REG 22
+#include "op_template.h"
+
+#define REG 23
+#include "op_template.h"
+
+#define REG 24
+#include "op_template.h"
+
+#define REG 25
+#include "op_template.h"
+
+#define REG 26
+#include "op_template.h"
+
+#define REG 27
+#include "op_template.h"
+
+#define REG 28
+#include "op_template.h"
+
+#define REG 29
+#include "op_template.h"
+
+#define REG 30
+#include "op_template.h"
+
+#define REG 31
+#include "op_template.h"
+
+/* Debug stuff */
+void OPPROTO op_no_op (void)
+{
+#if !defined (DEBUG_OP)
+    __asm__ __volatile__("nop" : : : "memory");
+#endif
+    RETURN();
+}
+
+void OPPROTO op_tb_flush (void)
+{
+    helper_tb_flush();
+    RETURN();
+}
+
+/* Load and stores */
+#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"
+/* Those are used for supervisor, executive and pal modes */
+#define MEMSUFFIX _data
+#include "op_mem.h"
+#endif
+
+/* Special operation for load and store */
+void OPPROTO op_n7 (void)
+{
+    T0 &= ~(uint64_t)0x7;
+    RETURN();
+}
+
+/* Misc */
+void OPPROTO op_excp (void)
+{
+    helper_excp(PARAM(1), PARAM(2));
+    RETURN();
+}
+
+void OPPROTO op_load_amask (void)
+{
+    helper_amask();
+    RETURN();
+}
+
+void OPPROTO op_load_pcc (void)
+{
+    helper_load_pcc();
+    RETURN();
+}
+
+void OPPROTO op_load_implver (void)
+{
+    helper_load_implver();
+    RETURN();
+}
+
+void OPPROTO op_load_fpcr (void)
+{
+    helper_load_fpcr();
+    RETURN();
+}
+
+void OPPROTO op_store_fpcr (void)
+{
+    helper_store_fpcr();
+    RETURN();
+}
+
+void OPPROTO op_load_irf (void)
+{
+    helper_load_irf();
+    RETURN();
+}
+
+void OPPROTO op_set_irf (void)
+{
+    helper_set_irf();
+    RETURN();
+}
+
+void OPPROTO op_clear_irf (void)
+{
+    helper_clear_irf();
+    RETURN();
+}
+
+void OPPROTO op_exit_tb (void)
+{
+    EXIT_TB();
+}
+
+/* Arithmetic */
+void OPPROTO op_addq (void)
+{
+    T0 += T1;
+    RETURN();
+}
+
+void OPPROTO op_addqv (void)
+{
+    helper_addqv();
+    RETURN();
+}
+
+void OPPROTO op_addl (void)
+{
+    T0 = (int64_t)((int32_t)(T0 + T1));
+    RETURN();
+}
+
+void OPPROTO op_addlv (void)
+{
+    helper_addlv();
+    RETURN();
+}
+
+void OPPROTO op_subq (void)
+{
+    T0 -= T1;
+    RETURN();
+}
+
+void OPPROTO op_subqv (void)
+{
+    helper_subqv();
+    RETURN();
+}
+
+void OPPROTO op_subl (void)
+{
+    T0 = (int64_t)((int32_t)(T0 - T1));
+    RETURN();
+}
+
+void OPPROTO op_sublv (void)
+{
+    helper_sublv();
+    RETURN();
+}
+
+void OPPROTO op_s4 (void)
+{
+    T0 <<= 2;
+    RETURN();
+}
+
+void OPPROTO op_s8 (void)
+{
+    T0 <<= 3;
+    RETURN();
+}
+
+void OPPROTO op_mull (void)
+{
+    T0 = (int64_t)((int32_t)T0 * (int32_t)T1);
+    RETURN();
+}
+
+void OPPROTO op_mullv (void)
+{
+    helper_mullv();
+    RETURN();
+}
+
+void OPPROTO op_mulq (void)
+{
+    T0 *= T1;
+    RETURN();
+}
+
+void OPPROTO op_mulqv (void)
+{
+    helper_mulqv();
+    RETURN();
+}
+
+void OPPROTO op_umulh (void)
+{
+    helper_umulh();
+    RETURN();
+}
+
+/* Logical */
+void OPPROTO op_and (void)
+{
+    T0 &= T1;
+    RETURN();
+}
+
+void OPPROTO op_bic (void)
+{
+    T0 &= ~T1;
+    RETURN();
+}
+
+void OPPROTO op_bis (void)
+{
+    T0 |= T1;
+    RETURN();
+}
+
+void OPPROTO op_eqv (void)
+{
+    T0 ^= ~T1;
+    RETURN();
+}
+
+void OPPROTO op_ornot (void)
+{
+    T0 |= ~T1;
+    RETURN();
+}
+
+void OPPROTO op_xor (void)
+{
+    T0 ^= T1;
+    RETURN();
+}
+
+void OPPROTO op_sll (void)
+{
+    T0 <<= T1;
+    RETURN();
+}
+
+void OPPROTO op_srl (void)
+{
+    T0 >>= T1;
+    RETURN();
+}
+
+void OPPROTO op_sra (void)
+{
+    T0 = (int64_t)T0 >> T1;
+    RETURN();
+}
+
+void OPPROTO op_sextb (void)
+{
+    T0 = (int64_t)((int8_t)T0);
+    RETURN();
+}
+
+void OPPROTO op_sextw (void)
+{
+    T0 = (int64_t)((int16_t)T0);
+    RETURN();
+
+}
+
+void OPPROTO op_ctpop (void)
+{
+    helper_ctpop();
+    RETURN();
+}
+
+void OPPROTO op_ctlz (void)
+{
+    helper_ctlz();
+    RETURN();
+}
+
+void OPPROTO op_cttz (void)
+{
+    helper_cttz();
+    RETURN();
+}
+
+void OPPROTO op_mskbl (void)
+{
+    helper_mskbl();
+    RETURN();
+}
+
+void OPPROTO op_extbl (void)
+{
+    helper_extbl();
+    RETURN();
+}
+
+void OPPROTO op_insbl (void)
+{
+    helper_insbl();
+    RETURN();
+}
+
+void OPPROTO op_mskwl (void)
+{
+    helper_mskwl();
+    RETURN();
+}
+
+void OPPROTO op_extwl (void)
+{
+    helper_extwl();
+    RETURN();
+}
+
+void OPPROTO op_inswl (void)
+{
+    helper_inswl();
+    RETURN();
+}
+
+void OPPROTO op_mskll (void)
+{
+    helper_mskll();
+    RETURN();
+}
+
+void OPPROTO op_extll (void)
+{
+    helper_extll();
+    RETURN();
+}
+
+void OPPROTO op_insll (void)
+{
+    helper_insll();
+    RETURN();
+}
+
+void OPPROTO op_zap (void)
+{
+    helper_zap();
+    RETURN();
+}
+
+void OPPROTO op_zapnot (void)
+{
+    helper_zapnot();
+    RETURN();
+}
+
+void OPPROTO op_mskql (void)
+{
+    helper_mskql();
+    RETURN();
+}
+
+void OPPROTO op_extql (void)
+{
+    helper_extql();
+    RETURN();
+}
+
+void OPPROTO op_insql (void)
+{
+    helper_insql();
+    RETURN();
+}
+
+void OPPROTO op_mskwh (void)
+{
+    helper_mskwh();
+    RETURN();
+}
+
+void OPPROTO op_inswh (void)
+{
+    helper_inswh();
+    RETURN();
+}
+
+void OPPROTO op_extwh (void)
+{
+    helper_extwh();
+    RETURN();
+}
+
+void OPPROTO op_msklh (void)
+{
+    helper_msklh();
+    RETURN();
+}
+
+void OPPROTO op_inslh (void)
+{
+    helper_inslh();
+    RETURN();
+}
+
+void OPPROTO op_extlh (void)
+{
+    helper_extlh();
+    RETURN();
+}
+
+void OPPROTO op_mskqh (void)
+{
+    helper_mskqh();
+    RETURN();
+}
+
+void OPPROTO op_insqh (void)
+{
+    helper_insqh();
+    RETURN();
+}
+
+void OPPROTO op_extqh (void)
+{
+    helper_extqh();
+    RETURN();
+}
+
+/* Tests */
+void OPPROTO op_cmpult (void)
+{
+    if (T0 < T1)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmpule (void)
+{
+    if (T0 <= T1)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmpeq (void)
+{
+    if (T0 == T1)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmplt (void)
+{
+    if ((int64_t)T0 < (int64_t)T1)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmple (void)
+{
+    if ((int64_t)T0 <= (int64_t)T1)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmpbge (void)
+{
+    helper_cmpbge();
+    RETURN();
+}
+
+void OPPROTO op_cmpeqz (void)
+{
+    if (T0 == 0)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmpnez (void)
+{
+    if (T0 != 0)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmpltz (void)
+{
+    if ((int64_t)T0 < 0)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmplez (void)
+{
+    if ((int64_t)T0 <= 0)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmpgtz (void)
+{
+    if ((int64_t)T0 > 0)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmpgez (void)
+{
+    if ((int64_t)T0 >= 0)
+        T0 = 1;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_cmplbs (void)
+{
+    T0 &= 1;
+    RETURN();
+}
+
+void OPPROTO op_cmplbc (void)
+{
+    T0 = (~T0) & 1;
+    RETURN();
+}
+
+/* Branches */
+void OPPROTO op_branch (void)
+{
+    env->pc = T0 & ~3;
+    RETURN();
+}
+
+void OPPROTO op_addq1 (void)
+{
+    T1 += T0;
+    RETURN();
+}
+
+#if 0 // Qemu does not know how to do this...
+void OPPROTO op_bcond (void)
+{
+    if (T0)
+        env->pc = T1 & ~3;
+    else
+        env->pc = PARAM(1);
+    RETURN();
+}
+#else
+void OPPROTO op_bcond (void)
+{
+    if (T0)
+        env->pc = T1 & ~3;
+    else
+        env->pc = ((uint64_t)PARAM(1) << 32) | (uint64_t)PARAM(2);
+    RETURN();
+}
+#endif
+
+#if 0 // Qemu does not know how to do this...
+void OPPROTO op_update_pc (void)
+{
+    env->pc = PARAM(1);
+    RETURN();
+}
+#else
+void OPPROTO op_update_pc (void)
+{
+    env->pc = ((uint64_t)PARAM(1) << 32) | (uint64_t)PARAM(2);
+    RETURN();
+}
+#endif
+
+/* Optimization for 32 bits hosts architectures */
+void OPPROTO op_update_pc32 (void)
+{
+    env->pc = (uint64_t)PARAM(1);
+    RETURN();
+}
+
+/* IEEE floating point arithmetic */
+/* S floating (single) */
+void OPPROTO op_adds (void)
+{
+    FT0 = float32_add(FT0, FT1, &FP_STATUS);
+    RETURN();
+}
+
+void OPPROTO op_subs (void)
+{
+    FT0 = float32_sub(FT0, FT1, &FP_STATUS);
+    RETURN();
+}
+
+void OPPROTO op_muls (void)
+{
+    FT0 = float32_mul(FT0, FT1, &FP_STATUS);
+    RETURN();
+}
+
+void OPPROTO op_divs (void)
+{
+    FT0 = float32_div(FT0, FT1, &FP_STATUS);
+    RETURN();
+}
+
+void OPPROTO op_sqrts (void)
+{
+    helper_sqrts();
+    RETURN();
+}
+
+void OPPROTO op_cpys (void)
+{
+    helper_cpys();
+    RETURN();
+}
+
+void OPPROTO op_cpysn (void)
+{
+    helper_cpysn();
+    RETURN();
+}
+
+void OPPROTO op_cpyse (void)
+{
+    helper_cpyse();
+    RETURN();
+}
+
+void OPPROTO op_itofs (void)
+{
+    helper_itofs();
+    RETURN();
+}
+
+void OPPROTO op_ftois (void)
+{
+    helper_ftois();
+    RETURN();
+}
+
+/* T floating (double) */
+void OPPROTO op_addt (void)
+{
+    FT0 = float64_add(FT0, FT1, &FP_STATUS);
+    RETURN();
+}
+
+void OPPROTO op_subt (void)
+{
+    FT0 = float64_sub(FT0, FT1, &FP_STATUS);
+    RETURN();
+}
+
+void OPPROTO op_mult (void)
+{
+    FT0 = float64_mul(FT0, FT1, &FP_STATUS);
+    RETURN();
+}
+
+void OPPROTO op_divt (void)
+{
+    FT0 = float64_div(FT0, FT1, &FP_STATUS);
+    RETURN();
+}
+
+void OPPROTO op_sqrtt (void)
+{
+    helper_sqrtt();
+    RETURN();
+}
+
+void OPPROTO op_cmptun (void)
+{
+    helper_cmptun();
+    RETURN();
+}
+
+void OPPROTO op_cmpteq (void)
+{
+    helper_cmpteq();
+    RETURN();
+}
+
+void OPPROTO op_cmptle (void)
+{
+    helper_cmptle();
+    RETURN();
+}
+
+void OPPROTO op_cmptlt (void)
+{
+    helper_cmptlt();
+    RETURN();
+}
+
+void OPPROTO op_itoft (void)
+{
+    helper_itoft();
+    RETURN();
+}
+
+void OPPROTO op_ftoit (void)
+{
+    helper_ftoit();
+    RETURN();
+}
+
+/* VAX floating point arithmetic */
+/* F floating */
+void OPPROTO op_addf (void)
+{
+    helper_addf();
+    RETURN();
+}
+
+void OPPROTO op_subf (void)
+{
+    helper_subf();
+    RETURN();
+}
+
+void OPPROTO op_mulf (void)
+{
+    helper_mulf();
+    RETURN();
+}
+
+void OPPROTO op_divf (void)
+{
+    helper_divf();
+    RETURN();
+}
+
+void OPPROTO op_sqrtf (void)
+{
+    helper_sqrtf();
+    RETURN();
+}
+
+void OPPROTO op_cmpfeq (void)
+{
+    helper_cmpfeq();
+    RETURN();
+}
+
+void OPPROTO op_cmpfne (void)
+{
+    helper_cmpfne();
+    RETURN();
+}
+
+void OPPROTO op_cmpflt (void)
+{
+    helper_cmpflt();
+    RETURN();
+}
+
+void OPPROTO op_cmpfle (void)
+{
+    helper_cmpfle();
+    RETURN();
+}
+
+void OPPROTO op_cmpfgt (void)
+{
+    helper_cmpfgt();
+    RETURN();
+}
+
+void OPPROTO op_cmpfge (void)
+{
+    helper_cmpfge();
+    RETURN();
+}
+
+void OPPROTO op_itoff (void)
+{
+    helper_itoff();
+    RETURN();
+}
+
+/* G floating */
+void OPPROTO op_addg (void)
+{
+    helper_addg();
+    RETURN();
+}
+
+void OPPROTO op_subg (void)
+{
+    helper_subg();
+    RETURN();
+}
+
+void OPPROTO op_mulg (void)
+{
+    helper_mulg();
+    RETURN();
+}
+
+void OPPROTO op_divg (void)
+{
+    helper_divg();
+    RETURN();
+}
+
+void OPPROTO op_sqrtg (void)
+{
+    helper_sqrtg();
+    RETURN();
+}
+
+void OPPROTO op_cmpgeq (void)
+{
+    helper_cmpgeq();
+    RETURN();
+}
+
+void OPPROTO op_cmpglt (void)
+{
+    helper_cmpglt();
+    RETURN();
+}
+
+void OPPROTO op_cmpgle (void)
+{
+    helper_cmpgle();
+    RETURN();
+}
+
+/* Floating point format conversion */
+void OPPROTO op_cvtst (void)
+{
+    FT0 = (float)FT0;
+    RETURN();
+}
+
+void OPPROTO op_cvtqs (void)
+{
+    helper_cvtqs();
+    RETURN();
+}
+
+void OPPROTO op_cvtts (void)
+{
+    FT0 = (float)FT0;
+    RETURN();
+}
+
+void OPPROTO op_cvttq (void)
+{
+    helper_cvttq();
+    RETURN();
+}
+
+void OPPROTO op_cvtqt (void)
+{
+    helper_cvtqt();
+    RETURN();
+}
+
+void OPPROTO op_cvtqf (void)
+{
+    helper_cvtqf();
+    RETURN();
+}
+
+void OPPROTO op_cvtgf (void)
+{
+    helper_cvtgf();
+    RETURN();
+}
+
+void OPPROTO op_cvtgd (void)
+{
+    helper_cvtgd();
+    RETURN();
+}
+
+void OPPROTO op_cvtgq (void)
+{
+    helper_cvtgq();
+    RETURN();
+}
+
+void OPPROTO op_cvtqg (void)
+{
+    helper_cvtqg();
+    RETURN();
+}
+
+void OPPROTO op_cvtdg (void)
+{
+    helper_cvtdg();
+    RETURN();
+}
+
+void OPPROTO op_cvtlq (void)
+{
+    helper_cvtlq();
+    RETURN();
+}
+
+void OPPROTO op_cvtql (void)
+{
+    helper_cvtql();
+    RETURN();
+}
+
+void OPPROTO op_cvtqlv (void)
+{
+    helper_cvtqlv();
+    RETURN();
+}
+
+void OPPROTO op_cvtqlsv (void)
+{
+    helper_cvtqlsv();
+    RETURN();
+}
+
+/* PALcode support special instructions */
+#if !defined (CONFIG_USER_ONLY)
+void OPPROTO op_hw_rei (void)
+{
+    env->pc = env->ipr[IPR_EXC_ADDR] & ~3;
+    env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
+    /* XXX: re-enable interrupts and memory mapping */
+    RETURN();
+}
+
+void OPPROTO op_hw_ret (void)
+{
+    env->pc = T0 & ~3;
+    env->ipr[IPR_EXC_ADDR] = T0 & 1;
+    /* XXX: re-enable interrupts and memory mapping */
+    RETURN();
+}
+
+void OPPROTO op_mfpr (void)
+{
+    helper_mfpr(PARAM(1));
+    RETURN();
+}
+
+void OPPROTO op_mtpr (void)
+{
+    helper_mtpr(PARAM(1));
+    RETURN();
+}
+
+void OPPROTO op_set_alt_mode (void)
+{
+    env->saved_mode = env->ps & 0xC;
+    env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC);
+    RETURN();
+}
+
+void OPPROTO op_restore_mode (void)
+{
+    env->ps = (env->ps & ~0xC) | env->saved_mode;
+    RETURN();
+}
+
+void OPPROTO op_ld_phys_to_virt (void)
+{
+    helper_ld_phys_to_virt();
+    RETURN();
+}
+
+void OPPROTO op_st_phys_to_virt (void)
+{
+    helper_st_phys_to_virt();
+    RETURN();
+}
+#endif /* !defined (CONFIG_USER_ONLY) */
diff --git a/target-alpha/op_helper.c b/target-alpha/op_helper.c
new file mode 100644
index 0000000..deac6c2
--- /dev/null
+++ b/target-alpha/op_helper.c
@@ -0,0 +1,1255 @@
+/*
+ *  Alpha emulation cpu micro-operations helpers for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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"
+#include "softfloat.h"
+
+#include "op_helper.h"
+
+#define MEMSUFFIX _raw
+#include "op_helper_mem.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#define MEMSUFFIX _user
+#include "op_helper_mem.h"
+
+#define MEMSUFFIX _kernel
+#include "op_helper_mem.h"
+
+/* Those are used for supervisor and executive modes */
+#define MEMSUFFIX _data
+#include "op_helper_mem.h"
+#endif
+
+void helper_tb_flush (void)
+{
+    tlb_flush(env, 1);
+}
+
+void cpu_dump_EA (target_ulong EA);
+void helper_print_mem_EA (target_ulong EA)
+{
+    cpu_dump_EA(EA);
+}
+
+/*****************************************************************************/
+/* Exceptions processing helpers */
+void helper_excp (uint32_t excp, uint32_t error)
+{
+    env->exception_index = excp;
+    env->error_code = error;
+    cpu_loop_exit();
+}
+
+void helper_amask (void)
+{
+    switch (env->implver) {
+    case IMPLVER_2106x:
+        /* EV4, EV45, LCA, LCA45 & EV5 */
+        break;
+    case IMPLVER_21164:
+    case IMPLVER_21264:
+    case IMPLVER_21364:
+        T0 &= ~env->amask;
+        break;
+    }
+}
+
+void helper_load_pcc (void)
+{
+    /* XXX: TODO */
+    T0 = 0;
+}
+
+void helper_load_implver (void)
+{
+    T0 = env->implver;
+}
+
+void helper_load_fpcr (void)
+{
+    T0 = 0;
+#ifdef CONFIG_SOFTFLOAT
+    T0 |= env->fp_status.float_exception_flags << 52;
+    if (env->fp_status.float_exception_flags)
+        T0 |= 1ULL << 63;
+    env->ipr[IPR_EXC_SUM] &= ~0x3E:
+    env->ipr[IPR_EXC_SUM] |= env->fp_status.float_exception_flags << 1;
+#endif
+    switch (env->fp_status.float_rounding_mode) {
+    case float_round_nearest_even:
+        T0 |= 2ULL << 58;
+        break;
+    case float_round_down:
+        T0 |= 1ULL << 58;
+        break;
+    case float_round_up:
+        T0 |= 3ULL << 58;
+        break;
+    case float_round_to_zero:
+        break;
+    }
+}
+
+void helper_store_fpcr (void)
+{
+#ifdef CONFIG_SOFTFLOAT
+    set_float_exception_flags((T0 >> 52) & 0x3F, &FP_STATUS);
+#endif
+    switch ((T0 >> 58) & 3) {
+    case 0:
+        set_float_rounding_mode(float_round_to_zero, &FP_STATUS);
+        break;
+    case 1:
+        set_float_rounding_mode(float_round_down, &FP_STATUS);
+        break;
+    case 2:
+        set_float_rounding_mode(float_round_nearest_even, &FP_STATUS);
+        break;
+    case 3:
+        set_float_rounding_mode(float_round_up, &FP_STATUS);
+        break;
+    }
+}
+
+void helper_load_irf (void)
+{
+    /* XXX: TODO */
+    T0 = 0;
+}
+
+void helper_set_irf (void)
+{
+    /* XXX: TODO */
+}
+
+void helper_clear_irf (void)
+{
+    /* XXX: TODO */
+}
+
+void helper_addqv (void)
+{
+    T2 = T0;
+    T0 += T1;
+    if (unlikely((T2 ^ T1 ^ (-1ULL)) & (T2 ^ T0) & (1ULL << 63))) {
+        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+    }
+}
+
+void helper_addlv (void)
+{
+    T2 = T0;
+    T0 = (uint32_t)(T0 + T1);
+    if (unlikely((T2 ^ T1 ^ (-1UL)) & (T2 ^ T0) & (1UL << 31))) {
+        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+    }
+}
+
+void helper_subqv (void)
+{
+    T2 = T0;
+    T0 -= T1;
+    if (unlikely(((~T2) ^ T0 ^ (-1ULL)) & ((~T2) ^ T1) & (1ULL << 63))) {
+        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+    }
+}
+
+void helper_sublv (void)
+{
+    T2 = T0;
+    T0 = (uint32_t)(T0 - T1);
+    if (unlikely(((~T2) ^ T0 ^ (-1UL)) & ((~T2) ^ T1) & (1UL << 31))) {
+        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+    }
+}
+
+void helper_mullv (void)
+{
+    int64_t res = (int64_t)T0 * (int64_t)T1;
+
+    if (unlikely((int32_t)res != res)) {
+        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+    }
+    T0 = (int64_t)((int32_t)res);
+}
+
+void helper_mulqv ()
+{
+    uint64_t res, tmp0, tmp1;
+
+    res = (T0 >> 32) * (T1 >> 32);
+    tmp0 = ((T0 & 0xFFFFFFFF) * (T1 >> 32)) +
+        ((T0 >> 32) * (T1 & 0xFFFFFFFF));
+    tmp1 = (T0 & 0xFFFFFFFF) * (T1 & 0xFFFFFFFF);
+    tmp0 += tmp1 >> 32;
+    res += tmp0 >> 32;
+    T0 *= T1;
+    if (unlikely(res != 0)) {
+        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+    }
+}
+
+void helper_umulh (void)
+{
+    uint64_t tmp0, tmp1;
+
+    tmp0 = ((T0 & 0xFFFFFFFF) * (T1 >> 32)) +
+        ((T0 >> 32) * (T1 & 0xFFFFFFFF));
+    tmp1 = (T0 & 0xFFFFFFFF) * (T1 & 0xFFFFFFFF);
+    tmp0 += tmp1 >> 32;
+    T0 = (T0 >> 32) * (T0 >> 32);
+    T0 += tmp0 >> 32;
+}
+
+void helper_ctpop (void)
+{
+    int n;
+
+    for (n = 0; T0 != 0; n++)
+        T0 = T0 ^ (T0 - 1);
+    T0 = n;
+}
+
+void helper_ctlz (void)
+{
+    uint32_t op32;
+    int n;
+
+    n = 0;
+    if (!(T0 & 0xFFFFFFFF00000000ULL)) {
+        n += 32;
+        T0 <<= 32;
+    }
+    /* Make it easier for 32 bits hosts */
+    op32 = T0 >> 32;
+    if (!(op32 & 0xFFFF0000UL)) {
+        n += 16;
+        op32 <<= 16;
+    }
+    if (!(op32 & 0xFF000000UL)) {
+        n += 8;
+        op32 <<= 8;
+    }
+    if (!(op32 & 0xF0000000UL)) {
+        n += 4;
+        op32 <<= 4;
+    }
+    if (!(op32 & 0xC0000000UL)) {
+        n += 2;
+        op32 <<= 2;
+    }
+    if (!(op32 & 0x80000000UL)) {
+        n++;
+        op32 <<= 1;
+    }
+    if (!(op32 & 0x80000000UL)) {
+        n++;
+    }
+    T0 = n;
+}
+
+void helper_cttz (void)
+{
+    uint32_t op32;
+    int n;
+
+    n = 0;
+    if (!(T0 & 0x00000000FFFFFFFFULL)) {
+        n += 32;
+        T0 >>= 32;
+    }
+    /* Make it easier for 32 bits hosts */
+    op32 = T0;
+    if (!(op32 & 0x0000FFFFUL)) {
+        n += 16;
+        op32 >>= 16;
+    }
+    if (!(op32 & 0x000000FFUL)) {
+        n += 8;
+        op32 >>= 8;
+    }
+    if (!(op32 & 0x0000000FUL)) {
+        n += 4;
+        op32 >>= 4;
+    }
+    if (!(op32 & 0x00000003UL)) {
+        n += 2;
+        op32 >>= 2;
+    }
+    if (!(op32 & 0x00000001UL)) {
+        n++;
+        op32 >>= 1;
+    }
+    if (!(op32 & 0x00000001UL)) {
+        n++;
+    }
+    T0 = n;
+}
+
+static inline uint64_t byte_zap (uint64_t op, uint8_t mskb)
+{
+    uint64_t mask;
+
+    mask = 0;
+    mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL;
+    mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL;
+    mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL;
+    mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL;
+    mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL;
+    mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL;
+    mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL;
+    mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL;
+
+    return op & ~mask;
+}
+
+void helper_mskbl (void)
+{
+    T0 = byte_zap(T0, 0x01 << (T1 & 7));
+}
+
+void helper_extbl (void)
+{
+    T0 >>= (T1 & 7) * 8;
+    T0 = byte_zap(T0, 0xFE);
+}
+
+void helper_insbl (void)
+{
+    T0 <<= (T1 & 7) * 8;
+    T0 = byte_zap(T0, ~(0x01 << (T1 & 7)));
+}
+
+void helper_mskwl (void)
+{
+    T0 = byte_zap(T0, 0x03 << (T1 & 7));
+}
+
+void helper_extwl (void)
+{
+    T0 >>= (T1 & 7) * 8;
+    T0 = byte_zap(T0, 0xFC);
+}
+
+void helper_inswl (void)
+{
+    T0 <<= (T1 & 7) * 8;
+    T0 = byte_zap(T0, ~(0x03 << (T1 & 7)));
+}
+
+void helper_mskll (void)
+{
+    T0 = byte_zap(T0, 0x0F << (T1 & 7));
+}
+
+void helper_extll (void)
+{
+    T0 >>= (T1 & 7) * 8;
+    T0 = byte_zap(T0, 0xF0);
+}
+
+void helper_insll (void)
+{
+    T0 <<= (T1 & 7) * 8;
+    T0 = byte_zap(T0, ~(0x0F << (T1 & 7)));
+}
+
+void helper_zap (void)
+{
+    T0 = byte_zap(T0, T1);
+}
+
+void helper_zapnot (void)
+{
+    T0 = byte_zap(T0, ~T1);
+}
+
+void helper_mskql (void)
+{
+    T0 = byte_zap(T0, 0xFF << (T1 & 7));
+}
+
+void helper_extql (void)
+{
+    T0 >>= (T1 & 7) * 8;
+    T0 = byte_zap(T0, 0x00);
+}
+
+void helper_insql (void)
+{
+    T0 <<= (T1 & 7) * 8;
+    T0 = byte_zap(T0, ~(0xFF << (T1 & 7)));
+}
+
+void helper_mskwh (void)
+{
+    T0 = byte_zap(T0, (0x03 << (T1 & 7)) >> 8);
+}
+
+void helper_inswh (void)
+{
+    T0 >>= 64 - ((T1 & 7) * 8);
+    T0 = byte_zap(T0, ~((0x03 << (T1 & 7)) >> 8));
+}
+
+void helper_extwh (void)
+{
+    T0 <<= 64 - ((T1 & 7) * 8);
+    T0 = byte_zap(T0, ~0x07);
+}
+
+void helper_msklh (void)
+{
+    T0 = byte_zap(T0, (0x0F << (T1 & 7)) >> 8);
+}
+
+void helper_inslh (void)
+{
+    T0 >>= 64 - ((T1 & 7) * 8);
+    T0 = byte_zap(T0, ~((0x0F << (T1 & 7)) >> 8));
+}
+
+void helper_extlh (void)
+{
+    T0 <<= 64 - ((T1 & 7) * 8);
+    T0 = byte_zap(T0, ~0x0F);
+}
+
+void helper_mskqh (void)
+{
+    T0 = byte_zap(T0, (0xFF << (T1 & 7)) >> 8);
+}
+
+void helper_insqh (void)
+{
+    T0 >>= 64 - ((T1 & 7) * 8);
+    T0 = byte_zap(T0, ~((0xFF << (T1 & 7)) >> 8));
+}
+
+void helper_extqh (void)
+{
+    T0 <<= 64 - ((T1 & 7) * 8);
+    T0 = byte_zap(T0, 0x00);
+}
+
+void helper_cmpbge (void)
+{
+    uint8_t opa, opb, res;
+    int i;
+
+    res = 0;
+    for (i = 0; i < 7; i++) {
+        opa = T0 >> (i * 8);
+        opb = T1 >> (i * 8);
+        if (opa >= opb)
+            res |= 1 << i;
+    }
+    T0 = res;
+}
+
+void helper_cmov_fir (int freg)
+{
+    if (FT0 != 0)
+        env->fir[freg] = FT1;
+}
+
+void helper_sqrts (void)
+{
+    FT0 = float32_sqrt(FT0, &FP_STATUS);
+}
+
+void helper_cpys (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p, q, r;
+
+    p.d = FT0;
+    q.d = FT1;
+    r.i = p.i & 0x8000000000000000ULL;
+    r.i |= q.i & ~0x8000000000000000ULL;
+    FT0 = r.d;
+}
+
+void helper_cpysn (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p, q, r;
+
+    p.d = FT0;
+    q.d = FT1;
+    r.i = (~p.i) & 0x8000000000000000ULL;
+    r.i |= q.i & ~0x8000000000000000ULL;
+    FT0 = r.d;
+}
+
+void helper_cpyse (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p, q, r;
+
+    p.d = FT0;
+    q.d = FT1;
+    r.i = p.i & 0xFFF0000000000000ULL;
+    r.i |= q.i & ~0xFFF0000000000000ULL;
+    FT0 = r.d;
+}
+
+void helper_itofs (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.d = FT0;
+    FT0 = int64_to_float32(p.i, &FP_STATUS);
+}
+
+void helper_ftois (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = float32_to_int64(FT0, &FP_STATUS);
+    FT0 = p.d;
+}
+
+void helper_sqrtt (void)
+{
+    FT0 = float64_sqrt(FT0, &FP_STATUS);
+}
+
+void helper_cmptun (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = 0;
+    if (float64_is_nan(FT0) || float64_is_nan(FT1))
+        p.i = 0x4000000000000000ULL;
+    FT0 = p.d;
+}
+
+void helper_cmpteq (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = 0;
+    if (float64_eq(FT0, FT1, &FP_STATUS))
+        p.i = 0x4000000000000000ULL;
+    FT0 = p.d;
+}
+
+void helper_cmptle (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = 0;
+    if (float64_le(FT0, FT1, &FP_STATUS))
+        p.i = 0x4000000000000000ULL;
+    FT0 = p.d;
+}
+
+void helper_cmptlt (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = 0;
+    if (float64_lt(FT0, FT1, &FP_STATUS))
+        p.i = 0x4000000000000000ULL;
+    FT0 = p.d;
+}
+
+void helper_itoft (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.d = FT0;
+    FT0 = int64_to_float64(p.i, &FP_STATUS);
+}
+
+void helper_ftoit (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = float64_to_int64(FT0, &FP_STATUS);
+    FT0 = p.d;
+}
+
+static int vaxf_is_valid (float ff)
+{
+    union {
+        float f;
+        uint32_t i;
+    } p;
+    uint32_t exp, mant;
+
+    p.f = ff;
+    exp = (p.i >> 23) & 0xFF;
+    mant = p.i & 0x007FFFFF;
+    if (exp == 0 && ((p.i & 0x80000000) || mant != 0)) {
+        /* Reserved operands / Dirty zero */
+        return 0;
+    }
+
+    return 1;
+}
+
+static float vaxf_to_ieee32 (float ff)
+{
+    union {
+        float f;
+        uint32_t i;
+    } p;
+    uint32_t exp;
+
+    p.f = ff;
+    exp = (p.i >> 23) & 0xFF;
+    if (exp < 3) {
+        /* Underflow */
+        p.f = 0.0;
+    } else {
+        p.f *= 0.25;
+    }
+
+    return p.f;
+}
+
+static float ieee32_to_vaxf (float fi)
+{
+    union {
+        float f;
+        uint32_t i;
+    } p;
+    uint32_t exp, mant;
+
+    p.f = fi;
+    exp = (p.i >> 23) & 0xFF;
+    mant = p.i & 0x007FFFFF;
+    if (exp == 255) {
+        /* NaN or infinity */
+        p.i = 1;
+    } else if (exp == 0) {
+        if (mant == 0) {
+            /* Zero */
+            p.i = 0;
+        } else {
+            /* Denormalized */
+            p.f *= 2.0;
+        }
+    } else {
+        if (exp >= 253) {
+            /* Overflow */
+            p.i = 1;
+        } else {
+            p.f *= 4.0;
+        }
+    }
+
+    return p.f;
+}
+
+void helper_addf (void)
+{
+    float ft0, ft1, ft2;
+
+    if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxf_to_ieee32(FT0);
+    ft1 = vaxf_to_ieee32(FT1);
+    ft2 = float32_add(ft0, ft1, &FP_STATUS);
+    FT0 = ieee32_to_vaxf(ft2);
+}
+
+void helper_subf (void)
+{
+    float ft0, ft1, ft2;
+
+    if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxf_to_ieee32(FT0);
+    ft1 = vaxf_to_ieee32(FT1);
+    ft2 = float32_sub(ft0, ft1, &FP_STATUS);
+    FT0 = ieee32_to_vaxf(ft2);
+}
+
+void helper_mulf (void)
+{
+    float ft0, ft1, ft2;
+
+    if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxf_to_ieee32(FT0);
+    ft1 = vaxf_to_ieee32(FT1);
+    ft2 = float32_mul(ft0, ft1, &FP_STATUS);
+    FT0 = ieee32_to_vaxf(ft2);
+}
+
+void helper_divf (void)
+{
+    float ft0, ft1, ft2;
+
+    if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxf_to_ieee32(FT0);
+    ft1 = vaxf_to_ieee32(FT1);
+    ft2 = float32_div(ft0, ft1, &FP_STATUS);
+    FT0 = ieee32_to_vaxf(ft2);
+}
+
+void helper_sqrtf (void)
+{
+    float ft0, ft1;
+
+    if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxf_to_ieee32(FT0);
+    ft1 = float32_sqrt(ft0, &FP_STATUS);
+    FT0 = ieee32_to_vaxf(ft1);
+}
+
+void helper_itoff (void)
+{
+    /* XXX: TODO */
+}
+
+static int vaxg_is_valid (double ff)
+{
+    union {
+        double f;
+        uint64_t i;
+    } p;
+    uint64_t exp, mant;
+
+    p.f = ff;
+    exp = (p.i >> 52) & 0x7FF;
+    mant = p.i & 0x000FFFFFFFFFFFFFULL;
+    if (exp == 0 && ((p.i & 0x8000000000000000ULL) || mant != 0)) {
+        /* Reserved operands / Dirty zero */
+        return 0;
+    }
+
+    return 1;
+}
+
+static double vaxg_to_ieee64 (double fg)
+{
+    union {
+        double f;
+        uint64_t i;
+    } p;
+    uint32_t exp;
+
+    p.f = fg;
+    exp = (p.i >> 52) & 0x7FF;
+    if (exp < 3) {
+        /* Underflow */
+        p.f = 0.0;
+    } else {
+        p.f *= 0.25;
+    }
+
+    return p.f;
+}
+
+static double ieee64_to_vaxg (double fi)
+{
+    union {
+        double f;
+        uint64_t i;
+    } p;
+    uint64_t mant;
+    uint32_t exp;
+
+    p.f = fi;
+    exp = (p.i >> 52) & 0x7FF;
+    mant = p.i & 0x000FFFFFFFFFFFFFULL;
+    if (exp == 255) {
+        /* NaN or infinity */
+        p.i = 1; /* VAX dirty zero */
+    } else if (exp == 0) {
+        if (mant == 0) {
+            /* Zero */
+            p.i = 0;
+        } else {
+            /* Denormalized */
+            p.f *= 2.0;
+        }
+    } else {
+        if (exp >= 2045) {
+            /* Overflow */
+            p.i = 1; /* VAX dirty zero */
+        } else {
+            p.f *= 4.0;
+        }
+    }
+
+    return p.f;
+}
+
+void helper_addg (void)
+{
+    double ft0, ft1, ft2;
+
+    if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxg_to_ieee64(FT0);
+    ft1 = vaxg_to_ieee64(FT1);
+    ft2 = float64_add(ft0, ft1, &FP_STATUS);
+    FT0 = ieee64_to_vaxg(ft2);
+}
+
+void helper_subg (void)
+{
+    double ft0, ft1, ft2;
+
+    if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxg_to_ieee64(FT0);
+    ft1 = vaxg_to_ieee64(FT1);
+    ft2 = float64_sub(ft0, ft1, &FP_STATUS);
+    FT0 = ieee64_to_vaxg(ft2);
+}
+
+void helper_mulg (void)
+{
+    double ft0, ft1, ft2;
+
+    if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxg_to_ieee64(FT0);
+    ft1 = vaxg_to_ieee64(FT1);
+    ft2 = float64_mul(ft0, ft1, &FP_STATUS);
+    FT0 = ieee64_to_vaxg(ft2);
+}
+
+void helper_divg (void)
+{
+    double ft0, ft1, ft2;
+
+    if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxg_to_ieee64(FT0);
+    ft1 = vaxg_to_ieee64(FT1);
+    ft2 = float64_div(ft0, ft1, &FP_STATUS);
+    FT0 = ieee64_to_vaxg(ft2);
+}
+
+void helper_sqrtg (void)
+{
+    double ft0, ft1;
+
+    if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxg_to_ieee64(FT0);
+    ft1 = float64_sqrt(ft0, &FP_STATUS);
+    FT0 = ieee64_to_vaxg(ft1);
+}
+
+void helper_cmpgeq (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+    double ft0, ft1;
+
+    if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxg_to_ieee64(FT0);
+    ft1 = vaxg_to_ieee64(FT1);
+    p.u = 0;
+    if (float64_eq(ft0, ft1, &FP_STATUS))
+        p.u = 0x4000000000000000ULL;
+    FT0 = p.d;
+}
+
+void helper_cmpglt (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+    double ft0, ft1;
+
+    if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxg_to_ieee64(FT0);
+    ft1 = vaxg_to_ieee64(FT1);
+    p.u = 0;
+    if (float64_lt(ft0, ft1, &FP_STATUS))
+        p.u = 0x4000000000000000ULL;
+    FT0 = p.d;
+}
+
+void helper_cmpgle (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+    double ft0, ft1;
+
+    if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+        /* XXX: TODO */
+    }
+    ft0 = vaxg_to_ieee64(FT0);
+    ft1 = vaxg_to_ieee64(FT1);
+    p.u = 0;
+    if (float64_le(ft0, ft1, &FP_STATUS))
+        p.u = 0x4000000000000000ULL;
+    FT0 = p.d;
+}
+
+void helper_cvtqs (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+
+    p.d = FT0;
+    FT0 = (float)p.u;
+}
+
+void helper_cvttq (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+
+    p.u = FT0;
+    FT0 = p.d;
+}
+
+void helper_cvtqt (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+
+    p.d = FT0;
+    FT0 = p.u;
+}
+
+void helper_cvtqf (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+
+    p.d = FT0;
+    FT0 = ieee32_to_vaxf(p.u);
+}
+
+void helper_cvtgf (void)
+{
+    double ft0;
+
+    ft0 = vaxg_to_ieee64(FT0);
+    FT0 = ieee32_to_vaxf(ft0);
+}
+
+void helper_cvtgd (void)
+{
+    /* XXX: TODO */
+}
+
+void helper_cvtgq (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+
+    p.u = vaxg_to_ieee64(FT0);
+    FT0 = p.d;
+}
+
+void helper_cvtqg (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p;
+
+    p.d = FT0;
+    FT0 = ieee64_to_vaxg(p.u);
+}
+
+void helper_cvtdg (void)
+{
+    /* XXX: TODO */
+}
+
+void helper_cvtlq (void)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p, q;
+
+    p.d = FT0;
+    q.u = (p.u >> 29) & 0x3FFFFFFF;
+    q.u |= (p.u >> 32);
+    q.u = (int64_t)((int32_t)q.u);
+    FT0 = q.d;
+}
+
+static inline void __helper_cvtql (int s, int v)
+{
+    union {
+        double d;
+        uint64_t u;
+    } p, q;
+
+    p.d = FT0;
+    q.u = ((uint64_t)(p.u & 0xC0000000)) << 32;
+    q.u |= ((uint64_t)(p.u & 0x7FFFFFFF)) << 29;
+    FT0 = q.d;
+    if (v && (int64_t)((int32_t)p.u) != (int64_t)p.u) {
+        helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+    }
+    if (s) {
+        /* TODO */
+    }
+}
+
+void helper_cvtql (void)
+{
+    __helper_cvtql(0, 0);
+}
+
+void helper_cvtqlv (void)
+{
+    __helper_cvtql(0, 1);
+}
+
+void helper_cvtqlsv (void)
+{
+    __helper_cvtql(1, 1);
+}
+
+void helper_cmpfeq (void)
+{
+    if (float64_eq(FT0, FT1, &FP_STATUS))
+        T0 = 1;
+    else
+        T0 = 0;
+}
+
+void helper_cmpfne (void)
+{
+    if (float64_eq(FT0, FT1, &FP_STATUS))
+        T0 = 0;
+    else
+        T0 = 1;
+}
+
+void helper_cmpflt (void)
+{
+    if (float64_lt(FT0, FT1, &FP_STATUS))
+        T0 = 1;
+    else
+        T0 = 0;
+}
+
+void helper_cmpfle (void)
+{
+    if (float64_lt(FT0, FT1, &FP_STATUS))
+        T0 = 1;
+    else
+        T0 = 0;
+}
+
+void helper_cmpfgt (void)
+{
+    if (float64_le(FT0, FT1, &FP_STATUS))
+        T0 = 0;
+    else
+        T0 = 1;
+}
+
+void helper_cmpfge (void)
+{
+    if (float64_lt(FT0, FT1, &FP_STATUS))
+        T0 = 0;
+    else
+        T0 = 1;
+}
+
+#if !defined (CONFIG_USER_ONLY)
+void helper_mfpr (int iprn)
+{
+    uint64_t val;
+
+    if (cpu_alpha_mfpr(env, iprn, &val) == 0)
+        T0 = val;
+}
+
+void helper_mtpr (int iprn)
+{
+    cpu_alpha_mtpr(env, iprn, T0, NULL);
+}
+#endif
+
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined (CONFIG_USER_ONLY)
+
+#define GETPC() (__builtin_return_address(0))
+
+/* XXX: the two following helpers are pure hacks.
+ *      Hopefully, we emulate the PALcode, then we should never see
+ *      HW_LD / HW_ST instructions.
+ */
+void helper_ld_phys_to_virt (void)
+{
+    uint64_t tlb_addr, physaddr;
+    int index, is_user;
+    void *retaddr;
+
+    is_user = (env->ps >> 3) & 3;
+    index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ redo:
+    tlb_addr = env->tlb_table[is_user][index].addr_read;
+    if ((T0 & TARGET_PAGE_MASK) ==
+        (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        physaddr = T0 + env->tlb_table[is_user][index].addend;
+    } else {
+        /* the page is not in the TLB : fill it */
+        retaddr = GETPC();
+        tlb_fill(T0, 0, is_user, retaddr);
+        goto redo;
+    }
+    T0 = physaddr;
+}
+
+void helper_st_phys_to_virt (void)
+{
+    uint64_t tlb_addr, physaddr;
+    int index, is_user;
+    void *retaddr;
+
+    is_user = (env->ps >> 3) & 3;
+    index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ redo:
+    tlb_addr = env->tlb_table[is_user][index].addr_write;
+    if ((T0 & TARGET_PAGE_MASK) ==
+        (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+        physaddr = T0 + env->tlb_table[is_user][index].addend;
+    } else {
+        /* the page is not in the TLB : fill it */
+        retaddr = GETPC();
+        tlb_fill(T0, 1, is_user, retaddr);
+        goto redo;
+    }
+    T0 = physaddr;
+}
+
+#define MMUSUFFIX _mmu
+
+#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_alpha_handle_mmu_fault(env, addr, is_write, is_user, 1);
+    if (!likely(ret == 0)) {
+        if (likely(retaddr)) {
+            /* now we have a real cpu fault */
+            pc = (target_phys_addr_t)retaddr;
+            tb = tb_find_pc(pc);
+            if (likely(tb)) {
+                /* the PC is inside the translated code. It means that we have
+                   a virtual CPU fault */
+                cpu_restore_state(tb, env, pc, NULL);
+            }
+        }
+        /* Exception index and error code are already set */
+        cpu_loop_exit();
+    }
+    env = saved_env;
+}
+
+#endif
diff --git a/target-alpha/op_helper.h b/target-alpha/op_helper.h
new file mode 100644
index 0000000..806a30d
--- /dev/null
+++ b/target-alpha/op_helper.h
@@ -0,0 +1,141 @@
+/*
+ *  Alpha emulation cpu micro-operations helpers definitions for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+void helper_call_pal (uint32_t palcode);
+void helper_excp (uint32_t excp, uint32_t error);
+void helper_amask (void);
+void helper_load_pcc (void);
+void helper_load_implver (void);
+void helper_load_fpcr (void);
+void helper_store_fpcr (void);
+void helper_load_irf (void);
+void helper_set_irf (void);
+void helper_clear_irf (void);
+void helper_addqv (void);
+void helper_addlv (void);
+void helper_subqv (void);
+void helper_sublv (void);
+void helper_mullv (void);
+void helper_mulqv (void);
+void helper_umulh (void);
+void helper_ctpop (void);
+void helper_ctlz (void);
+void helper_cttz (void);
+void helper_mskbl (void);
+void helper_extbl (void);
+void helper_insbl (void);
+void helper_mskwl (void);
+void helper_extwl (void);
+void helper_inswl (void);
+void helper_mskll (void);
+void helper_extll (void);
+void helper_insll (void);
+void helper_zap (void);
+void helper_zapnot (void);
+void helper_mskql (void);
+void helper_extql (void);
+void helper_insql (void);
+void helper_mskwh (void);
+void helper_inswh (void);
+void helper_extwh (void);
+void helper_msklh (void);
+void helper_inslh (void);
+void helper_extlh (void);
+void helper_mskqh (void);
+void helper_insqh (void);
+void helper_extqh (void);
+void helper_cmpbge (void);
+void helper_cmov_fir (int freg);
+
+double helper_ldff_raw (target_ulong ea);
+void helper_stff_raw (target_ulong ea, double op);
+double helper_ldfg_raw (target_ulong ea);
+void helper_stfg_raw (target_ulong ea, double op);
+#if !defined(CONFIG_USER_ONLY)
+double helper_ldff_user (target_ulong ea);
+void helper_stff_user (target_ulong ea, double op);
+double helper_ldff_kernel (target_ulong ea);
+void helper_stff_kernel (target_ulong ea, double op);
+double helper_ldff_data (target_ulong ea);
+void helper_stff_data (target_ulong ea, double op);
+double helper_ldfg_user (target_ulong ea);
+void helper_stfg_user (target_ulong ea, double op);
+double helper_ldfg_kernel (target_ulong ea);
+void helper_stfg_kernel (target_ulong ea, double op);
+double helper_ldfg_data (target_ulong ea);
+void helper_stfg_data (target_ulong ea, double op);
+#endif
+
+void helper_sqrts (void);
+void helper_cpys (void);
+void helper_cpysn (void);
+void helper_cpyse (void);
+void helper_itofs (void);
+void helper_ftois (void);
+
+void helper_sqrtt (void);
+void helper_cmptun (void);
+void helper_cmpteq (void);
+void helper_cmptle (void);
+void helper_cmptlt (void);
+void helper_itoft (void);
+void helper_ftoit (void);
+
+void helper_addf (void);
+void helper_subf (void);
+void helper_mulf (void);
+void helper_divf (void);
+void helper_sqrtf (void);
+void helper_cmpfeq (void);
+void helper_cmpfne (void);
+void helper_cmpflt (void);
+void helper_cmpfle (void);
+void helper_cmpfgt (void);
+void helper_cmpfge (void);
+void helper_itoff (void);
+
+void helper_addg (void);
+void helper_subg (void);
+void helper_mulg (void);
+void helper_divg (void);
+void helper_sqrtg (void);
+void helper_cmpgeq (void);
+void helper_cmpglt (void);
+void helper_cmpgle (void);
+
+void helper_cvtqs (void);
+void helper_cvttq (void);
+void helper_cvtqt (void);
+void helper_cvtqf (void);
+void helper_cvtgf (void);
+void helper_cvtgd (void);
+void helper_cvtgq (void);
+void helper_cvtqg (void);
+void helper_cvtdg (void);
+void helper_cvtlq (void);
+void helper_cvtql (void);
+void helper_cvtqlv (void);
+void helper_cvtqlsv (void);
+
+void helper_mfpr (int iprn);
+void helper_mtpr (int iprn);
+void helper_ld_phys_to_virt (void);
+void helper_st_phys_to_virt (void);
+void helper_tb_flush (void);
diff --git a/target-alpha/op_helper_mem.h b/target-alpha/op_helper_mem.h
new file mode 100644
index 0000000..09c39bb
--- /dev/null
+++ b/target-alpha/op_helper_mem.h
@@ -0,0 +1,40 @@
+/*
+ *  Alpha emulation cpu micro-operations helpers for memory accesses for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+/* XXX: TODO */
+double glue(helper_ldff, MEMSUFFIX) (target_ulong ea)
+{
+    return 0;
+}
+
+void glue(helper_stff, MEMSUFFIX) (target_ulong ea, double op)
+{
+}
+
+double glue(helper_ldfg, MEMSUFFIX) (target_ulong ea)
+{
+    return 0;
+}
+
+void glue(helper_stfg, MEMSUFFIX) (target_ulong ea, double op)
+{
+}
+
+#undef MEMSUFFIX
diff --git a/target-alpha/op_mem.h b/target-alpha/op_mem.h
new file mode 100644
index 0000000..922d0d4
--- /dev/null
+++ b/target-alpha/op_mem.h
@@ -0,0 +1,125 @@
+/*
+ *  Alpha emulation cpu micro-operations for memory accesses for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+#define DEBUG_MEM_ACCESSES
+#if defined (DEBUG_MEM_ACCESSES)
+void helper_print_mem_EA (target_ulong EA);
+#define print_mem_EA(EA) do { helper_print_mem_EA(EA); } while (0)
+#else
+#define print_mem_EA(EA) do { } while (0)
+#endif
+
+static inline uint32_t glue(ldl_l, MEMSUFFIX) (target_ulong EA)
+{
+    env->lock = EA;
+
+    return glue(ldl, MEMSUFFIX)(EA);
+}
+
+static inline uint32_t glue(ldq_l, MEMSUFFIX) (target_ulong EA)
+{
+    env->lock = EA;
+
+    return glue(ldq, MEMSUFFIX)(EA);
+}
+
+static inline void glue(stl_c, MEMSUFFIX) (target_ulong EA, uint32_t data)
+{
+    if (EA == env->lock) {
+        glue(stl, MEMSUFFIX)(EA, data);
+        T0 = 0;
+    } else {
+        T0 = 1;
+    }
+    env->lock = -1;
+}
+
+static inline void glue(stq_c, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    if (EA == env->lock) {
+        glue(stq, MEMSUFFIX)(EA, data);
+        T0 = 0;
+    } else {
+        T0 = 1;
+    }
+    env->lock = -1;
+}
+
+#define ALPHA_LD_OP(name, op)                                                 \
+void OPPROTO glue(glue(op_ld, name), MEMSUFFIX) (void)                        \
+{                                                                             \
+    print_mem_EA(T0);                                                         \
+    T1 = glue(op, MEMSUFFIX)(T0);                                             \
+    RETURN();                                                                 \
+}
+
+#define ALPHA_ST_OP(name, op)                                                 \
+void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void)                        \
+{                                                                             \
+    print_mem_EA(T0);                                                         \
+    glue(op, MEMSUFFIX)(T0, T1);                                              \
+    RETURN();                                                                 \
+}
+
+ALPHA_LD_OP(bu, ldub);
+ALPHA_ST_OP(b, stb);
+ALPHA_LD_OP(wu, lduw);
+ALPHA_ST_OP(w, stw);
+ALPHA_LD_OP(l, ldl);
+ALPHA_ST_OP(l, stl);
+ALPHA_LD_OP(q, ldq);
+ALPHA_ST_OP(q, stq);
+
+ALPHA_LD_OP(q_u, ldq);
+ALPHA_ST_OP(q_u, stq);
+
+ALPHA_LD_OP(l_l, ldl_l);
+ALPHA_LD_OP(q_l, ldq_l);
+ALPHA_ST_OP(l_c, stl_c);
+ALPHA_ST_OP(q_c, stq_c);
+
+#define ALPHA_LDF_OP(name, op)                                                \
+void OPPROTO glue(glue(op_ld, name), MEMSUFFIX) (void)                        \
+{                                                                             \
+    print_mem_EA(T0);                                                         \
+    FT1 = glue(op, MEMSUFFIX)(T0);                                            \
+    RETURN();                                                                 \
+}
+
+#define ALPHA_STF_OP(name, op)                                                \
+void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void)                        \
+{                                                                             \
+    print_mem_EA(T0);                                                         \
+    glue(op, MEMSUFFIX)(T0, FT1);                                             \
+    RETURN();                                                                 \
+}
+
+ALPHA_LDF_OP(t, ldfq);
+ALPHA_STF_OP(t, stfq);
+ALPHA_LDF_OP(s, ldfl);
+ALPHA_STF_OP(s, stfl);
+
+/* VAX floating point */
+ALPHA_LDF_OP(f, helper_ldff);
+ALPHA_STF_OP(f, helper_stff);
+ALPHA_LDF_OP(g, helper_ldfg);
+ALPHA_STF_OP(g, helper_stfg);
+
+#undef MEMSUFFIX
diff --git a/target-alpha/op_template.h b/target-alpha/op_template.h
new file mode 100644
index 0000000..db15bb8
--- /dev/null
+++ b/target-alpha/op_template.h
@@ -0,0 +1,167 @@
+/*
+ *  Alpha emulation cpu micro-operations templates for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+/* Optimized constant loads */
+#if REG < 3
+void OPPROTO glue(op_reset_T, REG) (void)
+{
+    glue(T, REG) = 0;
+    RETURN();
+}
+
+void OPPROTO glue(op_reset_FT, REG) (void)
+{
+    glue(FT, REG) = 0;
+    RETURN();
+}
+
+/* XXX: This can be great on most RISC machines */
+#if !defined(__i386__) && !defined(__x86_64__)
+void OPPROTO glue(op_set_s16_T, REG) (void)
+{
+    glue(T, REG) = (int16_t)PARAM(1);
+    RETURN();
+}
+
+void OPPROTO glue(op_set_u16_T, REG) (void)
+{
+    glue(T, REG) = (uint16_t)PARAM(1);
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_set_s32_T, REG) (void)
+{
+    glue(T, REG) = (int32_t)PARAM(1);
+    RETURN();
+}
+
+void OPPROTO glue(op_set_u32_T, REG) (void)
+{
+    glue(T, REG) = (uint32_t)PARAM(1);
+    RETURN();
+}
+
+#if 0 // Qemu does not know how to do this...
+void OPPROTO glue(op_set_64_T, REG) (void)
+{
+    glue(T, REG) = (int64_t)PARAM(1);
+    RETURN();
+}
+#else
+void OPPROTO glue(op_set_64_T, REG) (void)
+{
+    glue(T, REG) = ((int64_t)PARAM(1) << 32) | (int64_t)PARAM(2);
+    RETURN();
+}
+#endif
+
+#endif /* REG < 3 */
+
+/* Fixed-point register moves */
+#if REG < 31
+void OPPROTO glue(op_load_T0_ir, REG) (void)
+{
+    T0 = env->ir[REG];
+    RETURN();
+}
+
+void OPPROTO glue(op_load_T1_ir, REG) (void)
+{
+    T1 = env->ir[REG];
+    RETURN();
+}
+
+void OPPROTO glue(op_load_T2_ir, REG) (void)
+{
+    T2 = env->ir[REG];
+    RETURN();
+}
+
+void OPPROTO glue(op_store_T0_ir, REG) (void)
+{
+    env->ir[REG] = T0;
+    RETURN();
+}
+
+void OPPROTO glue(op_store_T1_ir, REG) (void)
+{
+    env->ir[REG] = T1;
+    RETURN();
+}
+
+void OPPROTO glue(op_store_T2_ir, REG) (void)
+{
+    env->ir[REG] = T2;
+    RETURN();
+}
+
+void OPPROTO glue(op_cmov_ir, REG) (void)
+{
+    if (T0)
+        env->ir[REG] = T1;
+    RETURN();
+}
+
+/* floating point registers moves */
+void OPPROTO glue(op_load_FT0_fir, REG) (void)
+{
+    FT0 = env->fir[REG];
+    RETURN();
+}
+
+void OPPROTO glue(op_load_FT1_fir, REG) (void)
+{
+    FT1 = env->fir[REG];
+    RETURN();
+}
+
+void OPPROTO glue(op_load_FT2_fir, REG) (void)
+{
+    FT2 = env->fir[REG];
+    RETURN();
+}
+
+void OPPROTO glue(op_store_FT0_fir, REG) (void)
+{
+    env->fir[REG] = FT0;
+    RETURN();
+}
+
+void OPPROTO glue(op_store_FT1_fir, REG) (void)
+{
+    env->fir[REG] = FT1;
+    RETURN();
+}
+
+void OPPROTO glue(op_store_FT2_fir, REG) (void)
+{
+    env->fir[REG] = FT2;
+    RETURN();
+}
+
+void OPPROTO glue(op_cmov_fir, REG) (void)
+{
+    helper_cmov_fir(REG);
+    RETURN();
+}
+#endif /* REG < 31 */
+
+#undef REG
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
new file mode 100644
index 0000000..6a7da5a
--- /dev/null
+++ b/target-alpha/translate.c
@@ -0,0 +1,2119 @@
+/*
+ *  Alpha emulation cpu translation for qemu.
+ *
+ *  Copyright (c) 2007 Jocelyn Mayer
+ *
+ * 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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+
+#define DO_SINGLE_STEP
+#define GENERATE_NOP
+#define ALPHA_DEBUG_DISAS
+#define DO_TB_FLUSH
+
+typedef struct DisasContext DisasContext;
+struct DisasContext {
+    uint64_t pc;
+    int mem_idx;
+#if !defined (CONFIG_USER_ONLY)
+    int pal_mode;
+#endif
+    uint32_t amask;
+};
+
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
+
+enum {
+#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#include "opc.h"
+#undef DEF
+    NB_OPS,
+};
+
+static uint16_t *gen_opc_ptr;
+static uint32_t *gen_opparam_ptr;
+
+#include "gen-op.h"
+
+static inline void gen_op_nop (void)
+{
+#if defined(GENERATE_NOP)
+    gen_op_no_op();
+#endif
+}
+
+#define GEN32(func, NAME) \
+static GenOpFunc *NAME ## _table [32] = {                                     \
+NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,                                   \
+NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,                                   \
+NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11,                                 \
+NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
+NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
+NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
+NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
+NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
+};                                                                            \
+static inline void func(int n)                                                \
+{                                                                             \
+    NAME ## _table[n]();                                                      \
+}
+
+/* IR moves */
+/* Special hacks for ir31 */
+#define gen_op_load_T0_ir31 gen_op_reset_T0
+#define gen_op_load_T1_ir31 gen_op_reset_T1
+#define gen_op_load_T2_ir31 gen_op_reset_T2
+#define gen_op_store_T0_ir31 gen_op_nop
+#define gen_op_store_T1_ir31 gen_op_nop
+#define gen_op_store_T2_ir31 gen_op_nop
+#define gen_op_cmov_ir31 gen_op_nop
+GEN32(gen_op_load_T0_ir, gen_op_load_T0_ir);
+GEN32(gen_op_load_T1_ir, gen_op_load_T1_ir);
+GEN32(gen_op_load_T2_ir, gen_op_load_T2_ir);
+GEN32(gen_op_store_T0_ir, gen_op_store_T0_ir);
+GEN32(gen_op_store_T1_ir, gen_op_store_T1_ir);
+GEN32(gen_op_store_T2_ir, gen_op_store_T2_ir);
+GEN32(gen_op_cmov_ir, gen_op_cmov_ir);
+
+static inline void gen_load_ir (DisasContext *ctx, int irn, int Tn)
+{
+    switch (Tn) {
+    case 0:
+        gen_op_load_T0_ir(irn);
+        break;
+    case 1:
+        gen_op_load_T1_ir(irn);
+        break;
+    case 2:
+        gen_op_load_T2_ir(irn);
+        break;
+    }
+}
+
+static inline void gen_store_ir (DisasContext *ctx, int irn, int Tn)
+{
+    switch (Tn) {
+    case 0:
+        gen_op_store_T0_ir(irn);
+        break;
+    case 1:
+        gen_op_store_T1_ir(irn);
+        break;
+    case 2:
+        gen_op_store_T2_ir(irn);
+        break;
+    }
+}
+
+/* FIR moves */
+/* Special hacks for fir31 */
+#define gen_op_load_FT0_fir31 gen_op_reset_FT0
+#define gen_op_load_FT1_fir31 gen_op_reset_FT1
+#define gen_op_load_FT2_fir31 gen_op_reset_FT2
+#define gen_op_store_FT0_fir31 gen_op_nop
+#define gen_op_store_FT1_fir31 gen_op_nop
+#define gen_op_store_FT2_fir31 gen_op_nop
+#define gen_op_cmov_fir31 gen_op_nop
+GEN32(gen_op_load_FT0_fir, gen_op_load_FT0_fir);
+GEN32(gen_op_load_FT1_fir, gen_op_load_FT1_fir);
+GEN32(gen_op_load_FT2_fir, gen_op_load_FT2_fir);
+GEN32(gen_op_store_FT0_fir, gen_op_store_FT0_fir);
+GEN32(gen_op_store_FT1_fir, gen_op_store_FT1_fir);
+GEN32(gen_op_store_FT2_fir, gen_op_store_FT2_fir);
+GEN32(gen_op_cmov_fir, gen_op_cmov_fir);
+
+static inline void gen_load_fir (DisasContext *ctx, int firn, int Tn)
+{
+    switch (Tn) {
+    case 0:
+        gen_op_load_FT0_fir(firn);
+        break;
+    case 1:
+        gen_op_load_FT1_fir(firn);
+        break;
+    case 2:
+        gen_op_load_FT2_fir(firn);
+        break;
+    }
+}
+
+static inline void gen_store_fir (DisasContext *ctx, int firn, int Tn)
+{
+    switch (Tn) {
+    case 0:
+        gen_op_store_FT0_fir(firn);
+        break;
+    case 1:
+        gen_op_store_FT1_fir(firn);
+        break;
+    case 2:
+        gen_op_store_FT2_fir(firn);
+        break;
+    }
+}
+
+/* Memory moves */
+#if defined(CONFIG_USER_ONLY)
+#define OP_LD_TABLE(width)                                                    \
+static GenOpFunc *gen_op_ld##width[] = {                                      \
+    &gen_op_ld##width##_raw,                                                  \
+}
+#define OP_ST_TABLE(width)                                                    \
+static GenOpFunc *gen_op_st##width[] = {                                      \
+    &gen_op_st##width##_raw,                                                  \
+}
+#else
+#define OP_LD_TABLE(width)                                                    \
+static GenOpFunc *gen_op_ld##width[] = {                                      \
+    &gen_op_ld##width##_kernel,                                               \
+    &gen_op_ld##width##_user, /* executive */                                 \
+    &gen_op_ld##width##_data, /* supervisor */                                \
+    &gen_op_ld##width##_data, /* user */                                      \
+}
+#define OP_ST_TABLE(width)                                                    \
+static GenOpFunc *gen_op_st##width[] = {                                      \
+    &gen_op_st##width##_kernel,                                               \
+    &gen_op_st##width##_user, /* executive */                                 \
+    &gen_op_st##width##_data, /* supervisor */                                \
+    &gen_op_st##width##_data, /* user */                                      \
+}
+#endif
+
+#define GEN_LD(width)                                                         \
+OP_LD_TABLE(width);                                                           \
+static void gen_ld##width (DisasContext *ctx)                                 \
+{                                                                             \
+    (*gen_op_ld##width[ctx->mem_idx])();                                      \
+}
+
+#define GEN_ST(width)                                                         \
+OP_ST_TABLE(width);                                                           \
+static void gen_st##width (DisasContext *ctx)                                 \
+{                                                                             \
+    (*gen_op_st##width[ctx->mem_idx])();                                      \
+}
+
+GEN_LD(bu);
+GEN_ST(b);
+GEN_LD(wu);
+GEN_ST(w);
+GEN_LD(l);
+GEN_ST(l);
+GEN_LD(q);
+GEN_ST(q);
+GEN_LD(q_u);
+GEN_ST(q_u);
+GEN_LD(l_l);
+GEN_ST(l_c);
+GEN_LD(q_l);
+GEN_ST(q_c);
+
+#if 0 /* currently unused */
+GEN_LD(f);
+GEN_ST(f);
+GEN_LD(g);
+GEN_ST(g);
+#endif /* 0 */
+GEN_LD(s);
+GEN_ST(s);
+GEN_LD(t);
+GEN_ST(t);
+
+#if defined(__i386__) || defined(__x86_64__)
+static inline void gen_op_set_s16_T0 (int16_t imm)
+{
+    gen_op_set_s32_T0((int32_t)imm);
+}
+
+static inline void gen_op_set_s16_T1 (int16_t imm)
+{
+    gen_op_set_s32_T1((int32_t)imm);
+}
+
+static inline void gen_op_set_u16_T0 (uint16_t imm)
+{
+    gen_op_set_s32_T0((uint32_t)imm);
+}
+
+static inline void gen_op_set_u16_T1 (uint16_t imm)
+{
+    gen_op_set_s32_T1((uint32_t)imm);
+}
+#endif
+
+static inline void gen_set_sT0 (DisasContext *ctx, int64_t imm)
+{
+    int32_t imm32;
+    int16_t imm16;
+
+    imm32 = imm;
+    if (imm32 == imm) {
+        imm16 = imm;
+        if (imm16 == imm) {
+            if (imm == 0) {
+                gen_op_reset_T0();
+            } else {
+                gen_op_set_s16_T0(imm16);
+            }
+        } else {
+            gen_op_set_s32_T0(imm32);
+        }
+    } else {
+#if 0 // Qemu does not know how to do this...
+        gen_op_set_64_T0(imm);
+#else
+        gen_op_set_64_T0(imm >> 32, imm);
+#endif
+    }
+}
+
+static inline void gen_set_sT1 (DisasContext *ctx, int64_t imm)
+{
+    int32_t imm32;
+    int16_t imm16;
+
+    imm32 = imm;
+    if (imm32 == imm) {
+        imm16 = imm;
+        if (imm16 == imm) {
+            if (imm == 0) {
+                gen_op_reset_T1();
+            } else {
+                gen_op_set_s16_T1(imm16);
+            }
+        } else {
+            gen_op_set_s32_T1(imm32);
+        }
+    } else {
+#if 0 // Qemu does not know how to do this...
+        gen_op_set_64_T1(imm);
+#else
+        gen_op_set_64_T1(imm >> 32, imm);
+#endif
+    }
+}
+
+static inline void gen_set_uT0 (DisasContext *ctx, uint64_t imm)
+{
+    if (!(imm >> 32)) {
+        if ((!imm >> 16)) {
+            if (imm == 0)
+                gen_op_reset_T0();
+            else
+                gen_op_set_u16_T0(imm);
+        } else {
+            gen_op_set_u32_T0(imm);
+        }
+    } else {
+#if 0 // Qemu does not know how to do this...
+        gen_op_set_64_T0(imm);
+#else
+        gen_op_set_64_T0(imm >> 32, imm);
+#endif
+    }
+}
+
+static inline void gen_set_uT1 (DisasContext *ctx, uint64_t imm)
+{
+    if (!(imm >> 32)) {
+        if ((!imm >> 16)) {
+            if (imm == 0)
+                gen_op_reset_T1();
+            else
+                gen_op_set_u16_T1(imm);
+        } else {
+            gen_op_set_u32_T1(imm);
+        }
+    } else {
+#if 0 // Qemu does not know how to do this...
+        gen_op_set_64_T1(imm);
+#else
+        gen_op_set_64_T1(imm >> 32, imm);
+#endif
+    }
+}
+
+static inline void gen_update_pc (DisasContext *ctx)
+{
+    if (!(ctx->pc >> 32)) {
+        gen_op_update_pc32(ctx->pc);
+    } else {
+#if 0 // Qemu does not know how to do this...
+        gen_op_update_pc(ctx->pc);
+#else
+        gen_op_update_pc(ctx->pc >> 32, ctx->pc);
+#endif
+    }
+}
+
+static inline void _gen_op_bcond (DisasContext *ctx)
+{
+#if 0 // Qemu does not know how to do this...
+    gen_op_bcond(ctx->pc);
+#else
+    gen_op_bcond(ctx->pc >> 32, ctx->pc);
+#endif
+}
+
+static inline void gen_excp (DisasContext *ctx, int exception, int error_code)
+{
+    gen_update_pc(ctx);
+    gen_op_excp(exception, error_code);
+}
+
+static inline void gen_invalid (DisasContext *ctx)
+{
+    gen_excp(ctx, EXCP_OPCDEC, 0);
+}
+
+static void gen_load_mem (DisasContext *ctx,
+                          void (*gen_load_op)(DisasContext *ctx),
+                          int ra, int rb, int32_t disp16, int clear)
+{
+    if (ra == 31 && disp16 == 0) {
+        /* UNOP */
+        gen_op_nop();
+    } else {
+        gen_load_ir(ctx, rb, 0);
+        if (disp16 != 0) {
+            gen_set_sT1(ctx, disp16);
+            gen_op_addq();
+        }
+        if (clear)
+            gen_op_n7();
+        (*gen_load_op)(ctx);
+        gen_store_ir(ctx, ra, 1);
+    }
+}
+
+static void gen_store_mem (DisasContext *ctx,
+                           void (*gen_store_op)(DisasContext *ctx),
+                           int ra, int rb, int32_t disp16, int clear)
+{
+    gen_load_ir(ctx, rb, 0);
+    if (disp16 != 0) {
+        gen_set_sT1(ctx, disp16);
+        gen_op_addq();
+    }
+    if (clear)
+        gen_op_n7();
+    gen_load_ir(ctx, ra, 1);
+    (*gen_store_op)(ctx);
+}
+
+static void gen_load_fmem (DisasContext *ctx,
+                           void (*gen_load_fop)(DisasContext *ctx),
+                          int ra, int rb, int32_t disp16)
+{
+    gen_load_ir(ctx, rb, 0);
+    if (disp16 != 0) {
+        gen_set_sT1(ctx, disp16);
+        gen_op_addq();
+    }
+    (*gen_load_fop)(ctx);
+    gen_store_fir(ctx, ra, 1);
+}
+
+static void gen_store_fmem (DisasContext *ctx,
+                            void (*gen_store_fop)(DisasContext *ctx),
+                            int ra, int rb, int32_t disp16)
+{
+    gen_load_ir(ctx, rb, 0);
+    if (disp16 != 0) {
+        gen_set_sT1(ctx, disp16);
+        gen_op_addq();
+    }
+    gen_load_fir(ctx, ra, 1);
+    (*gen_store_fop)(ctx);
+}
+
+static void gen_bcond (DisasContext *ctx, void (*gen_test_op)(void),
+                       int ra, int32_t disp16)
+{
+    if (disp16 != 0) {
+        gen_set_uT0(ctx, ctx->pc);
+        gen_set_sT1(ctx, disp16 << 2);
+        gen_op_addq1();
+    } else {
+        gen_set_uT1(ctx, ctx->pc);
+    }
+    gen_load_ir(ctx, ra, 0);
+    (*gen_test_op)();
+    _gen_op_bcond(ctx);
+}
+
+static void gen_fbcond (DisasContext *ctx, void (*gen_test_op)(void),
+                        int ra, int32_t disp16)
+{
+    if (disp16 != 0) {
+        gen_set_uT0(ctx, ctx->pc);
+        gen_set_sT1(ctx, disp16 << 2);
+        gen_op_addq1();
+    } else {
+        gen_set_uT1(ctx, ctx->pc);
+    }
+    gen_load_fir(ctx, ra, 0);
+    (*gen_test_op)();
+    _gen_op_bcond(ctx);
+}
+
+static void gen_arith2 (DisasContext *ctx, void (*gen_arith_op)(void),
+                        int rb, int rc, int islit, int8_t lit)
+{
+    if (islit)
+        gen_set_sT0(ctx, lit);
+    else
+        gen_load_ir(ctx, rb, 0);
+    (*gen_arith_op)();
+    gen_store_ir(ctx, rc, 0);
+}
+
+static void gen_arith3 (DisasContext *ctx, void (*gen_arith_op)(void),
+                        int ra, int rb, int rc, int islit, int8_t lit)
+{
+    gen_load_ir(ctx, ra, 0);
+    if (islit)
+        gen_set_sT1(ctx, lit);
+    else
+        gen_load_ir(ctx, rb, 1);
+    (*gen_arith_op)();
+    gen_store_ir(ctx, rc, 0);
+}
+
+static void gen_cmov (DisasContext *ctx, void (*gen_test_op)(void),
+                      int ra, int rb, int rc, int islit, int8_t lit)
+{
+    gen_load_ir(ctx, ra, 1);
+    if (islit)
+        gen_set_sT0(ctx, lit);
+    else
+        gen_load_ir(ctx, rb, 0);
+    (*gen_test_op)();
+    gen_op_cmov_ir(rc);
+}
+
+static void gen_farith2 (DisasContext *ctx, void (*gen_arith_fop)(void),
+                         int rb, int rc)
+{
+    gen_load_fir(ctx, rb, 0);
+    (*gen_arith_fop)();
+    gen_store_fir(ctx, rc, 0);
+}
+
+static void gen_farith3 (DisasContext *ctx, void (*gen_arith_fop)(void),
+                         int ra, int rb, int rc)
+{
+    gen_load_fir(ctx, ra, 0);
+    gen_load_fir(ctx, rb, 1);
+    (*gen_arith_fop)();
+    gen_store_fir(ctx, rc, 0);
+}
+
+static void gen_fcmov (DisasContext *ctx, void (*gen_test_fop)(void),
+                       int ra, int rb, int rc)
+{
+    gen_load_fir(ctx, ra, 0);
+    gen_load_fir(ctx, rb, 1);
+    (*gen_test_fop)();
+    gen_op_cmov_fir(rc);
+}
+
+static void gen_fti (DisasContext *ctx, void (*gen_move_fop)(void),
+                     int ra, int rc)
+{
+    gen_load_fir(ctx, rc, 0);
+    (*gen_move_fop)();
+    gen_store_ir(ctx, ra, 0);
+}
+
+static void gen_itf (DisasContext *ctx, void (*gen_move_fop)(void),
+                     int ra, int rc)
+{
+    gen_load_ir(ctx, ra, 0);
+    (*gen_move_fop)();
+    gen_store_fir(ctx, rc, 0);
+}
+
+static void gen_s4addl (void)
+{
+    gen_op_s4();
+    gen_op_addl();
+}
+
+static void gen_s4subl (void)
+{
+    gen_op_s4();
+    gen_op_subl();
+}
+
+static void gen_s8addl (void)
+{
+    gen_op_s8();
+    gen_op_addl();
+}
+
+static void gen_s8subl (void)
+{
+    gen_op_s8();
+    gen_op_subl();
+}
+
+static void gen_s4addq (void)
+{
+    gen_op_s4();
+    gen_op_addq();
+}
+
+static void gen_s4subq (void)
+{
+    gen_op_s4();
+    gen_op_subq();
+}
+
+static void gen_s8addq (void)
+{
+    gen_op_s8();
+    gen_op_addq();
+}
+
+static void gen_s8subq (void)
+{
+    gen_op_s8();
+    gen_op_subq();
+}
+
+static void gen_amask (void)
+{
+    gen_op_load_amask();
+    gen_op_bic();
+}
+
+static int translate_one (DisasContext *ctx, uint32_t insn)
+{
+    uint32_t palcode;
+    int32_t disp21, disp16, disp12;
+    uint16_t fn11, fn16;
+    uint8_t opc, ra, rb, rc, sbz, fpfn, fn7, fn2, islit;
+    int8_t lit;
+    int ret;
+
+    /* Decode all instruction fields */
+    opc = insn >> 26;
+    ra = (insn >> 21) & 0x1F;
+    rb = (insn >> 16) & 0x1F;
+    rc = insn & 0x1F;
+    sbz = (insn >> 13) & 0x07;
+    islit = (insn >> 12) & 1;
+    lit = (insn >> 13) & 0xFF;
+    palcode = insn & 0x03FFFFFF;
+    disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11;
+    disp16 = (int16_t)(insn & 0x0000FFFF);
+    disp12 = (int32_t)((insn & 0x00000FFF) << 20) >> 20;
+    fn16 = insn & 0x0000FFFF;
+    fn11 = (insn >> 5) & 0x000007FF;
+    fpfn = fn11 & 0x3F;
+    fn7 = (insn >> 5) & 0x0000007F;
+    fn2 = (insn >> 5) & 0x00000003;
+    ret = 0;
+#if defined ALPHA_DEBUG_DISAS
+    if (logfile != NULL) {
+        fprintf(logfile, "opc %02x ra %d rb %d rc %d disp16 %04x\n",
+                opc, ra, rb, rc, disp16);
+    }
+#endif
+    switch (opc) {
+    case 0x00:
+        /* CALL_PAL */
+        if (palcode >= 0x80 && palcode < 0xC0) {
+            /* Unprivileged PAL call */
+            gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x1F) << 6), 0);
+#if !defined (CONFIG_USER_ONLY)
+        } else if (palcode < 0x40) {
+            /* Privileged PAL code */
+            if (ctx->mem_idx & 1)
+                goto invalid_opc;
+            else
+                gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x1F) << 6), 0);
+#endif
+        } else {
+            /* Invalid PAL call */
+            goto invalid_opc;
+        }
+        ret = 3;
+        break;
+    case 0x01:
+        /* OPC01 */
+        goto invalid_opc;
+    case 0x02:
+        /* OPC02 */
+        goto invalid_opc;
+    case 0x03:
+        /* OPC03 */
+        goto invalid_opc;
+    case 0x04:
+        /* OPC04 */
+        goto invalid_opc;
+    case 0x05:
+        /* OPC05 */
+        goto invalid_opc;
+    case 0x06:
+        /* OPC06 */
+        goto invalid_opc;
+    case 0x07:
+        /* OPC07 */
+        goto invalid_opc;
+    case 0x08:
+        /* LDA */
+        gen_load_ir(ctx, rb, 0);
+        gen_set_sT1(ctx, disp16);
+        gen_op_addq();
+        gen_store_ir(ctx, ra, 0);
+        break;
+    case 0x09:
+        /* LDAH */
+        gen_load_ir(ctx, rb, 0);
+        gen_set_sT1(ctx, disp16 << 16);
+        gen_op_addq();
+        gen_store_ir(ctx, ra, 0);
+        break;
+    case 0x0A:
+        /* LDBU */
+        if (!(ctx->amask & AMASK_BWX))
+            goto invalid_opc;
+        gen_load_mem(ctx, &gen_ldbu, ra, rb, disp16, 0);
+        break;
+    case 0x0B:
+        /* LDQ_U */
+        gen_load_mem(ctx, &gen_ldq_u, ra, rb, disp16, 1);
+        break;
+    case 0x0C:
+        /* LDWU */
+        if (!(ctx->amask & AMASK_BWX))
+            goto invalid_opc;
+        gen_load_mem(ctx, &gen_ldwu, ra, rb, disp16, 0);
+        break;
+    case 0x0D:
+        /* STW */
+        if (!(ctx->amask & AMASK_BWX))
+            goto invalid_opc;
+        gen_store_mem(ctx, &gen_stw, ra, rb, disp16, 0);
+        break;
+    case 0x0E:
+        /* STB */
+        if (!(ctx->amask & AMASK_BWX))
+            goto invalid_opc;
+        gen_store_mem(ctx, &gen_stb, ra, rb, disp16, 0);
+        break;
+    case 0x0F:
+        /* STQ_U */
+        gen_store_mem(ctx, &gen_stq_u, ra, rb, disp16, 1);
+        break;
+    case 0x10:
+        switch (fn7) {
+        case 0x00:
+            /* ADDL */
+            gen_arith3(ctx, &gen_op_addl, ra, rb, rc, islit, lit);
+            break;
+        case 0x02:
+            /* S4ADDL */
+            gen_arith3(ctx, &gen_s4addl, ra, rb, rc, islit, lit);
+            break;
+        case 0x09:
+            /* SUBL */
+            gen_arith3(ctx, &gen_op_subl, ra, rb, rc, islit, lit);
+            break;
+        case 0x0B:
+            /* S4SUBL */
+            gen_arith3(ctx, &gen_s4subl, ra, rb, rc, islit, lit);
+            break;
+        case 0x0F:
+            /* CMPBGE */
+            gen_arith3(ctx, &gen_op_cmpbge, ra, rb, rc, islit, lit);
+            break;
+        case 0x12:
+            /* S8ADDL */
+            gen_arith3(ctx, &gen_s8addl, ra, rb, rc, islit, lit);
+            break;
+        case 0x1B:
+            /* S8SUBL */
+            gen_arith3(ctx, &gen_s8subl, ra, rb, rc, islit, lit);
+            break;
+        case 0x1D:
+            /* CMPULT */
+            gen_arith3(ctx, &gen_op_cmpult, ra, rb, rc, islit, lit);
+            break;
+        case 0x20:
+            /* ADDQ */
+            gen_arith3(ctx, &gen_op_addq, ra, rb, rc, islit, lit);
+            break;
+        case 0x22:
+            /* S4ADDQ */
+            gen_arith3(ctx, &gen_s4addq, ra, rb, rc, islit, lit);
+            break;
+        case 0x29:
+            /* SUBQ */
+            gen_arith3(ctx, &gen_op_subq, ra, rb, rc, islit, lit);
+            break;
+        case 0x2B:
+            /* S4SUBQ */
+            gen_arith3(ctx, &gen_s4subq, ra, rb, rc, islit, lit);
+            break;
+        case 0x2D:
+            /* CMPEQ */
+            gen_arith3(ctx, &gen_op_cmpeq, ra, rb, rc, islit, lit);
+            break;
+        case 0x32:
+            /* S8ADDQ */
+            gen_arith3(ctx, &gen_s8addq, ra, rb, rc, islit, lit);
+            break;
+        case 0x3B:
+            /* S8SUBQ */
+            gen_arith3(ctx, &gen_s8subq, ra, rb, rc, islit, lit);
+            break;
+        case 0x3D:
+            /* CMPULE */
+            gen_arith3(ctx, &gen_op_cmpule, ra, rb, rc, islit, lit);
+            break;
+        case 0x40:
+            /* ADDL/V */
+            gen_arith3(ctx, &gen_op_addlv, ra, rb, rc, islit, lit);
+            break;
+        case 0x49:
+            /* SUBL/V */
+            gen_arith3(ctx, &gen_op_sublv, ra, rb, rc, islit, lit);
+            break;
+        case 0x4D:
+            /* CMPLT */
+            gen_arith3(ctx, &gen_op_cmplt, ra, rb, rc, islit, lit);
+            break;
+        case 0x60:
+            /* ADDQ/V */
+            gen_arith3(ctx, &gen_op_addqv, ra, rb, rc, islit, lit);
+            break;
+        case 0x69:
+            /* SUBQ/V */
+            gen_arith3(ctx, &gen_op_subqv, ra, rb, rc, islit, lit);
+            break;
+        case 0x6D:
+            /* CMPLE */
+            gen_arith3(ctx, &gen_op_cmple, ra, rb, rc, islit, lit);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x11:
+        switch (fn7) {
+        case 0x00:
+            /* AND */
+            gen_arith3(ctx, &gen_op_and, ra, rb, rc, islit, lit);
+            break;
+        case 0x08:
+            /* BIC */
+            gen_arith3(ctx, &gen_op_bic, ra, rb, rc, islit, lit);
+            break;
+        case 0x14:
+            /* CMOVLBS */
+            gen_cmov(ctx, &gen_op_cmplbs, ra, rb, rc, islit, lit);
+            break;
+        case 0x16:
+            /* CMOVLBC */
+            gen_cmov(ctx, &gen_op_cmplbc, ra, rb, rc, islit, lit);
+            break;
+        case 0x20:
+            /* BIS */
+            if (ra == rb || ra == 31 || rb == 31) {
+                if (ra == 31 && rc == 31) {
+                    /* NOP */
+                    gen_op_nop();
+                } else {
+                    /* MOV */
+                    gen_load_ir(ctx, rb, 0);
+                    gen_store_ir(ctx, rc, 0);
+                }
+            } else {
+                gen_arith3(ctx, &gen_op_bis, ra, rb, rc, islit, lit);
+            }
+            break;
+        case 0x24:
+            /* CMOVEQ */
+            gen_cmov(ctx, &gen_op_cmpeqz, ra, rb, rc, islit, lit);
+            break;
+        case 0x26:
+            /* CMOVNE */
+            gen_cmov(ctx, &gen_op_cmpnez, ra, rb, rc, islit, lit);
+            break;
+        case 0x28:
+            /* ORNOT */
+            gen_arith3(ctx, &gen_op_ornot, ra, rb, rc, islit, lit);
+            break;
+        case 0x40:
+            /* XOR */
+            gen_arith3(ctx, &gen_op_xor, ra, rb, rc, islit, lit);
+            break;
+        case 0x44:
+            /* CMOVLT */
+            gen_cmov(ctx, &gen_op_cmpltz, ra, rb, rc, islit, lit);
+            break;
+        case 0x46:
+            /* CMOVGE */
+            gen_cmov(ctx, &gen_op_cmpgez, ra, rb, rc, islit, lit);
+            break;
+        case 0x48:
+            /* EQV */
+            gen_arith3(ctx, &gen_op_eqv, ra, rb, rc, islit, lit);
+            break;
+        case 0x61:
+            /* AMASK */
+            gen_arith2(ctx, &gen_amask, rb, rc, islit, lit);
+            break;
+        case 0x64:
+            /* CMOVLE */
+            gen_cmov(ctx, &gen_op_cmplez, ra, rb, rc, islit, lit);
+            break;
+        case 0x66:
+            /* CMOVGT */
+            gen_cmov(ctx, &gen_op_cmpgtz, ra, rb, rc, islit, lit);
+            break;
+        case 0x6C:
+            /* IMPLVER */
+            gen_op_load_implver();
+            gen_store_ir(ctx, rc, 0);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x12:
+        switch (fn7) {
+        case 0x02:
+            /* MSKBL */
+            gen_arith3(ctx, &gen_op_mskbl, ra, rb, rc, islit, lit);
+            break;
+        case 0x06:
+            /* EXTBL */
+            gen_arith3(ctx, &gen_op_extbl, ra, rb, rc, islit, lit);
+            break;
+        case 0x0B:
+            /* INSBL */
+            gen_arith3(ctx, &gen_op_insbl, ra, rb, rc, islit, lit);
+            break;
+        case 0x12:
+            /* MSKWL */
+            gen_arith3(ctx, &gen_op_mskwl, ra, rb, rc, islit, lit);
+            break;
+        case 0x16:
+            /* EXTWL */
+            gen_arith3(ctx, &gen_op_extwl, ra, rb, rc, islit, lit);
+            break;
+        case 0x1B:
+            /* INSWL */
+            gen_arith3(ctx, &gen_op_inswl, ra, rb, rc, islit, lit);
+            break;
+        case 0x22:
+            /* MSKLL */
+            gen_arith3(ctx, &gen_op_mskll, ra, rb, rc, islit, lit);
+            break;
+        case 0x26:
+            /* EXTLL */
+            gen_arith3(ctx, &gen_op_extll, ra, rb, rc, islit, lit);
+            break;
+        case 0x2B:
+            /* INSLL */
+            gen_arith3(ctx, &gen_op_insll, ra, rb, rc, islit, lit);
+            break;
+        case 0x30:
+            /* ZAP */
+            gen_arith3(ctx, &gen_op_zap, ra, rb, rc, islit, lit);
+            break;
+        case 0x31:
+            /* ZAPNOT */
+            gen_arith3(ctx, &gen_op_zapnot, ra, rb, rc, islit, lit);
+            break;
+        case 0x32:
+            /* MSKQL */
+            gen_arith3(ctx, &gen_op_mskql, ra, rb, rc, islit, lit);
+            break;
+        case 0x34:
+            /* SRL */
+            gen_arith3(ctx, &gen_op_srl, ra, rb, rc, islit, lit);
+            break;
+        case 0x36:
+            /* EXTQL */
+            gen_arith3(ctx, &gen_op_extql, ra, rb, rc, islit, lit);
+            break;
+        case 0x39:
+            /* SLL */
+            gen_arith3(ctx, &gen_op_sll, ra, rb, rc, islit, lit);
+            break;
+        case 0x3B:
+            /* INSQL */
+            gen_arith3(ctx, &gen_op_insql, ra, rb, rc, islit, lit);
+            break;
+        case 0x3C:
+            /* SRA */
+            gen_arith3(ctx, &gen_op_sra, ra, rb, rc, islit, lit);
+            break;
+        case 0x52:
+            /* MSKWH */
+            gen_arith3(ctx, &gen_op_mskwh, ra, rb, rc, islit, lit);
+            break;
+        case 0x57:
+            /* INSWH */
+            gen_arith3(ctx, &gen_op_inswh, ra, rb, rc, islit, lit);
+            break;
+        case 0x5A:
+            /* EXTWH */
+            gen_arith3(ctx, &gen_op_extwh, ra, rb, rc, islit, lit);
+            break;
+        case 0x62:
+            /* MSKLH */
+            gen_arith3(ctx, &gen_op_msklh, ra, rb, rc, islit, lit);
+            break;
+        case 0x67:
+            /* INSLH */
+            gen_arith3(ctx, &gen_op_inslh, ra, rb, rc, islit, lit);
+            break;
+        case 0x6A:
+            /* EXTLH */
+            gen_arith3(ctx, &gen_op_extlh, ra, rb, rc, islit, lit);
+            break;
+        case 0x72:
+            /* MSKQH */
+            gen_arith3(ctx, &gen_op_mskqh, ra, rb, rc, islit, lit);
+            break;
+        case 0x77:
+            /* INSQH */
+            gen_arith3(ctx, &gen_op_insqh, ra, rb, rc, islit, lit);
+            break;
+        case 0x7A:
+            /* EXTQH */
+            gen_arith3(ctx, &gen_op_extqh, ra, rb, rc, islit, lit);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x13:
+        switch (fn7) {
+        case 0x00:
+            /* MULL */
+            gen_arith3(ctx, &gen_op_mull, ra, rb, rc, islit, lit);
+            break;
+        case 0x20:
+            /* MULQ */
+            gen_arith3(ctx, &gen_op_mulq, ra, rb, rc, islit, lit);
+            break;
+        case 0x30:
+            /* UMULH */
+            gen_arith3(ctx, &gen_op_umulh, ra, rb, rc, islit, lit);
+            break;
+        case 0x40:
+            /* MULL/V */
+            gen_arith3(ctx, &gen_op_mullv, ra, rb, rc, islit, lit);
+            break;
+        case 0x60:
+            /* MULQ/V */
+            gen_arith3(ctx, &gen_op_mulqv, ra, rb, rc, islit, lit);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x14:
+        switch (fpfn) { /* f11 & 0x3F */
+        case 0x04:
+            /* ITOFS */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+            gen_itf(ctx, &gen_op_itofs, ra, rc);
+            break;
+        case 0x0A:
+            /* SQRTF */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+            gen_farith2(ctx, &gen_op_sqrtf, rb, rc);
+            break;
+        case 0x0B:
+            /* SQRTS */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+            gen_farith2(ctx, &gen_op_sqrts, rb, rc);
+            break;
+        case 0x14:
+            /* ITOFF */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+#if 0 // TODO
+            gen_itf(ctx, &gen_op_itoff, ra, rc);
+#else
+            goto invalid_opc;
+#endif
+            break;
+        case 0x24:
+            /* ITOFT */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+            gen_itf(ctx, &gen_op_itoft, ra, rc);
+            break;
+        case 0x2A:
+            /* SQRTG */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+            gen_farith2(ctx, &gen_op_sqrtg, rb, rc);
+            break;
+        case 0x02B:
+            /* SQRTT */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+            gen_farith2(ctx, &gen_op_sqrtt, rb, rc);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x15:
+        /* VAX floating point */
+        /* XXX: rounding mode and trap are ignored (!) */
+        switch (fpfn) { /* f11 & 0x3F */
+        case 0x00:
+            /* ADDF */
+            gen_farith3(ctx, &gen_op_addf, ra, rb, rc);
+            break;
+        case 0x01:
+            /* SUBF */
+            gen_farith3(ctx, &gen_op_subf, ra, rb, rc);
+            break;
+        case 0x02:
+            /* MULF */
+            gen_farith3(ctx, &gen_op_mulf, ra, rb, rc);
+            break;
+        case 0x03:
+            /* DIVF */
+            gen_farith3(ctx, &gen_op_divf, ra, rb, rc);
+            break;
+        case 0x1E:
+            /* CVTDG */
+#if 0 // TODO
+            gen_farith2(ctx, &gen_op_cvtdg, rb, rc);
+#else
+            goto invalid_opc;
+#endif
+            break;
+        case 0x20:
+            /* ADDG */
+            gen_farith3(ctx, &gen_op_addg, ra, rb, rc);
+            break;
+        case 0x21:
+            /* SUBG */
+            gen_farith3(ctx, &gen_op_subg, ra, rb, rc);
+            break;
+        case 0x22:
+            /* MULG */
+            gen_farith3(ctx, &gen_op_mulg, ra, rb, rc);
+            break;
+        case 0x23:
+            /* DIVG */
+            gen_farith3(ctx, &gen_op_divg, ra, rb, rc);
+            break;
+        case 0x25:
+            /* CMPGEQ */
+            gen_farith3(ctx, &gen_op_cmpgeq, ra, rb, rc);
+            break;
+        case 0x26:
+            /* CMPGLT */
+            gen_farith3(ctx, &gen_op_cmpglt, ra, rb, rc);
+            break;
+        case 0x27:
+            /* CMPGLE */
+            gen_farith3(ctx, &gen_op_cmpgle, ra, rb, rc);
+            break;
+        case 0x2C:
+            /* CVTGF */
+            gen_farith2(ctx, &gen_op_cvtgf, rb, rc);
+            break;
+        case 0x2D:
+            /* CVTGD */
+#if 0 // TODO
+            gen_farith2(ctx, &gen_op_cvtgd, rb, rc);
+#else
+            goto invalid_opc;
+#endif
+            break;
+        case 0x2F:
+            /* CVTGQ */
+            gen_farith2(ctx, &gen_op_cvtgq, rb, rc);
+            break;
+        case 0x3C:
+            /* CVTQF */
+            gen_farith2(ctx, &gen_op_cvtqf, rb, rc);
+            break;
+        case 0x3E:
+            /* CVTQG */
+            gen_farith2(ctx, &gen_op_cvtqg, rb, rc);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x16:
+        /* IEEE floating-point */
+        /* XXX: rounding mode and traps are ignored (!) */
+        switch (fpfn) { /* f11 & 0x3F */
+        case 0x00:
+            /* ADDS */
+            gen_farith3(ctx, &gen_op_adds, ra, rb, rc);
+            break;
+        case 0x01:
+            /* SUBS */
+            gen_farith3(ctx, &gen_op_subs, ra, rb, rc);
+            break;
+        case 0x02:
+            /* MULS */
+            gen_farith3(ctx, &gen_op_muls, ra, rb, rc);
+            break;
+        case 0x03:
+            /* DIVS */
+            gen_farith3(ctx, &gen_op_divs, ra, rb, rc);
+            break;
+        case 0x20:
+            /* ADDT */
+            gen_farith3(ctx, &gen_op_addt, ra, rb, rc);
+            break;
+        case 0x21:
+            /* SUBT */
+            gen_farith3(ctx, &gen_op_subt, ra, rb, rc);
+            break;
+        case 0x22:
+            /* MULT */
+            gen_farith3(ctx, &gen_op_mult, ra, rb, rc);
+            break;
+        case 0x23:
+            /* DIVT */
+            gen_farith3(ctx, &gen_op_divt, ra, rb, rc);
+            break;
+        case 0x24:
+            /* CMPTUN */
+            gen_farith3(ctx, &gen_op_cmptun, ra, rb, rc);
+            break;
+        case 0x25:
+            /* CMPTEQ */
+            gen_farith3(ctx, &gen_op_cmpteq, ra, rb, rc);
+            break;
+        case 0x26:
+            /* CMPTLT */
+            gen_farith3(ctx, &gen_op_cmptlt, ra, rb, rc);
+            break;
+        case 0x27:
+            /* CMPTLE */
+            gen_farith3(ctx, &gen_op_cmptle, ra, rb, rc);
+            break;
+        case 0x2C:
+            /* XXX: incorrect */
+            if (fn11 == 0x2AC) {
+                /* CVTST */
+                gen_farith2(ctx, &gen_op_cvtst, rb, rc);
+            } else {
+                /* CVTTS */
+                gen_farith2(ctx, &gen_op_cvtts, rb, rc);
+            }
+            break;
+        case 0x2F:
+            /* CVTTQ */
+            gen_farith2(ctx, &gen_op_cvttq, rb, rc);
+            break;
+        case 0x3C:
+            /* CVTQS */
+            gen_farith2(ctx, &gen_op_cvtqs, rb, rc);
+            break;
+        case 0x3E:
+            /* CVTQT */
+            gen_farith2(ctx, &gen_op_cvtqt, rb, rc);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x17:
+        switch (fn11) {
+        case 0x010:
+            /* CVTLQ */
+            gen_farith2(ctx, &gen_op_cvtlq, rb, rc);
+            break;
+        case 0x020:
+            /* CPYS */
+            if (ra == rb) {
+                if (ra == 31 && rc == 31) {
+                    /* FNOP */
+                    gen_op_nop();
+                } else {
+                    /* FMOV */
+                    gen_load_fir(ctx, rb, 0);
+                    gen_store_fir(ctx, rc, 0);
+                }
+            } else {
+                gen_farith3(ctx, &gen_op_cpys, ra, rb, rc);
+            }
+            break;
+        case 0x021:
+            /* CPYSN */
+            gen_farith2(ctx, &gen_op_cpysn, rb, rc);
+            break;
+        case 0x022:
+            /* CPYSE */
+            gen_farith2(ctx, &gen_op_cpyse, rb, rc);
+            break;
+        case 0x024:
+            /* MT_FPCR */
+            gen_load_fir(ctx, ra, 0);
+            gen_op_store_fpcr();
+            break;
+        case 0x025:
+            /* MF_FPCR */
+            gen_op_load_fpcr();
+            gen_store_fir(ctx, ra, 0);
+            break;
+        case 0x02A:
+            /* FCMOVEQ */
+            gen_fcmov(ctx, &gen_op_cmpfeq, ra, rb, rc);
+            break;
+        case 0x02B:
+            /* FCMOVNE */
+            gen_fcmov(ctx, &gen_op_cmpfne, ra, rb, rc);
+            break;
+        case 0x02C:
+            /* FCMOVLT */
+            gen_fcmov(ctx, &gen_op_cmpflt, ra, rb, rc);
+            break;
+        case 0x02D:
+            /* FCMOVGE */
+            gen_fcmov(ctx, &gen_op_cmpfge, ra, rb, rc);
+            break;
+        case 0x02E:
+            /* FCMOVLE */
+            gen_fcmov(ctx, &gen_op_cmpfle, ra, rb, rc);
+            break;
+        case 0x02F:
+            /* FCMOVGT */
+            gen_fcmov(ctx, &gen_op_cmpfgt, ra, rb, rc);
+            break;
+        case 0x030:
+            /* CVTQL */
+            gen_farith2(ctx, &gen_op_cvtql, rb, rc);
+            break;
+        case 0x130:
+            /* CVTQL/V */
+            gen_farith2(ctx, &gen_op_cvtqlv, rb, rc);
+            break;
+        case 0x530:
+            /* CVTQL/SV */
+            gen_farith2(ctx, &gen_op_cvtqlsv, rb, rc);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x18:
+        switch ((uint16_t)disp16) {
+        case 0x0000:
+            /* TRAPB */
+            /* No-op. Just exit from the current tb */
+            ret = 2;
+            break;
+        case 0x0400:
+            /* EXCB */
+            /* No-op. Just exit from the current tb */
+            ret = 2;
+            break;
+        case 0x4000:
+            /* MB */
+            /* No-op */
+            break;
+        case 0x4400:
+            /* WMB */
+            /* No-op */
+            break;
+        case 0x8000:
+            /* FETCH */
+            /* No-op */
+            break;
+        case 0xA000:
+            /* FETCH_M */
+            /* No-op */
+            break;
+        case 0xC000:
+            /* RPCC */
+            gen_op_load_pcc();
+            gen_store_ir(ctx, ra, 0);
+            break;
+        case 0xE000:
+            /* RC */
+            gen_op_load_irf();
+            gen_store_ir(ctx, ra, 0);
+            gen_op_clear_irf();
+            break;
+        case 0xE800:
+            /* ECB */
+            /* XXX: TODO: evict tb cache at address rb */
+#if 0
+            ret = 2;
+#else
+            goto invalid_opc;
+#endif
+            break;
+        case 0xF000:
+            /* RS */
+            gen_op_load_irf();
+            gen_store_ir(ctx, ra, 0);
+            gen_op_set_irf();
+            break;
+        case 0xF800:
+            /* WH64 */
+            /* No-op */
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x19:
+        /* HW_MFPR (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+        goto invalid_opc;
+#else
+        if (!ctx->pal_mode)
+            goto invalid_opc;
+        gen_op_mfpr(insn & 0xFF);
+        gen_store_ir(ctx, ra, 0);
+        break;
+#endif
+    case 0x1A:
+        gen_load_ir(ctx, rb, 0);
+        if (ra != 31) {
+            gen_set_uT1(ctx, ctx->pc);
+            gen_store_ir(ctx, ra, 1);
+        }
+        gen_op_branch();
+        /* Those four jumps only differ by the branch prediction hint */
+        switch (fn2) {
+        case 0x0:
+            /* JMP */
+            break;
+        case 0x1:
+            /* JSR */
+            break;
+        case 0x2:
+            /* RET */
+            break;
+        case 0x3:
+            /* JSR_COROUTINE */
+            break;
+        }
+        ret = 1;
+        break;
+    case 0x1B:
+        /* HW_LD (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+        goto invalid_opc;
+#else
+        if (!ctx->pal_mode)
+            goto invalid_opc;
+        gen_load_ir(ctx, rb, 0);
+        gen_set_sT1(ctx, disp12);
+        gen_op_addq();
+        switch ((insn >> 12) & 0xF) {
+        case 0x0:
+            /* Longword physical access */
+            gen_op_ldl_raw();
+            break;
+        case 0x1:
+            /* Quadword physical access */
+            gen_op_ldq_raw();
+            break;
+        case 0x2:
+            /* Longword physical access with lock */
+            gen_op_ldl_l_raw();
+            break;
+        case 0x3:
+            /* Quadword physical access with lock */
+            gen_op_ldq_l_raw();
+            break;
+        case 0x4:
+            /* Longword virtual PTE fetch */
+            gen_op_ldl_kernel();
+            break;
+        case 0x5:
+            /* Quadword virtual PTE fetch */
+            gen_op_ldq_kernel();
+            break;
+        case 0x6:
+            /* Invalid */
+            goto invalid_opc;
+        case 0x7:
+            /* Invalid */
+            goto invalid_opc;
+        case 0x8:
+            /* Longword virtual access */
+            gen_op_ld_phys_to_virt();
+            gen_op_ldl_raw();
+            break;
+        case 0x9:
+            /* Quadword virtual access */
+            gen_op_ld_phys_to_virt();
+            gen_op_ldq_raw();
+            break;
+        case 0xA:
+            /* Longword virtual access with protection check */
+            gen_ldl(ctx);
+            break;
+        case 0xB:
+            /* Quadword virtual access with protection check */
+            gen_ldq(ctx);
+            break;
+        case 0xC:
+            /* Longword virtual access with altenate access mode */
+            gen_op_set_alt_mode();
+            gen_op_ld_phys_to_virt();
+            gen_op_ldl_raw();
+            gen_op_restore_mode();
+            break;
+        case 0xD:
+            /* Quadword virtual access with altenate access mode */
+            gen_op_set_alt_mode();
+            gen_op_ld_phys_to_virt();
+            gen_op_ldq_raw();
+            gen_op_restore_mode();
+            break;
+        case 0xE:
+            /* Longword virtual access with alternate access mode and
+             * protection checks
+             */
+            gen_op_set_alt_mode();
+            gen_op_ldl_data();
+            gen_op_restore_mode();
+            break;
+        case 0xF:
+            /* Quadword virtual access with alternate access mode and
+             * protection checks
+             */
+            gen_op_set_alt_mode();
+            gen_op_ldq_data();
+            gen_op_restore_mode();
+            break;
+        }
+        gen_store_ir(ctx, ra, 1);
+        break;
+#endif
+    case 0x1C:
+        switch (fn7) {
+        case 0x00:
+            /* SEXTB */
+            if (!(ctx->amask & AMASK_BWX))
+                goto invalid_opc;
+            gen_arith2(ctx, &gen_op_sextb, rb, rc, islit, lit);
+            break;
+        case 0x01:
+            /* SEXTW */
+            if (!(ctx->amask & AMASK_BWX))
+                goto invalid_opc;
+            gen_arith2(ctx, &gen_op_sextw, rb, rc, islit, lit);
+            break;
+        case 0x30:
+            /* CTPOP */
+            if (!(ctx->amask & AMASK_CIX))
+                goto invalid_opc;
+            gen_arith2(ctx, &gen_op_ctpop, rb, rc, 0, 0);
+            break;
+        case 0x31:
+            /* PERR */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x32:
+            /* CTLZ */
+            if (!(ctx->amask & AMASK_CIX))
+                goto invalid_opc;
+            gen_arith2(ctx, &gen_op_ctlz, rb, rc, 0, 0);
+            break;
+        case 0x33:
+            /* CTTZ */
+            if (!(ctx->amask & AMASK_CIX))
+                goto invalid_opc;
+            gen_arith2(ctx, &gen_op_cttz, rb, rc, 0, 0);
+            break;
+        case 0x34:
+            /* UNPKBW */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x35:
+            /* UNPKWL */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x36:
+            /* PKWB */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x37:
+            /* PKLB */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x38:
+            /* MINSB8 */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x39:
+            /* MINSW4 */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x3A:
+            /* MINUB8 */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x3B:
+            /* MINUW4 */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x3C:
+            /* MAXUB8 */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x3D:
+            /* MAXUW4 */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x3E:
+            /* MAXSB8 */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x3F:
+            /* MAXSW4 */
+            if (!(ctx->amask & AMASK_MVI))
+                goto invalid_opc;
+            /* XXX: TODO */
+            goto invalid_opc;
+            break;
+        case 0x70:
+            /* FTOIT */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+            gen_fti(ctx, &gen_op_ftoit, ra, rb);
+            break;
+        case 0x78:
+            /* FTOIS */
+            if (!(ctx->amask & AMASK_FIX))
+                goto invalid_opc;
+            gen_fti(ctx, &gen_op_ftois, ra, rb);
+            break;
+        default:
+            goto invalid_opc;
+        }
+        break;
+    case 0x1D:
+        /* HW_MTPR (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+        goto invalid_opc;
+#else
+        if (!ctx->pal_mode)
+            goto invalid_opc;
+        gen_load_ir(ctx, ra, 0);
+        gen_op_mtpr(insn & 0xFF);
+        ret = 2;
+        break;
+#endif
+    case 0x1E:
+        /* HW_REI (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+        goto invalid_opc;
+#else
+        if (!ctx->pal_mode)
+            goto invalid_opc;
+        if (rb == 31) {
+            /* "Old" alpha */
+            gen_op_hw_rei();
+        } else {
+            gen_load_ir(ctx, rb, 0);
+            gen_set_uT1(ctx, (((int64_t)insn << 51) >> 51));
+            gen_op_addq();
+            gen_op_hw_ret();
+        }
+        ret = 2;
+        break;
+#endif
+    case 0x1F:
+        /* HW_ST (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+        goto invalid_opc;
+#else
+        if (!ctx->pal_mode)
+            goto invalid_opc;
+        gen_load_ir(ctx, rb, 0);
+        gen_set_sT1(ctx, disp12);
+        gen_op_addq();
+        gen_load_ir(ctx, ra, 1);
+        switch ((insn >> 12) & 0xF) {
+        case 0x0:
+            /* Longword physical access */
+            gen_op_stl_raw();
+            break;
+        case 0x1:
+            /* Quadword physical access */
+            gen_op_stq_raw();
+            break;
+        case 0x2:
+            /* Longword physical access with lock */
+            gen_op_stl_c_raw();
+            break;
+        case 0x3:
+            /* Quadword physical access with lock */
+            gen_op_stq_c_raw();
+            break;
+        case 0x4:
+            /* Longword virtual access */
+            gen_op_st_phys_to_virt();
+            gen_op_stl_raw();
+            break;
+        case 0x5:
+            /* Quadword virtual access */
+            gen_op_st_phys_to_virt();
+            gen_op_stq_raw();
+            break;
+        case 0x6:
+            /* Invalid */
+            goto invalid_opc;
+        case 0x7:
+            /* Invalid */
+            goto invalid_opc;
+        case 0x8:
+            /* Invalid */
+            goto invalid_opc;
+        case 0x9:
+            /* Invalid */
+            goto invalid_opc;
+        case 0xA:
+            /* Invalid */
+            goto invalid_opc;
+        case 0xB:
+            /* Invalid */
+            goto invalid_opc;
+        case 0xC:
+            /* Longword virtual access with alternate access mode */
+            gen_op_set_alt_mode();
+            gen_op_st_phys_to_virt();
+            gen_op_ldl_raw();
+            gen_op_restore_mode();
+            break;
+        case 0xD:
+            /* Quadword virtual access with alternate access mode */
+            gen_op_set_alt_mode();
+            gen_op_st_phys_to_virt();
+            gen_op_ldq_raw();
+            gen_op_restore_mode();
+            break;
+        case 0xE:
+            /* Invalid */
+            goto invalid_opc;
+        case 0xF:
+            /* Invalid */
+            goto invalid_opc;
+        }
+        ret = 2;
+        break;
+#endif
+    case 0x20:
+        /* LDF */
+#if 0 // TODO
+        gen_load_fmem(ctx, &gen_ldf, ra, rb, disp16);
+#else
+        goto invalid_opc;
+#endif
+        break;
+    case 0x21:
+        /* LDG */
+#if 0 // TODO
+        gen_load_fmem(ctx, &gen_ldg, ra, rb, disp16);
+#else
+        goto invalid_opc;
+#endif
+        break;
+    case 0x22:
+        /* LDS */
+        gen_load_fmem(ctx, &gen_lds, ra, rb, disp16);
+        break;
+    case 0x23:
+        /* LDT */
+        gen_load_fmem(ctx, &gen_ldt, ra, rb, disp16);
+        break;
+    case 0x24:
+        /* STF */
+#if 0 // TODO
+        gen_store_fmem(ctx, &gen_stf, ra, rb, disp16);
+#else
+        goto invalid_opc;
+#endif
+        break;
+    case 0x25:
+        /* STG */
+#if 0 // TODO
+        gen_store_fmem(ctx, &gen_stg, ra, rb, disp16);
+#else
+        goto invalid_opc;
+#endif
+        break;
+    case 0x26:
+        /* STS */
+        gen_store_fmem(ctx, &gen_sts, ra, rb, disp16);
+        break;
+    case 0x27:
+        /* STT */
+        gen_store_fmem(ctx, &gen_stt, ra, rb, disp16);
+        break;
+    case 0x28:
+        /* LDL */
+        gen_load_mem(ctx, &gen_ldl, ra, rb, disp16, 0);
+        break;
+    case 0x29:
+        /* LDQ */
+        gen_load_mem(ctx, &gen_ldq, ra, rb, disp16, 0);
+        break;
+    case 0x2A:
+        /* LDL_L */
+        gen_load_mem(ctx, &gen_ldl_l, ra, rb, disp16, 0);
+        break;
+    case 0x2B:
+        /* LDQ_L */
+        gen_load_mem(ctx, &gen_ldq_l, ra, rb, disp16, 0);
+        break;
+    case 0x2C:
+        /* STL */
+        gen_store_mem(ctx, &gen_stl, ra, rb, disp16, 0);
+        break;
+    case 0x2D:
+        /* STQ */
+        gen_store_mem(ctx, &gen_stq, ra, rb, disp16, 0);
+        break;
+    case 0x2E:
+        /* STL_C */
+        gen_store_mem(ctx, &gen_stl_c, ra, rb, disp16, 0);
+        break;
+    case 0x2F:
+        /* STQ_C */
+        gen_store_mem(ctx, &gen_stq_c, ra, rb, disp16, 0);
+        break;
+    case 0x30:
+        /* BR */
+        gen_set_uT0(ctx, ctx->pc);
+        gen_store_ir(ctx, ra, 0);
+        if (disp21 != 0) {
+            gen_set_sT1(ctx, disp21 << 2);
+            gen_op_addq();
+        }
+        gen_op_branch();
+        ret = 1;
+        break;
+    case 0x31:
+        /* FBEQ */
+        gen_fbcond(ctx, &gen_op_cmpfeq, ra, disp16);
+        ret = 1;
+        break;
+    case 0x32:
+        /* FBLT */
+        gen_fbcond(ctx, &gen_op_cmpflt, ra, disp16);
+        ret = 1;
+        break;
+    case 0x33:
+        /* FBLE */
+        gen_fbcond(ctx, &gen_op_cmpfle, ra, disp16);
+        ret = 1;
+        break;
+    case 0x34:
+        /* BSR */
+        gen_set_uT0(ctx, ctx->pc);
+        gen_store_ir(ctx, ra, 0);
+        if (disp21 != 0) {
+            gen_set_sT1(ctx, disp21 << 2);
+            gen_op_addq();
+        }
+        gen_op_branch();
+        ret = 1;
+        break;
+    case 0x35:
+        /* FBNE */
+        gen_fbcond(ctx, &gen_op_cmpfne, ra, disp16);
+        ret = 1;
+        break;
+    case 0x36:
+        /* FBGE */
+        gen_fbcond(ctx, &gen_op_cmpfge, ra, disp16);
+        ret = 1;
+        break;
+    case 0x37:
+        /* FBGT */
+        gen_fbcond(ctx, &gen_op_cmpfgt, ra, disp16);
+        ret = 1;
+        break;
+    case 0x38:
+        /* BLBC */
+        gen_bcond(ctx, &gen_op_cmplbc, ra, disp16);
+        ret = 1;
+        break;
+    case 0x39:
+        /* BEQ */
+        gen_bcond(ctx, &gen_op_cmpeqz, ra, disp16);
+        ret = 1;
+        break;
+    case 0x3A:
+        /* BLT */
+        gen_bcond(ctx, &gen_op_cmpltz, ra, disp16);
+        ret = 1;
+        break;
+    case 0x3B:
+        /* BLE */
+        gen_bcond(ctx, &gen_op_cmplez, ra, disp16);
+        ret = 1;
+        break;
+    case 0x3C:
+        /* BLBS */
+        gen_bcond(ctx, &gen_op_cmplbs, ra, disp16);
+        ret = 1;
+        break;
+    case 0x3D:
+        /* BNE */
+        gen_bcond(ctx, &gen_op_cmpnez, ra, disp16);
+        ret = 1;
+        break;
+    case 0x3E:
+        /* BGE */
+        gen_bcond(ctx, &gen_op_cmpgez, ra, disp16);
+        ret = 1;
+        break;
+    case 0x3F:
+        /* BGT */
+        gen_bcond(ctx, &gen_op_cmpgtz, ra, disp16);
+        ret = 1;
+        break;
+    invalid_opc:
+        gen_invalid(ctx);
+        ret = 3;
+        break;
+    }
+
+    return ret;
+}
+
+int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
+                                    int search_pc)
+{
+#if defined ALPHA_DEBUG_DISAS
+    static int insn_count;
+#endif
+    DisasContext ctx, *ctxp = &ctx;
+    target_ulong pc_start;
+    uint32_t insn;
+    uint16_t *gen_opc_end;
+    int j, lj = -1;
+    int ret;
+
+    pc_start = tb->pc;
+    gen_opc_ptr = gen_opc_buf;
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+    gen_opparam_ptr = gen_opparam_buf;
+    nb_gen_labels = 0;
+    ctx.pc = pc_start;
+    ctx.amask = env->amask;
+#if defined (CONFIG_USER_ONLY)
+    ctx.mem_idx = 0;
+#else
+    ctx.mem_idx = ((env->ps >> 3) & 3);
+    ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
+#endif
+    for (ret = 0; ret == 0;) {
+        if (env->nb_breakpoints > 0) {
+            for(j = 0; j < env->nb_breakpoints; j++) {
+                if (env->breakpoints[j] == ctx.pc) {
+                    gen_excp(&ctx, EXCP_DEBUG, 0);
+                    break;
+                }
+            }
+        }
+        if (search_pc) {
+            j = gen_opc_ptr - gen_opc_buf;
+            if (lj < j) {
+                lj++;
+                while (lj < j)
+                    gen_opc_instr_start[lj++] = 0;
+                gen_opc_pc[lj] = ctx.pc;
+                gen_opc_instr_start[lj] = 1;
+            }
+        }
+#if defined ALPHA_DEBUG_DISAS
+        insn_count++;
+        if (logfile != NULL) {
+            fprintf(logfile, "pc " TARGET_FMT_lx " mem_idx %d\n",
+                    ctx.pc, ctx.mem_idx);
+        }
+#endif
+        insn = ldl_code(ctx.pc);
+#if defined ALPHA_DEBUG_DISAS
+        insn_count++;
+        if (logfile != NULL) {
+            fprintf(logfile, "opcode %08x %d\n", insn, insn_count);
+        }
+#endif
+        ctx.pc += 4;
+        ret = translate_one(ctxp, insn);
+        if (ret != 0)
+            break;
+        /* if we reach a page boundary or are single stepping, stop
+         * generation
+         */
+        if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) ||
+            (env->singlestep_enabled)) {
+            break;
+        }
+#if defined (DO_SINGLE_STEP)
+        break;
+#endif
+    }
+    if (ret != 1 && ret != 3) {
+        gen_update_pc(&ctx);
+    }
+    gen_op_reset_T0();
+#if defined (DO_TB_FLUSH)
+    gen_op_tb_flush();
+#endif
+    /* Generate the return instruction */
+    gen_op_exit_tb();
+    *gen_opc_ptr = INDEX_op_end;
+    if (search_pc) {
+        j = gen_opc_ptr - gen_opc_buf;
+        lj++;
+        while (lj <= j)
+            gen_opc_instr_start[lj++] = 0;
+    } else {
+        tb->size = ctx.pc - pc_start;
+    }
+#if defined ALPHA_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_CPU) {
+        cpu_dump_state(env, logfile, fprintf, 0);
+    }
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+	target_disas(logfile, pc_start, ctx.pc - pc_start, 1);
+        fprintf(logfile, "\n");
+    }
+    if (loglevel & CPU_LOG_TB_OP) {
+        fprintf(logfile, "OP:\n");
+        dump_ops(gen_opc_buf, gen_opparam_buf);
+        fprintf(logfile, "\n");
+    }
+#endif
+
+    return 0;
+}
+
+int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+    return gen_intermediate_code_internal(env, tb, 0);
+}
+
+int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+    return gen_intermediate_code_internal(env, tb, 1);
+}
+
+CPUAlphaState * cpu_alpha_init (void)
+{
+    CPUAlphaState *env;
+    uint64_t hwpcb;
+
+    env = qemu_mallocz(sizeof(CPUAlphaState));
+    if (!env)
+        return NULL;
+    cpu_exec_init(env);
+    tlb_flush(env, 1);
+    /* XXX: should not be hardcoded */
+    env->implver = IMPLVER_2106x;
+    env->ps = 0x1F00;
+#if defined (CONFIG_USER_ONLY)
+    env->ps |= 1 << 3;
+#endif
+    pal_init(env);
+    /* Initialize IPR */
+    hwpcb = env->ipr[IPR_PCBB];
+    env->ipr[IPR_ASN] = 0;
+    env->ipr[IPR_ASTEN] = 0;
+    env->ipr[IPR_ASTSR] = 0;
+    env->ipr[IPR_DATFX] = 0;
+    /* XXX: fix this */
+    //    env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8);
+    //    env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0);
+    //    env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16);
+    //    env->ipr[IPR_USP] = ldq_raw(hwpcb + 24);
+    env->ipr[IPR_FEN] = 0;
+    env->ipr[IPR_IPL] = 31;
+    env->ipr[IPR_MCES] = 0;
+    env->ipr[IPR_PERFMON] = 0; /* Implementation specific */
+    //    env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32);
+    env->ipr[IPR_SISR] = 0;
+    env->ipr[IPR_VIRBND] = -1ULL;
+
+    return env;
+}
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 3208c13..76fdbb2 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1,6 +1,6 @@
 /*
  * ARM virtual CPU header
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -38,6 +38,11 @@
 #define EXCP_FIQ             6
 #define EXCP_BKPT            7
 
+typedef void ARMWriteCPFunc(void *opaque, int cp_info,
+                            int srcreg, int operand, uint32_t value);
+typedef uint32_t ARMReadCPFunc(void *opaque, int cp_info,
+                               int dstreg, int operand);
+
 /* We currently assume float and double are IEEE single and double
    precision respectively.
    Doing runtime conversions is tricky because VFP registers may contain
@@ -59,11 +64,11 @@
     uint32_t banked_spsr[6];
     uint32_t banked_r13[6];
     uint32_t banked_r14[6];
-    
+
     /* These hold r8-r12.  */
     uint32_t usr_regs[5];
     uint32_t fiq_regs[5];
-    
+
     /* cpsr flag cache for faster execution */
     uint32_t CF; /* 0 or 1 */
     uint32_t VF; /* V is the bit 31. All other bits are undefined */
@@ -75,20 +80,38 @@
     /* System control coprocessor (cp15) */
     struct {
         uint32_t c0_cpuid;
+        uint32_t c0_cachetype;
         uint32_t c1_sys; /* System control register.  */
         uint32_t c1_coproc; /* Coprocessor access register.  */
-        uint32_t c2; /* MMU translation table base.  */
-        uint32_t c3; /* MMU domain access control register.  */
+        uint32_t c1_xscaleauxcr; /* XScale auxiliary control register.  */
+        uint32_t c2_base; /* MMU translation table base.  */
+        uint32_t c2_data; /* MPU data cachable bits.  */
+        uint32_t c2_insn; /* MPU instruction cachable bits.  */
+        uint32_t c3; /* MMU domain access control register
+                        MPU write buffer control.  */
         uint32_t c5_insn; /* Fault status registers.  */
         uint32_t c5_data;
+        uint32_t c6_region[8]; /* MPU base/size registers.  */
         uint32_t c6_insn; /* Fault address registers.  */
         uint32_t c6_data;
         uint32_t c9_insn; /* Cache lockdown registers.  */
         uint32_t c9_data;
         uint32_t c13_fcse; /* FCSE PID.  */
         uint32_t c13_context; /* Context ID.  */
+        uint32_t c15_cpar; /* XScale Coprocessor Access Register */
+        uint32_t c15_ticonfig; /* TI925T configuration byte.  */
+        uint32_t c15_i_max; /* Maximum D-cache dirty line index.  */
+        uint32_t c15_i_min; /* Minimum D-cache dirty line index.  */
+        uint32_t c15_threadid; /* TI debugger thread-ID.  */
     } cp15;
 
+    /* Coprocessor IO used by peripherals */
+    struct {
+        ARMReadCPFunc *cp_read;
+        ARMWriteCPFunc *cp_write;
+        void *opaque;
+    } cp[15];
+
     /* Internal CPU feature flags.  */
     uint32_t features;
 
@@ -111,10 +134,18 @@
         /* Temporary variables if we don't have spare fp regs.  */
         float32 tmp0s, tmp1s;
         float64 tmp0d, tmp1d;
-        
+
         float_status fp_status;
     } vfp;
 
+    /* iwMMXt coprocessor state.  */
+    struct {
+        uint64_t regs[16];
+        uint64_t val;
+
+        uint32_t cregs[16];
+    } iwmmxt;
+
 #if defined(CONFIG_USER_ONLY)
     /* For usermode syscall translation.  */
     int eabi;
@@ -122,6 +153,13 @@
 
     CPU_COMMON
 
+    /* These fields after the common ones so they are preserved on reset.  */
+    int ram_size;
+    const char *kernel_filename;
+    const char *kernel_cmdline;
+    const char *initrd_filename;
+    int board_id;
+    target_phys_addr_t loader_start;
 } CPUARMState;
 
 CPUARMState *cpu_arm_init(void);
@@ -133,7 +171,7 @@
 /* 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.  */
-int cpu_arm_signal_handler(int host_signum, void *pinfo, 
+int cpu_arm_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 
 #define CPSR_M (0x1f)
@@ -155,7 +193,7 @@
 {
     int ZF;
     ZF = (env->NZF == 0);
-    return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) | 
+    return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
         (env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
         | (env->thumb << 5);
 }
@@ -198,10 +236,23 @@
 #define ARM_VFP_FPINST  9
 #define ARM_VFP_FPINST2 10
 
+/* iwMMXt coprocessor control registers.  */
+#define ARM_IWMMXT_wCID		0
+#define ARM_IWMMXT_wCon		1
+#define ARM_IWMMXT_wCSSF	2
+#define ARM_IWMMXT_wCASF	3
+#define ARM_IWMMXT_wCGR0	8
+#define ARM_IWMMXT_wCGR1	9
+#define ARM_IWMMXT_wCGR2	10
+#define ARM_IWMMXT_wCGR3	11
 
 enum arm_features {
     ARM_FEATURE_VFP,
-    ARM_FEATURE_AUXCR /* ARM1026 Auxiliary control register.  */
+    ARM_FEATURE_AUXCR,  /* ARM1026 Auxiliary control register.  */
+    ARM_FEATURE_XSCALE, /* Intel XScale extensions.  */
+    ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension.  */
+    ARM_FEATURE_MPU,    /* Only has Memory Protection Unit, not full MMU.  */
+    ARM_FEATURE_OMAPCP  /* OMAP specific CP15 ops handling.  */
 };
 
 static inline int arm_feature(CPUARMState *env, int feature)
@@ -209,19 +260,46 @@
     return (env->features & (1u << feature)) != 0;
 }
 
-void cpu_arm_set_model(CPUARMState *env, uint32_t id);
+void arm_cpu_list(void);
+void cpu_arm_set_model(CPUARMState *env, const char *name);
 
-#define ARM_CPUID_ARM1026 0x4106a262
-#define ARM_CPUID_ARM926  0x41069265
+void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
+                       ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+                       void *opaque);
+
+#define ARM_CPUID_ARM1026   0x4106a262
+#define ARM_CPUID_ARM926    0x41069265
+#define ARM_CPUID_ARM946    0x41059461
+#define ARM_CPUID_TI915T    0x54029152
+#define ARM_CPUID_TI925T    0x54029252
+#define ARM_CPUID_PXA250    0x69052100
+#define ARM_CPUID_PXA255    0x69052d00
+#define ARM_CPUID_PXA260    0x69052903
+#define ARM_CPUID_PXA261    0x69052d05
+#define ARM_CPUID_PXA262    0x69052d06
+#define ARM_CPUID_PXA270    0x69054110
+#define ARM_CPUID_PXA270_A0 0x69054110
+#define ARM_CPUID_PXA270_A1 0x69054111
+#define ARM_CPUID_PXA270_B0 0x69054112
+#define ARM_CPUID_PXA270_B1 0x69054113
+#define ARM_CPUID_PXA270_C0 0x69054114
+#define ARM_CPUID_PXA270_C5 0x69054117
 
 #if defined(CONFIG_USER_ONLY)
 #define TARGET_PAGE_BITS 12
 #else
 /* The ARM MMU allows 1k pages.  */
 /* ??? Linux doesn't actually use these, and they're deprecated in recent
-   architecture revisions.  Maybe an a configure option to disable them.  */
+   architecture revisions.  Maybe a configure option to disable them.  */
 #define TARGET_PAGE_BITS 10
 #endif
+
+#define CPUState CPUARMState
+#define cpu_init cpu_arm_init
+#define cpu_exec cpu_arm_exec
+#define cpu_gen_code cpu_arm_gen_code
+#define cpu_signal_handler cpu_arm_signal_handler
+
 #include "cpu-all.h"
 
 #endif
diff --git a/target-arm/exec.h b/target-arm/exec.h
index deba893..9da1915 100644
--- a/target-arm/exec.h
+++ b/target-arm/exec.h
@@ -1,6 +1,6 @@
 /*
  *  ARM execution defines
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -17,19 +17,13 @@
  * 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 "config.h"
 #include "dyngen-exec.h"
 
-#if defined(__sparc__)
-struct CPUARMState *env;
-uint32_t T0;
-uint32_t T1;
-uint32_t T2;
-#else
 register struct CPUARMState *env asm(AREG0);
 register uint32_t T0 asm(AREG1);
 register uint32_t T1 asm(AREG2);
 register uint32_t T2 asm(AREG3);
-#endif
 
 /* TODO: Put these in FP regs on targets that have such things.  */
 /* It is ok for FT0s and FT0d to overlap.  Likewise FT1s and FT1d.  */
@@ -38,6 +32,8 @@
 #define FT0d env->vfp.tmp0d
 #define FT1d env->vfp.tmp1d
 
+#define M0   env->iwmmxt.val
+
 #include "cpu.h"
 #include "exec-all.h"
 
@@ -52,6 +48,20 @@
 int cpu_arm_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu);
 
+static inline int cpu_halted(CPUState *env) {
+    if (!env->halted)
+        return 0;
+    /* An interrupt wakes the CPU even if the I and F CPSR bits are
+       set.  We use EXITTB to silently wake CPU without causing an
+       actual interrupt.  */
+    if (env->interrupt_request &
+        (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
 #if !defined(CONFIG_USER_ONLY)
 #include "softmmu_exec.h"
 #endif
@@ -60,6 +70,8 @@
 
 void cpu_lock(void);
 void cpu_unlock(void);
+void helper_set_cp(CPUState *, uint32_t, uint32_t);
+uint32_t helper_get_cp(CPUState *, uint32_t);
 void helper_set_cp15(CPUState *, uint32_t, uint32_t);
 uint32_t helper_get_cp15(CPUState *, uint32_t);
 
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 5b4cd13..01573a2 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -5,8 +5,78 @@
 #include "cpu.h"
 #include "exec-all.h"
 
+static inline void set_feature(CPUARMState *env, int feature)
+{
+    env->features |= 1u << feature;
+}
+
+static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
+{
+    env->cp15.c0_cpuid = id;
+    switch (id) {
+    case ARM_CPUID_ARM926:
+        set_feature(env, ARM_FEATURE_VFP);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        env->cp15.c1_sys = 0x00090078;
+        break;
+    case ARM_CPUID_ARM946:
+        set_feature(env, ARM_FEATURE_MPU);
+        env->cp15.c0_cachetype = 0x0f004006;
+        env->cp15.c1_sys = 0x00000078;
+        break;
+    case ARM_CPUID_ARM1026:
+        set_feature(env, ARM_FEATURE_VFP);
+        set_feature(env, ARM_FEATURE_AUXCR);
+        env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
+        env->cp15.c0_cachetype = 0x1dd20d2;
+        env->cp15.c1_sys = 0x00090078;
+        break;
+    case ARM_CPUID_TI915T:
+    case ARM_CPUID_TI925T:
+        set_feature(env, ARM_FEATURE_OMAPCP);
+        env->cp15.c0_cpuid = ARM_CPUID_TI925T; /* Depends on wiring.  */
+        env->cp15.c0_cachetype = 0x5109149;
+        env->cp15.c1_sys = 0x00000070;
+        env->cp15.c15_i_max = 0x000;
+        env->cp15.c15_i_min = 0xff0;
+        break;
+    case ARM_CPUID_PXA250:
+    case ARM_CPUID_PXA255:
+    case ARM_CPUID_PXA260:
+    case ARM_CPUID_PXA261:
+    case ARM_CPUID_PXA262:
+        set_feature(env, ARM_FEATURE_XSCALE);
+        /* JTAG_ID is ((id << 28) | 0x09265013) */
+        env->cp15.c0_cachetype = 0xd172172;
+        env->cp15.c1_sys = 0x00000078;
+        break;
+    case ARM_CPUID_PXA270_A0:
+    case ARM_CPUID_PXA270_A1:
+    case ARM_CPUID_PXA270_B0:
+    case ARM_CPUID_PXA270_B1:
+    case ARM_CPUID_PXA270_C0:
+    case ARM_CPUID_PXA270_C5:
+        set_feature(env, ARM_FEATURE_XSCALE);
+        /* JTAG_ID is ((id << 28) | 0x09265013) */
+        set_feature(env, ARM_FEATURE_IWMMXT);
+        env->iwmmxt.cregs[ARM_IWMMXT_wCID] = 0x69051000 | 'Q';
+        env->cp15.c0_cachetype = 0xd172172;
+        env->cp15.c1_sys = 0x00000078;
+        break;
+    default:
+        cpu_abort(env, "Bad CPU ID: %x\n", id);
+        break;
+    }
+}
+
 void cpu_reset(CPUARMState *env)
 {
+    uint32_t id;
+    id = env->cp15.c0_cpuid;
+    memset(env, 0, offsetof(CPUARMState, breakpoints));
+    if (id)
+        cpu_reset_model_id(env, id);
 #if defined (CONFIG_USER_ONLY)
     env->uncached_cpsr = ARM_CPU_MODE_USR;
     env->vfp.xregs[ARM_VFP_FPEXC] = 1 << 30;
@@ -16,6 +86,7 @@
     env->vfp.xregs[ARM_VFP_FPEXC] = 0;
 #endif
     env->regs[15] = 0;
+    tlb_flush(env, 1);
 }
 
 CPUARMState *cpu_arm_init(void)
@@ -27,32 +98,62 @@
         return NULL;
     cpu_exec_init(env);
     cpu_reset(env);
-    tlb_flush(env, 1);
     return env;
 }
 
-static inline void set_feature(CPUARMState *env, int feature)
+struct arm_cpu_t {
+    uint32_t id;
+    const char *name;
+};
+
+static const struct arm_cpu_t arm_cpu_names[] = {
+    { ARM_CPUID_ARM926, "arm926"},
+    { ARM_CPUID_ARM946, "arm946"},
+    { ARM_CPUID_ARM1026, "arm1026"},
+    { ARM_CPUID_TI925T, "ti925t" },
+    { ARM_CPUID_PXA250, "pxa250" },
+    { ARM_CPUID_PXA255, "pxa255" },
+    { ARM_CPUID_PXA260, "pxa260" },
+    { ARM_CPUID_PXA261, "pxa261" },
+    { ARM_CPUID_PXA262, "pxa262" },
+    { ARM_CPUID_PXA270, "pxa270" },
+    { ARM_CPUID_PXA270_A0, "pxa270-a0" },
+    { ARM_CPUID_PXA270_A1, "pxa270-a1" },
+    { ARM_CPUID_PXA270_B0, "pxa270-b0" },
+    { ARM_CPUID_PXA270_B1, "pxa270-b1" },
+    { ARM_CPUID_PXA270_C0, "pxa270-c0" },
+    { ARM_CPUID_PXA270_C5, "pxa270-c5" },
+    { 0, NULL}
+};
+
+void arm_cpu_list(void)
 {
-    env->features |= 1u << feature;
+    int i;
+
+    printf ("Available CPUs:\n");
+    for (i = 0; arm_cpu_names[i].name; i++) {
+        printf("  %s\n", arm_cpu_names[i].name);
+    }
 }
 
-void cpu_arm_set_model(CPUARMState *env, uint32_t id)
+void cpu_arm_set_model(CPUARMState *env, const char *name)
 {
-    env->cp15.c0_cpuid = id;
-    switch (id) {
-    case ARM_CPUID_ARM926:
-        set_feature(env, ARM_FEATURE_VFP);
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
-        break;
-    case ARM_CPUID_ARM1026:
-        set_feature(env, ARM_FEATURE_VFP);
-        set_feature(env, ARM_FEATURE_AUXCR);
-        env->vfp.xregs[ARM_VFP_FPSID] = 0x410110a0;
-        break;
-    default:
-        cpu_abort(env, "Bad CPU ID: %x\n", id);
-        break;
+    int i;
+    uint32_t id;
+
+    id = 0;
+    i = 0;
+    for (i = 0; arm_cpu_names[i].name; i++) {
+        if (strcmp(name, arm_cpu_names[i].name) == 0) {
+            id = arm_cpu_names[i].id;
+            break;
+        }
     }
+    if (!id) {
+        cpu_abort(env, "Unknown CPU '%s'", name);
+        return;
+    }
+    cpu_reset_model_id(env, id);
 }
 
 void cpu_arm_close(CPUARMState *env)
@@ -60,7 +161,7 @@
     free(env);
 }
 
-#if defined(CONFIG_USER_ONLY) 
+#if defined(CONFIG_USER_ONLY)
 
 void do_interrupt (CPUState *env)
 {
@@ -80,12 +181,26 @@
     return 1;
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
 
 /* These should probably raise undefined insn exceptions.  */
+void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return;
+}
+
+uint32_t helper_get_cp(CPUState *env, uint32_t insn)
+{
+    int op1 = (insn >> 8) & 0xf;
+    cpu_abort(env, "cp%i insn %08x\n", op1, insn);
+    return 0;
+}
+
 void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
 {
     cpu_abort(env, "cp15 insn %08x\n", insn);
@@ -297,13 +412,67 @@
         address += env->cp15.c13_fcse;
 
     if ((env->cp15.c1_sys & 1) == 0) {
-        /* MMU diusabled.  */
+        /* MMU/MPU disabled.  */
         *phys_ptr = address;
         *prot = PAGE_READ | PAGE_WRITE;
+    } else if (arm_feature(env, ARM_FEATURE_MPU)) {
+        int n;
+        uint32_t mask;
+        uint32_t base;
+
+        *phys_ptr = address;
+        for (n = 7; n >= 0; n--) {
+            base = env->cp15.c6_region[n];
+            if ((base & 1) == 0)
+                continue;
+            mask = 1 << ((base >> 1) & 0x1f);
+            /* Keep this shift separate from the above to avoid an
+               (undefined) << 32.  */
+            mask = (mask << 1) - 1;
+            if (((base ^ address) & ~mask) == 0)
+                break;
+        }
+        if (n < 0)
+            return 2;
+
+        if (access_type == 2) {
+            mask = env->cp15.c5_insn;
+        } else {
+            mask = env->cp15.c5_data;
+        }
+        mask = (mask >> (n * 4)) & 0xf;
+        switch (mask) {
+        case 0:
+            return 1;
+        case 1:
+            if (is_user)
+              return 1;
+            *prot = PAGE_READ | PAGE_WRITE;
+            break;
+        case 2:
+            *prot = PAGE_READ;
+            if (!is_user)
+                *prot |= PAGE_WRITE;
+            break;
+        case 3:
+            *prot = PAGE_READ | PAGE_WRITE;
+            break;
+        case 5:
+            if (is_user)
+                return 1;
+            *prot = PAGE_READ;
+            break;
+        case 6:
+            *prot = PAGE_READ;
+            break;
+        default:
+            /* Bad permission.  */
+            return 1;
+        }
     } else {
         /* Pagetable walk.  */
         /* Lookup l1 descriptor.  */
-        table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc);
+        table = (env->cp15.c2_base & 0xffffc000) | ((address >> 18) & 0x3ffc);
         desc = ldl_phys(table);
         type = (desc & 3);
         domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
@@ -326,7 +495,13 @@
             code = 13;
         } else {
             /* Lookup l2 entry.  */
-            table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
+            if (type == 1) {
+                /* Coarse pagetable.  */
+                table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
+            } else {
+                /* Fine pagetable.  */
+                table = (desc & 0xfffff000) | ((address >> 8) & 0xffc);
+            }
             desc = ldl_phys(table);
             switch (desc & 3) {
             case 0: /* Page translation fault.  */
@@ -342,11 +517,15 @@
                 break;
             case 3: /* 1k page.  */
                 if (type == 1) {
-                    /* Page translation fault.  */
-                    code = 7;
-                    goto do_fault;
-                }
-                phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
+                    if (arm_feature(env, ARM_FEATURE_XSCALE))
+                        phys_addr = (desc & 0xfffff000) | (address & 0xfff);
+                    else {
+                        /* Page translation fault.  */
+                        code = 7;
+                        goto do_fault;
+                    }
+                } else
+                    phys_addr = (desc & 0xfffffc00) | (address & 0x3ff);
                 ap = (desc >> 4) & 3;
                 break;
             default:
@@ -395,7 +574,7 @@
     return 1;
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     uint32_t phys_addr;
     int prot;
@@ -409,63 +588,175 @@
     return phys_addr;
 }
 
+void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
+{
+    int cp_num = (insn >> 8) & 0xf;
+    int cp_info = (insn >> 5) & 7;
+    int src = (insn >> 16) & 0xf;
+    int operand = insn & 0xf;
+
+    if (env->cp[cp_num].cp_write)
+        env->cp[cp_num].cp_write(env->cp[cp_num].opaque,
+                                 cp_info, src, operand, val);
+}
+
+uint32_t helper_get_cp(CPUState *env, uint32_t insn)
+{
+    int cp_num = (insn >> 8) & 0xf;
+    int cp_info = (insn >> 5) & 7;
+    int dest = (insn >> 16) & 0xf;
+    int operand = insn & 0xf;
+
+    if (env->cp[cp_num].cp_read)
+        return env->cp[cp_num].cp_read(env->cp[cp_num].opaque,
+                                       cp_info, dest, operand);
+    return 0;
+}
+
+/* Return basic MPU access permission bits.  */
+static uint32_t simple_mpu_ap_bits(uint32_t val)
+{
+    uint32_t ret;
+    uint32_t mask;
+    int i;
+    ret = 0;
+    mask = 3;
+    for (i = 0; i < 16; i += 2) {
+        ret |= (val >> i) & mask;
+        mask <<= 2;
+    }
+    return ret;
+}
+
+/* Pad basic MPU access permission bits to extended format.  */
+static uint32_t extended_mpu_ap_bits(uint32_t val)
+{
+    uint32_t ret;
+    uint32_t mask;
+    int i;
+    ret = 0;
+    mask = 3;
+    for (i = 0; i < 16; i += 2) {
+        ret |= (val & mask) << i;
+        mask <<= 2;
+    }
+    return ret;
+}
+
 void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
 {
     uint32_t op2;
+    uint32_t crm;
 
     op2 = (insn >> 5) & 7;
+    crm = insn & 0xf;
     switch ((insn >> 16) & 0xf) {
     case 0: /* ID codes.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE))
+            break;
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            break;
         goto bad_reg;
     case 1: /* System configuration.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            op2 = 0;
         switch (op2) {
         case 0:
-            env->cp15.c1_sys = val;
+            if (!arm_feature(env, ARM_FEATURE_XSCALE) || crm == 0)
+                env->cp15.c1_sys = val;
             /* ??? Lots of these bits are not implemented.  */
             /* This may enable/disable the MMU, so do a TLB flush.  */
             tlb_flush(env, 1);
             break;
+        case 1:
+            if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+                env->cp15.c1_xscaleauxcr = val;
+                break;
+            }
+            goto bad_reg;
         case 2:
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                goto bad_reg;
             env->cp15.c1_coproc = val;
             /* ??? Is this safe when called from within a TB?  */
             tb_flush(env);
+            break;
         default:
             goto bad_reg;
         }
         break;
-    case 2: /* MMU Page table control.  */
-        env->cp15.c2 = val;
+    case 2: /* MMU Page table control / MPU cache control.  */
+        if (arm_feature(env, ARM_FEATURE_MPU)) {
+            switch (op2) {
+            case 0:
+                env->cp15.c2_data = val;
+                break;
+            case 1:
+                env->cp15.c2_insn = val;
+                break;
+            default:
+                goto bad_reg;
+            }
+        } else {
+            env->cp15.c2_base = val;
+        }
         break;
-    case 3: /* MMU Domain access control.  */
+    case 3: /* MMU Domain access control / MPU write buffer control.  */
         env->cp15.c3 = val;
         break;
     case 4: /* Reserved.  */
         goto bad_reg;
-    case 5: /* MMU Fault status.  */
+    case 5: /* MMU Fault status / MPU access permission.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            op2 = 0;
         switch (op2) {
         case 0:
+            if (arm_feature(env, ARM_FEATURE_MPU))
+                val = extended_mpu_ap_bits(val);
             env->cp15.c5_data = val;
             break;
         case 1:
+            if (arm_feature(env, ARM_FEATURE_MPU))
+                val = extended_mpu_ap_bits(val);
+            env->cp15.c5_insn = val;
+            break;
+        case 2:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
+            env->cp15.c5_data = val;
+            break;
+        case 3:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
             env->cp15.c5_insn = val;
             break;
         default:
             goto bad_reg;
         }
         break;
-    case 6: /* MMU Fault address.  */
-        switch (op2) {
-        case 0:
-            env->cp15.c6_data = val;
-            break;
-        case 1:
-            env->cp15.c6_insn = val;
-            break;
-        default:
-            goto bad_reg;
+    case 6: /* MMU Fault address / MPU base/size.  */
+        if (arm_feature(env, ARM_FEATURE_MPU)) {
+            if (crm >= 8)
+                goto bad_reg;
+            env->cp15.c6_region[crm] = val;
+        } else {
+            if (arm_feature(env, ARM_FEATURE_OMAPCP))
+                op2 = 0;
+            switch (op2) {
+            case 0:
+                env->cp15.c6_data = val;
+                break;
+            case 1:
+                env->cp15.c6_insn = val;
+                break;
+            default:
+                goto bad_reg;
+            }
         }
         break;
     case 7: /* Cache control.  */
+        env->cp15.c15_i_max = 0x000;
+        env->cp15.c15_i_min = 0xff0;
         /* No cache, so nothing to do.  */
         break;
     case 8: /* MMU TLB control.  */
@@ -491,14 +782,25 @@
             goto bad_reg;
         }
         break;
-    case 9: /* Cache lockdown.  */
-        switch (op2) {
-        case 0:
-            env->cp15.c9_data = val;
+    case 9:
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
             break;
-        case 1:
-            env->cp15.c9_insn = val;
+        switch (crm) {
+        case 0: /* Cache lockdown.  */
+            switch (op2) {
+            case 0:
+                env->cp15.c9_data = val;
+                break;
+            case 1:
+                env->cp15.c9_insn = val;
+                break;
+            default:
+                goto bad_reg;
+            }
             break;
+        case 1: /* TCM memory region registers.  */
+            /* Not implemented.  */
+            goto bad_reg;
         default:
             goto bad_reg;
         }
@@ -506,12 +808,13 @@
     case 10: /* MMU TLB lockdown.  */
         /* ??? TLB lockdown not implemented.  */
         break;
-    case 11: /* TCM DMA control.  */
     case 12: /* Reserved.  */
         goto bad_reg;
     case 13: /* Process ID.  */
         switch (op2) {
         case 0:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
             /* Unlike real hardware the qemu TLB uses virtual addresses,
                not modified virtual addresses, so this causes a TLB flush.
              */
@@ -521,7 +824,8 @@
             break;
         case 1:
             /* This changes the ASID, so do a TLB flush.  */
-            if (env->cp15.c13_context != val)
+            if (env->cp15.c13_context != val
+                && !arm_feature(env, ARM_FEATURE_MPU))
               tlb_flush(env, 0);
             env->cp15.c13_context = val;
             break;
@@ -532,78 +836,162 @@
     case 14: /* Reserved.  */
         goto bad_reg;
     case 15: /* Implementation specific.  */
-        /* ??? Internal registers not implemented.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+            if (op2 == 0 && crm == 1) {
+                if (env->cp15.c15_cpar != (val & 0x3fff)) {
+                    /* Changes cp0 to cp13 behavior, so needs a TB flush.  */
+                    tb_flush(env);
+                    env->cp15.c15_cpar = val & 0x3fff;
+                }
+                break;
+            }
+            goto bad_reg;
+        }
+        if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
+            switch (crm) {
+            case 0:
+                break;
+            case 1: /* Set TI925T configuration.  */
+                env->cp15.c15_ticonfig = val & 0xe7;
+                env->cp15.c0_cpuid = (val & (1 << 5)) ? /* OS_TYPE bit */
+                        ARM_CPUID_TI915T : ARM_CPUID_TI925T;
+                break;
+            case 2: /* Set I_max.  */
+                env->cp15.c15_i_max = val;
+                break;
+            case 3: /* Set I_min.  */
+                env->cp15.c15_i_min = val;
+                break;
+            case 4: /* Set thread-ID.  */
+                env->cp15.c15_threadid = val & 0xffff;
+                break;
+            case 8: /* Wait-for-interrupt (deprecated).  */
+                cpu_interrupt(env, CPU_INTERRUPT_HALT);
+                break;
+            default:
+                goto bad_reg;
+            }
+        }
         break;
     }
     return;
 bad_reg:
     /* ??? For debugging only.  Should raise illegal instruction exception.  */
-    cpu_abort(env, "Unimplemented cp15 register read\n");
+    cpu_abort(env, "Unimplemented cp15 register write\n");
 }
 
 uint32_t helper_get_cp15(CPUState *env, uint32_t insn)
 {
     uint32_t op2;
+    uint32_t crm;
 
     op2 = (insn >> 5) & 7;
+    crm = insn & 0xf;
     switch ((insn >> 16) & 0xf) {
     case 0: /* ID codes.  */
         switch (op2) {
         default: /* Device ID.  */
             return env->cp15.c0_cpuid;
         case 1: /* Cache Type.  */
-            return 0x1dd20d2;
+            return env->cp15.c0_cachetype;
         case 2: /* TCM status.  */
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                goto bad_reg;
             return 0;
         }
     case 1: /* System configuration.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            op2 = 0;
         switch (op2) {
         case 0: /* Control register.  */
             return env->cp15.c1_sys;
         case 1: /* Auxiliary control register.  */
             if (arm_feature(env, ARM_FEATURE_AUXCR))
                 return 1;
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                return env->cp15.c1_xscaleauxcr;
             goto bad_reg;
         case 2: /* Coprocessor access register.  */
+            if (arm_feature(env, ARM_FEATURE_XSCALE))
+                goto bad_reg;
             return env->cp15.c1_coproc;
         default:
             goto bad_reg;
         }
-    case 2: /* MMU Page table control.  */
-        return env->cp15.c2;
-    case 3: /* MMU Domain access control.  */
+    case 2: /* MMU Page table control / MPU cache control.  */
+        if (arm_feature(env, ARM_FEATURE_MPU)) {
+            switch (op2) {
+            case 0:
+                return env->cp15.c2_data;
+                break;
+            case 1:
+                return env->cp15.c2_insn;
+                break;
+            default:
+                goto bad_reg;
+            }
+        } else {
+            return env->cp15.c2_base;
+        }
+    case 3: /* MMU Domain access control / MPU write buffer control.  */
         return env->cp15.c3;
     case 4: /* Reserved.  */
         goto bad_reg;
-    case 5: /* MMU Fault status.  */
+    case 5: /* MMU Fault status / MPU access permission.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            op2 = 0;
         switch (op2) {
         case 0:
+            if (arm_feature(env, ARM_FEATURE_MPU))
+                return simple_mpu_ap_bits(env->cp15.c5_data);
             return env->cp15.c5_data;
         case 1:
+            if (arm_feature(env, ARM_FEATURE_MPU))
+                return simple_mpu_ap_bits(env->cp15.c5_data);
+            return env->cp15.c5_insn;
+        case 2:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
+            return env->cp15.c5_data;
+        case 3:
+            if (!arm_feature(env, ARM_FEATURE_MPU))
+                goto bad_reg;
             return env->cp15.c5_insn;
         default:
             goto bad_reg;
         }
-    case 6: /* MMU Fault address.  */
-        switch (op2) {
-        case 0:
-            return env->cp15.c6_data;
-        case 1:
-            /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
-               do any harm.  */
-            return env->cp15.c6_insn;
-        default:
-            goto bad_reg;
+    case 6: /* MMU Fault address / MPU base/size.  */
+        if (arm_feature(env, ARM_FEATURE_MPU)) {
+            int n;
+            n = (insn & 0xf);
+            if (n >= 8)
+                goto bad_reg;
+            return env->cp15.c6_region[n];
+        } else {
+            if (arm_feature(env, ARM_FEATURE_OMAPCP))
+                op2 = 0;
+            switch (op2) {
+            case 0:
+                return env->cp15.c6_data;
+            case 1:
+                /* Arm9 doesn't have an IFAR, but implementing it anyway
+                   shouldn't do any harm.  */
+                return env->cp15.c6_insn;
+            default:
+                goto bad_reg;
+            }
         }
     case 7: /* Cache control.  */
         /* ??? This is for test, clean and invaidate operations that set the
-           Z flag.  We can't represent N = Z = 1, so it also clears clears
+           Z flag.  We can't represent N = Z = 1, so it also clears
            the N flag.  Oh well.  */
         env->NZF = 0;
         return 0;
     case 8: /* MMU TLB control.  */
         goto bad_reg;
     case 9: /* Cache lockdown.  */
+        if (arm_feature(env, ARM_FEATURE_OMAPCP))
+            return 0;
         switch (op2) {
         case 0:
             return env->cp15.c9_data;
@@ -630,7 +1018,29 @@
     case 14: /* Reserved.  */
         goto bad_reg;
     case 15: /* Implementation specific.  */
-        /* ??? Internal registers not implemented.  */
+        if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+            if (op2 == 0 && crm == 1)
+                return env->cp15.c15_cpar;
+
+            goto bad_reg;
+        }
+        if (arm_feature(env, ARM_FEATURE_OMAPCP)) {
+            switch (crm) {
+            case 0:
+                return 0;
+            case 1: /* Read TI925T configuration.  */
+                return env->cp15.c15_ticonfig;
+            case 2: /* Read I_max.  */
+                return env->cp15.c15_i_max;
+            case 3: /* Read I_min.  */
+                return env->cp15.c15_i_min;
+            case 4: /* Read thread-ID.  */
+                return env->cp15.c15_threadid;
+            case 8: /* TI925T_status */
+                return 0;
+            }
+            goto bad_reg;
+        }
         return 0;
     }
 bad_reg:
@@ -639,4 +1049,18 @@
     return 0;
 }
 
+void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
+                ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+                void *opaque)
+{
+    if (cpnum < 0 || cpnum > 14) {
+        cpu_abort(env, "Bad coprocessor number: %i\n", cpnum);
+        return;
+    }
+
+    env->cp[cpnum].cp_read = cp_read;
+    env->cp[cpnum].cp_write = cp_write;
+    env->cp[cpnum].opaque = opaque;
+}
+
 #endif
diff --git a/target-arm/nwfpe/double_cpdo.c b/target-arm/nwfpe/double_cpdo.c
index 944083a..dbd496e 100644
--- a/target-arm/nwfpe/double_cpdo.c
+++ b/target-arm/nwfpe/double_cpdo.c
@@ -42,14 +42,14 @@
    unsigned int Fd, Fm, Fn, nRc = 1;
 
    //printk("DoubleCPDO(0x%08x)\n",opcode);
-   
+
    Fm = getFm(opcode);
    if (CONSTANT_FM(opcode))
    {
      rFm = getDoubleConstant(Fm);
    }
    else
-   {  
+   {
      switch (fpa11->fType[Fm])
      {
         case typeSingle:
@@ -85,7 +85,7 @@
         case typeDouble:
           rFn = fpa11->fpreg[Fn].fDouble;
         break;
-        
+
         default: return 0;
       }
    }
@@ -220,7 +220,7 @@
 
       case NRM_CODE:
       break;
-      
+
       default:
       {
         nRc = 0;
@@ -286,11 +286,11 @@
 
 float64 float64_pow(float64 rFn,float64 rFm)
 {
-  return float64_exp(float64_mul(rFm,float64_ln(rFn))); 
+  return float64_exp(float64_mul(rFm,float64_ln(rFn)));
 }
 
 float64 float64_pol(float64 rFn,float64 rFm)
 {
-  return float64_arctan(float64_div(rFn,rFm)); 
+  return float64_arctan(float64_div(rFn,rFm));
 }
 #endif
diff --git a/target-arm/nwfpe/extended_cpdo.c b/target-arm/nwfpe/extended_cpdo.c
index f5ef623..05e32b0 100644
--- a/target-arm/nwfpe/extended_cpdo.c
+++ b/target-arm/nwfpe/extended_cpdo.c
@@ -42,14 +42,14 @@
    unsigned int Fd, Fm, Fn, nRc = 1;
 
    //printk("ExtendedCPDO(0x%08x)\n",opcode);
-   
+
    Fm = getFm(opcode);
    if (CONSTANT_FM(opcode))
    {
      rFm = getExtendedConstant(Fm);
    }
    else
-   {  
+   {
      switch (fpa11->fType[Fm])
      {
         case typeSingle:
@@ -59,15 +59,15 @@
         case typeDouble:
           rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
         break;
-        
+
         case typeExtended:
           rFm = fpa11->fpreg[Fm].fExtended;
         break;
-        
+
         default: return 0;
      }
    }
-   
+
    if (!MONADIC_INSTRUCTION(opcode))
    {
       Fn = getFn(opcode);
@@ -80,11 +80,11 @@
         case typeDouble:
           rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
         break;
-        
+
         case typeExtended:
           rFn = fpa11->fpreg[Fn].fExtended;
         break;
-        
+
         default: return 0;
       }
    }
@@ -204,13 +204,13 @@
 
       case NRM_CODE:
       break;
-      
+
       default:
       {
         nRc = 0;
       }
    }
-   
+
    if (0 != nRc) fpa11->fType[Fd] = typeExtended;
    return nRc;
 }
@@ -263,11 +263,11 @@
 
 floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm)
 {
-  return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); 
+  return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn)));
 }
 
 floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm)
 {
-  return floatx80_arctan(floatx80_div(rFn,rFm)); 
+  return floatx80_arctan(floatx80_div(rFn,rFm));
 }
 #endif
diff --git a/target-arm/nwfpe/fpa11.c b/target-arm/nwfpe/fpa11.c
index a8141e7..6b43500 100644
--- a/target-arm/nwfpe/fpa11.c
+++ b/target-arm/nwfpe/fpa11.c
@@ -43,16 +43,16 @@
 {
   int i;
   FPA11 *fpa11 = GET_FPA11();
-  
+
   /* initialize the register type array */
   for (i=0;i<=7;i++)
   {
     fpa11->fType[i] = typeNone;
   }
-  
+
   /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
   fpa11->fpsr = FP_EMULATOR | BIT_AC;
-  
+
   /* FPCR: set SB, AB and DA bits, clear all others */
 #if MAINTAIN_FPCR
   fpa11->fpcr = MASK_RESET;
@@ -66,36 +66,36 @@
 
 #if MAINTAIN_FPCR
    fpa11->fpcr &= ~MASK_ROUNDING_MODE;
-#endif   
+#endif
    switch (opcode & MASK_ROUNDING_MODE)
    {
       default:
       case ROUND_TO_NEAREST:
          rounding_mode = float_round_nearest_even;
-#if MAINTAIN_FPCR         
+#if MAINTAIN_FPCR
          fpa11->fpcr |= ROUND_TO_NEAREST;
-#endif         
+#endif
       break;
-      
+
       case ROUND_TO_PLUS_INFINITY:
          rounding_mode = float_round_up;
-#if MAINTAIN_FPCR         
+#if MAINTAIN_FPCR
          fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
-#endif         
+#endif
       break;
-      
+
       case ROUND_TO_MINUS_INFINITY:
          rounding_mode = float_round_down;
-#if MAINTAIN_FPCR         
+#if MAINTAIN_FPCR
          fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
-#endif         
+#endif
       break;
-      
+
       case ROUND_TO_ZERO:
          rounding_mode = float_round_to_zero;
-#if MAINTAIN_FPCR         
+#if MAINTAIN_FPCR
          fpa11->fpcr |= ROUND_TO_ZERO;
-#endif         
+#endif
       break;
   }
    set_float_rounding_mode(rounding_mode, &fpa11->fp_status);
@@ -107,30 +107,30 @@
    FPA11 *fpa11 = GET_FPA11();
 #if MAINTAIN_FPCR
    fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
-#endif   
+#endif
    switch (opcode & MASK_ROUNDING_PRECISION)
    {
       case ROUND_SINGLE:
          rounding_precision = 32;
-#if MAINTAIN_FPCR         
+#if MAINTAIN_FPCR
          fpa11->fpcr |= ROUND_SINGLE;
-#endif         
+#endif
       break;
-      
+
       case ROUND_DOUBLE:
          rounding_precision = 64;
-#if MAINTAIN_FPCR         
+#if MAINTAIN_FPCR
          fpa11->fpcr |= ROUND_DOUBLE;
-#endif         
+#endif
       break;
-      
+
       case ROUND_EXTENDED:
          rounding_precision = 80;
-#if MAINTAIN_FPCR         
+#if MAINTAIN_FPCR
          fpa11->fpcr |= ROUND_EXTENDED;
-#endif         
+#endif
       break;
-      
+
       default: rounding_precision = 80;
   }
    set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status);
@@ -142,12 +142,12 @@
 {
   unsigned int nRc = 0;
 //  unsigned long flags;
-  FPA11 *fpa11; 
+  FPA11 *fpa11;
 //  save_flags(flags); sti();
 
   qemufpa=qfpa;
   user_registers=qregs;
-  
+
 #if 0
   fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n",
           opcode, qregs[REG_PC]);
@@ -222,14 +222,14 @@
           }
       }
      break;
-     
-     case 0xe: 
+
+     case 0xe:
        if (opcode & 0x10)
          return EmulateCPDO(opcode);
        else
          return EmulateCPRT(opcode);
      break;
-  
+
      default: return 0;
   }
 }
diff --git a/target-arm/nwfpe/fpa11.h b/target-arm/nwfpe/fpa11.h
index 8751696..4fc0b3b 100644
--- a/target-arm/nwfpe/fpa11.h
+++ b/target-arm/nwfpe/fpa11.h
@@ -1,7 +1,7 @@
 /*
     NetWinder Floating Point Emulator
     (c) Rebel.com, 1998-1999
-    
+
     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
 
     This program is free software; you can redistribute it and/or modify
diff --git a/target-arm/nwfpe/fpa11_cpdo.c b/target-arm/nwfpe/fpa11_cpdo.c
index cc8aa87..7779637 100644
--- a/target-arm/nwfpe/fpa11_cpdo.c
+++ b/target-arm/nwfpe/fpa11_cpdo.c
@@ -30,26 +30,26 @@
 {
    FPA11 *fpa11 = GET_FPA11();
    unsigned int Fd, nType, nDest, nRc = 1;
-   
+
    //printk("EmulateCPDO(0x%08x)\n",opcode);
 
    /* Get the destination size.  If not valid let Linux perform
       an invalid instruction trap. */
    nDest = getDestinationSize(opcode);
    if (typeNone == nDest) return 0;
-   
+
    SetRoundingMode(opcode);
-     
+
    /* Compare the size of the operands in Fn and Fm.
       Choose the largest size and perform operations in that size,
-      in order to make use of all the precision of the operands. 
-      If Fm is a constant, we just grab a constant of a size 
+      in order to make use of all the precision of the operands.
+      If Fm is a constant, we just grab a constant of a size
       matching the size of the operand in Fn. */
    if (MONADIC_INSTRUCTION(opcode))
      nType = nDest;
    else
      nType = fpa11->fType[getFn(opcode)];
-   
+
    if (!CONSTANT_FM(opcode))
    {
      register unsigned int Fm = getFm(opcode);
@@ -79,39 +79,39 @@
        case typeSingle:
        {
          if (typeDouble == nType)
-           fpa11->fpreg[Fd].fSingle = 
+           fpa11->fpreg[Fd].fSingle =
               float64_to_float32(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
          else
-           fpa11->fpreg[Fd].fSingle = 
+           fpa11->fpreg[Fd].fSingle =
               floatx80_to_float32(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
        }
        break;
-          
+
        case typeDouble:
        {
          if (typeSingle == nType)
-           fpa11->fpreg[Fd].fDouble = 
+           fpa11->fpreg[Fd].fDouble =
               float32_to_float64(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
          else
-           fpa11->fpreg[Fd].fDouble = 
+           fpa11->fpreg[Fd].fDouble =
               floatx80_to_float64(fpa11->fpreg[Fd].fExtended, &fpa11->fp_status);
        }
        break;
-          
+
        case typeExtended:
        {
          if (typeSingle == nType)
-           fpa11->fpreg[Fd].fExtended = 
+           fpa11->fpreg[Fd].fExtended =
               float32_to_floatx80(fpa11->fpreg[Fd].fSingle, &fpa11->fp_status);
          else
-           fpa11->fpreg[Fd].fExtended = 
+           fpa11->fpreg[Fd].fExtended =
               float64_to_floatx80(fpa11->fpreg[Fd].fDouble, &fpa11->fp_status);
        }
        break;
      }
-     
+
      fpa11->fType[Fd] = nDest;
    }
-   
+
    return nRc;
 }
diff --git a/target-arm/nwfpe/fpa11_cpdt.c b/target-arm/nwfpe/fpa11_cpdt.c
index 914a86f..cae2922 100644
--- a/target-arm/nwfpe/fpa11_cpdt.c
+++ b/target-arm/nwfpe/fpa11_cpdt.c
@@ -52,7 +52,7 @@
    p[0] = tget32(addr + 4);
    p[1] = tget32(addr); /* sign & exponent */
 #endif
-}   
+}
 
 static inline
 void loadExtended(const unsigned int Fn,const unsigned int *pMem)
@@ -65,7 +65,7 @@
    p[0] = tget32(addr);  /* sign & exponent */
    p[1] = tget32(addr + 8);  /* ls bits */
    p[2] = tget32(addr + 4);  /* ms bits */
-}   
+}
 
 static inline
 void loadMultiple(const unsigned int Fn,const unsigned int *pMem)
@@ -78,7 +78,7 @@
    p = (unsigned int*)&(fpa11->fpreg[Fn]);
    x = tget32(addr);
    fpa11->fType[Fn] = (x >> 14) & 0x00000003;
-   
+
    switch (fpa11->fType[Fn])
    {
       case typeSingle:
@@ -88,13 +88,13 @@
          p[1] = tget32(addr + 4);  /* double msw */
          p[2] = 0;        /* empty */
       }
-      break; 
-   
+      break;
+
       case typeExtended:
       {
          p[1] = tget32(addr + 8);
          p[2] = tget32(addr + 4);  /* msw */
-         p[0] = (x & 0x80003fff);      
+         p[0] = (x & 0x80003fff);
       }
       break;
    }
@@ -107,22 +107,22 @@
    FPA11 *fpa11 = GET_FPA11();
    float32 val;
    register unsigned int *p = (unsigned int*)&val;
-   
+
    switch (fpa11->fType[Fn])
    {
-      case typeDouble: 
+      case typeDouble:
          val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
       break;
 
-      case typeExtended: 
+      case typeExtended:
          val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status);
       break;
 
       default: val = fpa11->fpreg[Fn].fSingle;
    }
-  
+
    tput32(addr, p[0]);
-}   
+}
 
 static inline
 void storeDouble(const unsigned int Fn,unsigned int *pMem)
@@ -134,7 +134,7 @@
 
    switch (fpa11->fType[Fn])
    {
-      case typeSingle: 
+      case typeSingle:
          val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
       break;
 
@@ -151,7 +151,7 @@
    tput32(addr, p[1]);	/* msw */
    tput32(addr + 4, p[0]);	/* lsw */
 #endif
-}   
+}
 
 static inline
 void storeExtended(const unsigned int Fn,unsigned int *pMem)
@@ -160,24 +160,24 @@
    FPA11 *fpa11 = GET_FPA11();
    floatx80 val;
    register unsigned int *p = (unsigned int*)&val;
-   
+
    switch (fpa11->fType[Fn])
    {
-      case typeSingle: 
+      case typeSingle:
          val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
       break;
 
-      case typeDouble: 
+      case typeDouble:
          val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
       break;
 
       default: val = fpa11->fpreg[Fn].fExtended;
    }
-   
+
    tput32(addr, p[0]); /* sign & exp */
    tput32(addr + 8, p[1]);
    tput32(addr + 4, p[2]); /* msw */
-}   
+}
 
 static inline
 void storeMultiple(const unsigned int Fn,unsigned int *pMem)
@@ -185,10 +185,10 @@
    target_ulong addr = (target_ulong)(long)pMem;
    FPA11 *fpa11 = GET_FPA11();
    register unsigned int nType, *p;
-   
+
    p = (unsigned int*)&(fpa11->fpreg[Fn]);
    nType = fpa11->fType[Fn];
-   
+
    switch (nType)
    {
       case typeSingle:
@@ -198,8 +198,8 @@
 	 tput32(addr + 4, p[1]); /* double msw */
 	 tput32(addr, nType << 14);
       }
-      break; 
-   
+      break;
+
       case typeExtended:
       {
 	 tput32(addr + 4, p[2]); /* msw */
@@ -239,7 +239,7 @@
       case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break;
       default: nRc = 0;
    }
-   
+
    if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
    return nRc;
 }
@@ -248,10 +248,10 @@
 {
    unsigned int *pBase, *pAddress, *pFinal, nRc = 1,
      write_back = WRITE_BACK(opcode);
-   
+
    //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
    SetRoundingMode(ROUND_TO_NEAREST);
-   
+
    pBase = (unsigned int*)readRegister(getRn(opcode));
    if (REG_PC == getRn(opcode))
    {
@@ -274,7 +274,7 @@
       case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break;
       default: nRc = 0;
    }
-   
+
    if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal);
    return nRc;
 }
@@ -315,14 +315,14 @@
 {
    unsigned int i, Fd, *pBase, *pAddress, *pFinal,
      write_back = WRITE_BACK(opcode);
-   
+
    pBase = (unsigned int*)readRegister(getRn(opcode));
    if (REG_PC == getRn(opcode))
    {
      pBase += 2;
      write_back = 0;
    }
-   
+
    pFinal = pBase;
    if (BIT_UP_SET(opcode))
      pFinal += getOffset(opcode);
@@ -349,7 +349,7 @@
   unsigned int nRc = 0;
 
   //printk("EmulateCPDT(0x%08x)\n",opcode);
-  
+
   if (LDF_OP(opcode))
   {
     nRc = PerformLDF(opcode);
@@ -361,7 +361,7 @@
   else if (STF_OP(opcode))
   {
     nRc = PerformSTF(opcode);
-  } 
+  }
   else if (SFM_OP(opcode))
   {
     nRc = PerformSFM(opcode);
@@ -370,7 +370,7 @@
   {
     nRc = 0;
   }
-  
+
   return nRc;
 }
 #endif
diff --git a/target-arm/nwfpe/fpa11_cprt.c b/target-arm/nwfpe/fpa11_cprt.c
index 3be9b42..04eae8c 100644
--- a/target-arm/nwfpe/fpa11_cprt.c
+++ b/target-arm/nwfpe/fpa11_cprt.c
@@ -55,7 +55,7 @@
   {
     case  FLT_CODE >> 20: nRc = PerformFLT(opcode); break;
     case  FIX_CODE >> 20: nRc = PerformFIX(opcode); break;
-    
+
     case  WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break;
     case  RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break;
 
@@ -67,14 +67,14 @@
 
     default: nRc = 0;
   }
-  
+
   return nRc;
 }
 
 unsigned int PerformFLT(const unsigned int opcode)
 {
    FPA11 *fpa11 = GET_FPA11();
-   
+
    unsigned int nRc = 1;
    SetRoundingMode(opcode);
 
@@ -95,7 +95,7 @@
             int32_to_float64(readRegister(getRd(opcode)), &fpa11->fp_status);
       }
       break;
-        
+
       case ROUND_EXTENDED:
       {
         fpa11->fType[getFn(opcode)] = typeExtended;
@@ -103,10 +103,10 @@
 	   int32_to_floatx80(readRegister(getRd(opcode)), &fpa11->fp_status);
       }
       break;
-      
+
       default: nRc = 0;
   }
-  
+
   return nRc;
 }
 
@@ -115,7 +115,7 @@
    FPA11 *fpa11 = GET_FPA11();
    unsigned int nRc = 1;
    unsigned int Fn = getFm(opcode);
-   
+
    SetRoundingMode(opcode);
 
    switch (fpa11->fType[Fn])
@@ -134,21 +134,21 @@
 	               float64_to_int32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status));
       }
       break;
-      	               
+
       case typeExtended:
       {
          writeRegister(getRd(opcode),
 	               floatx80_to_int32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status));
       }
       break;
-      
+
       default: nRc = 0;
   }
-  
+
   return nRc;
 }
 
-   
+
 static unsigned int __inline__
 PerformComparisonOperation(floatx80 Fn, floatx80 Fm)
 {
@@ -160,7 +160,7 @@
    {
       flags |= CC_NEGATIVE;
    }
-  
+
    /* test for equal condition */
    if (floatx80_eq(Fn,Fm, &fpa11->fp_status))
    {
@@ -172,13 +172,13 @@
    {
       flags |= CC_CARRY;
    }
-   
+
    writeConditionCodes(flags);
    return 1;
 }
 
 /* This instruction sets the flags N, Z, C, V in the FPSR. */
-   
+
 static unsigned int PerformComparison(const unsigned int opcode)
 {
    FPA11 *fpa11 = GET_FPA11();
@@ -200,27 +200,27 @@
       comparison (cheaper than an 80-bit one).  */
    switch (fpa11->fType[Fn])
    {
-      case typeSingle: 
+      case typeSingle:
         //printk("single.\n");
 	if (float32_is_nan(fpa11->fpreg[Fn].fSingle))
 	   goto unordered;
         rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status);
       break;
 
-      case typeDouble: 
+      case typeDouble:
         //printk("double.\n");
 	if (float64_is_nan(fpa11->fpreg[Fn].fDouble))
 	   goto unordered;
         rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status);
       break;
-      
-      case typeExtended: 
+
+      case typeExtended:
         //printk("extended.\n");
 	if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended))
 	   goto unordered;
         rFn = fpa11->fpreg[Fn].fExtended;
       break;
-      
+
       default: return 0;
    }
 
@@ -236,27 +236,27 @@
      //printk("Fm = r%d which contains a ",Fm);
       switch (fpa11->fType[Fm])
       {
-         case typeSingle: 
+         case typeSingle:
            //printk("single.\n");
 	   if (float32_is_nan(fpa11->fpreg[Fm].fSingle))
 	      goto unordered;
            rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle, &fpa11->fp_status);
          break;
 
-         case typeDouble: 
+         case typeDouble:
            //printk("double.\n");
 	   if (float64_is_nan(fpa11->fpreg[Fm].fDouble))
 	      goto unordered;
            rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble, &fpa11->fp_status);
          break;
-      
-         case typeExtended: 
+
+         case typeExtended:
            //printk("extended.\n");
 	   if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended))
 	      goto unordered;
            rFm = fpa11->fpreg[Fm].fExtended;
          break;
-      
+
          default: return 0;
       }
    }
diff --git a/target-arm/nwfpe/fpopcode.c b/target-arm/nwfpe/fpopcode.c
index d29e913..a733a1d 100644
--- a/target-arm/nwfpe/fpopcode.c
+++ b/target-arm/nwfpe/fpopcode.c
@@ -35,7 +35,7 @@
   { 0xa000000000000000ULL, 0x4001},	/* extended 5.0 */
   { 0x8000000000000000ULL, 0x3ffe},	/* extended 0.5 */
   { 0xa000000000000000ULL, 0x4002}	/* extended 10.0 */
-};  
+};
 
 const float64 float64Constant[] = {
   0x0000000000000000ULL,		/* double 0.0 */
@@ -46,7 +46,7 @@
   0x4014000000000000ULL,		/* double 5.0 */
   0x3fe0000000000000ULL,		/* double 0.5 */
   0x4024000000000000ULL			/* double 10.0 */
-};  
+};
 
 const float32 float32Constant[] = {
   0x00000000,				/* single 0.0 */
@@ -57,12 +57,12 @@
   0x40a00000,				/* single 5.0 */
   0x3f000000,				/* single 0.5 */
   0x41200000				/* single 10.0 */
-};  
+};
 
 unsigned int getTransferLength(const unsigned int opcode)
 {
   unsigned int nRc;
-  
+
   switch (opcode & MASK_TRANSFER_LENGTH)
   {
     case 0x00000000: nRc = 1; break; /* single precision */
@@ -70,14 +70,14 @@
     case 0x00400000: nRc = 3; break; /* extended precision */
     default: nRc = 0;
   }
-  
+
   return(nRc);
 }
 
 unsigned int getRegisterCount(const unsigned int opcode)
 {
   unsigned int nRc;
-  
+
   switch (opcode & MASK_REGISTER_COUNT)
   {
     case 0x00000000: nRc = 4; break;
@@ -86,14 +86,14 @@
     case 0x00408000: nRc = 3; break;
     default: nRc = 0;
   }
-  
+
   return(nRc);
 }
 
 unsigned int getRoundingPrecision(const unsigned int opcode)
 {
   unsigned int nRc;
-  
+
   switch (opcode & MASK_ROUNDING_PRECISION)
   {
     case 0x00000000: nRc = 1; break;
@@ -101,14 +101,14 @@
     case 0x00080000: nRc = 3; break;
     default: nRc = 0;
   }
-  
+
   return(nRc);
 }
 
 unsigned int getDestinationSize(const unsigned int opcode)
 {
   unsigned int nRc;
-  
+
   switch (opcode & MASK_DESTINATION_SIZE)
   {
     case 0x00000000: nRc = typeSingle; break;
@@ -116,7 +116,7 @@
     case 0x00080000: nRc = typeExtended; break;
     default: nRc = typeNone;
   }
-  
+
   return(nRc);
 }
 
diff --git a/target-arm/nwfpe/fpopcode.h b/target-arm/nwfpe/fpopcode.h
index 13c7419..6c51067 100644
--- a/target-arm/nwfpe/fpopcode.h
+++ b/target-arm/nwfpe/fpopcode.h
@@ -24,18 +24,18 @@
 
 /*
 ARM Floating Point Instruction Classes
-| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
 |c o n d|1 1 0 P|U|u|W|L|   Rn  |v|  Fd |0|0|0|1|  o f f s e t  | CPDT
 |c o n d|1 1 0 P|U|w|W|L|   Rn  |x|  Fd |0|0|0|1|  o f f s e t  | CPDT
-| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
 |c o n d|1 1 1 0|a|b|c|d|e|  Fn |j|  Fd |0|0|0|1|f|g|h|0|i|  Fm | CPDO
 |c o n d|1 1 1 0|a|b|c|L|e|  Fn |   Rd  |0|0|0|1|f|g|h|1|i|  Fm | CPRT
 |c o n d|1 1 1 0|a|b|c|1|e|  Fn |1|1|1|1|0|0|0|1|f|g|h|1|i|  Fm | comparisons
-| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 
+| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
 
 CPDT		data transfer instructions
 		LDF, STF, LFM, SFM
-		
+
 CPDO		dyadic arithmetic instructions
 		ADF, MUF, SUF, RSF, DVF, RDF,
 		POW, RPW, RMF, FML, FDV, FRD, POL
@@ -43,7 +43,7 @@
 CPDO		monadic arithmetic instructions
 		MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP,
 		SIN, COS, TAN, ASN, ACS, ATN, URD, NRM
-		
+
 CPRT		joint arithmetic/data transfer instructions
 		FIX (arithmetic followed by load/store)
 		FLT (load/store followed by arithmetic)
@@ -57,7 +57,7 @@
 W		write back bit: 1 = update base register (Rn)
 L		load/store bit: 0 = store, 1 = load
 Rn		base register
-Rd		destination/source register		
+Rd		destination/source register
 Fd		floating point destination register
 Fn		floating point source register
 Fm		floating point source register or floating point constant
@@ -370,19 +370,19 @@
 {
    extern const floatx80 floatx80Constant[];
    return floatx80Constant[nIndex];
-} 
+}
 
 static inline const float64 getDoubleConstant(const unsigned int nIndex)
 {
    extern const float64 float64Constant[];
    return float64Constant[nIndex];
-} 
+}
 
 static inline const float32 getSingleConstant(const unsigned int nIndex)
 {
    extern const float32 float32Constant[];
    return float32Constant[nIndex];
-} 
+}
 
 extern unsigned int getRegisterCount(const unsigned int opcode);
 extern unsigned int getDestinationSize(const unsigned int opcode);
diff --git a/target-arm/nwfpe/fpsr.h b/target-arm/nwfpe/fpsr.h
index 6dafb0f..0c66543 100644
--- a/target-arm/nwfpe/fpsr.h
+++ b/target-arm/nwfpe/fpsr.h
@@ -30,7 +30,7 @@
 	EXCEPTION TRAP ENABLE BYTE
 	SYSTEM CONTROL BYTE
 	CUMULATIVE EXCEPTION FLAGS BYTE
-	
+
 The FPCR is a 32 bit register consisting of bit flags.
 */
 
@@ -43,7 +43,7 @@
 
 #define MASK_SYSID		0xff000000
 #define BIT_HARDWARE		0x80000000
-#define FP_EMULATOR		0x01000000	/* System ID for emulator */ 
+#define FP_EMULATOR		0x01000000	/* System ID for emulator */
 #define FP_ACCELERATOR		0x81000000	/* System ID for FPA11 */
 
 /* EXCEPTION TRAP ENABLE BYTE
diff --git a/target-arm/nwfpe/single_cpdo.c b/target-arm/nwfpe/single_cpdo.c
index 7dd2620..1482f47 100644
--- a/target-arm/nwfpe/single_cpdo.c
+++ b/target-arm/nwfpe/single_cpdo.c
@@ -47,13 +47,13 @@
      rFm = getSingleConstant(Fm);
    }
    else
-   {  
+   {
      switch (fpa11->fType[Fm])
      {
         case typeSingle:
           rFm = fpa11->fpreg[Fm].fSingle;
         break;
-        
+
         default: return 0;
      }
    }
@@ -186,7 +186,7 @@
 
       case NRM_CODE:
       break;
-      
+
       default:
       {
         nRc = 0;
@@ -245,11 +245,11 @@
 
 float32 float32_pow(float32 rFn,float32 rFm)
 {
-  return float32_exp(float32_mul(rFm,float32_ln(rFn))); 
+  return float32_exp(float32_mul(rFm,float32_ln(rFn)));
 }
 
 float32 float32_pol(float32 rFn,float32 rFm)
 {
-  return float32_arctan(float32_div(rFn,rFm)); 
+  return float32_arctan(float32_div(rFn,rFm));
 }
 #endif
diff --git a/target-arm/op.c b/target-arm/op.c
index f17b812..e8a536c 100644
--- a/target-arm/op.c
+++ b/target-arm/op.c
@@ -1,6 +1,6 @@
 /*
  *  ARM micro operations
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *  Copyright (c) 2005 CodeSourcery, LLC
  *
@@ -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;
     }
@@ -774,7 +774,7 @@
   }
   else
     T0 = res;
-  
+
   FORCE_RET();
 }
 
@@ -792,7 +792,7 @@
   }
   else
     T0 = res;
-  
+
   FORCE_RET();
 }
 
@@ -819,7 +819,7 @@
     int shift;
     shift = PARAM1;
     if (shift != 0) {
-	env->CF = (T1 >> (32 - shift)) & 1;
+	env->CF = (T0 >> (32 - shift)) & 1;
 	T0 = T0 << shift;
     }
     env->NZF = T0;
@@ -832,7 +832,7 @@
 
     shift = PARAM1;
     if (shift == 0) {
-	env->CF = ((uint32_t)shift) >> 31;
+	env->CF = ((uint32_t)T0) >> 31;
 	T0 = 0;
     } else {
 	env->CF = (T0 >> (shift - 1)) & 1;
@@ -1127,7 +1127,7 @@
 void OPPROTO op_vfp_mrrd(void)
 {
     CPU_DoubleU u;
-    
+
     u.d = FT0d;
     T0 = u.l.lower;
     T1 = u.l.upper;
@@ -1136,18 +1136,30 @@
 void OPPROTO op_vfp_mdrr(void)
 {
     CPU_DoubleU u;
-    
+
     u.l.lower = T0;
     u.l.upper = T1;
     FT0d = u.d;
 }
 
-/* Copy the most significant bit to T0 to all bits of T1.  */
+/* Copy the most significant bit of T0 to all bits of T1.  */
 void OPPROTO op_signbit_T1_T0(void)
 {
     T1 = (int32_t)T0 >> 31;
 }
 
+void OPPROTO op_movl_cp_T0(void)
+{
+    helper_set_cp(env, PARAM1, T0);
+    FORCE_RET();
+}
+
+void OPPROTO op_movl_T0_cp(void)
+{
+    T0 = helper_get_cp(env, PARAM1);
+    FORCE_RET();
+}
+
 void OPPROTO op_movl_cp15_T0(void)
 {
     helper_set_cp15(env, PARAM1, T0);
@@ -1201,3 +1213,6 @@
 {
     T0 = T2;
 }
+
+/* iwMMXt support */
+#include "op_iwmmxt.c"
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index af5c61d..c861bf7 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -1,6 +1,6 @@
 /*
  *  ARM helper routines
- * 
+ *
  *  Copyright (c) 2005 CodeSourcery, LLC
  *
  * This library is free software; you can redistribute it and/or
diff --git a/target-arm/op_iwmmxt.c b/target-arm/op_iwmmxt.c
new file mode 100644
index 0000000..40ae10d
--- /dev/null
+++ b/target-arm/op_iwmmxt.c
@@ -0,0 +1,707 @@
+/*
+ * iwMMXt micro operations for XScale.
+ *
+ * Copyright (c) 2007 OpenedHand, Ltd.
+ * Written by Andrzej Zaborowski <andrew@openedhand.com>
+ *
+ * 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
+ */
+
+#define M1	env->iwmmxt.regs[PARAM1]
+
+/* iwMMXt macros extracted from GNU gdb.  */
+
+/* Set the SIMD wCASF flags for 8, 16, 32 or 64-bit operations.  */
+#define SIMD8_SET( v, n, b)	((v != 0) << ((((b) + 1) * 4) + (n)))
+#define SIMD16_SET(v, n, h)	((v != 0) << ((((h) + 1) * 8) + (n)))
+#define SIMD32_SET(v, n, w)	((v != 0) << ((((w) + 1) * 16) + (n)))
+#define SIMD64_SET(v, n)	((v != 0) << (32 + (n)))
+/* Flags to pass as "n" above.  */
+#define SIMD_NBIT	-1
+#define SIMD_ZBIT	-2
+#define SIMD_CBIT	-3
+#define SIMD_VBIT	-4
+/* Various status bit macros.  */
+#define NBIT8(x)	((x) & 0x80)
+#define NBIT16(x)	((x) & 0x8000)
+#define NBIT32(x)	((x) & 0x80000000)
+#define NBIT64(x)	((x) & 0x8000000000000000ULL)
+#define ZBIT8(x)	(((x) & 0xff) == 0)
+#define ZBIT16(x)	(((x) & 0xffff) == 0)
+#define ZBIT32(x)	(((x) & 0xffffffff) == 0)
+#define ZBIT64(x)	(x == 0)
+/* Sign extension macros.  */
+#define EXTEND8H(a)	((uint16_t) (int8_t) (a))
+#define EXTEND8(a)	((uint32_t) (int8_t) (a))
+#define EXTEND16(a)	((uint32_t) (int16_t) (a))
+#define EXTEND16S(a)	((int32_t) (int16_t) (a))
+#define EXTEND32(a)	((uint64_t) (int32_t) (a))
+
+void OPPROTO op_iwmmxt_movl_T0_T1_wRn(void)
+{
+    T0 = M1 & ~(uint32_t) 0;
+    T1 = M1 >> 32;
+}
+
+void OPPROTO op_iwmmxt_movl_wRn_T0_T1(void)
+{
+    M1 = ((uint64_t) T1 << 32) | T0;
+}
+
+void OPPROTO op_iwmmxt_movq_M0_wRn(void)
+{
+    M0 = M1;
+}
+
+void OPPROTO op_iwmmxt_orq_M0_wRn(void)
+{
+    M0 |= M1;
+}
+
+void OPPROTO op_iwmmxt_andq_M0_wRn(void)
+{
+    M0 &= M1;
+}
+
+void OPPROTO op_iwmmxt_xorq_M0_wRn(void)
+{
+    M0 ^= M1;
+}
+
+void OPPROTO op_iwmmxt_maddsq_M0_wRn(void)
+{
+    M0 = ((
+            EXTEND16S((M0 >> 0) & 0xffff) * EXTEND16S((M1 >> 0) & 0xffff) +
+            EXTEND16S((M0 >> 16) & 0xffff) * EXTEND16S((M1 >> 16) & 0xffff)
+        ) & 0xffffffff) | ((uint64_t) (
+            EXTEND16S((M0 >> 32) & 0xffff) * EXTEND16S((M1 >> 32) & 0xffff) +
+            EXTEND16S((M0 >> 48) & 0xffff) * EXTEND16S((M1 >> 48) & 0xffff)
+        ) << 32);
+}
+
+void OPPROTO op_iwmmxt_madduq_M0_wRn(void)
+{
+    M0 = ((
+            ((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) +
+            ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff)
+        ) & 0xffffffff) | ((
+            ((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) +
+            ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff)
+        ) << 32);
+}
+
+void OPPROTO op_iwmmxt_sadb_M0_wRn(void)
+{
+#define abs(x) (((x) >= 0) ? x : -x)
+#define SADB(SHR) abs((int) ((M0 >> SHR) & 0xff) - (int) ((M1 >> SHR) & 0xff))
+    M0 =
+        SADB(0) + SADB(8) + SADB(16) + SADB(24) +
+        SADB(32) + SADB(40) + SADB(48) + SADB(56);
+#undef SADB
+}
+
+void OPPROTO op_iwmmxt_sadw_M0_wRn(void)
+{
+#define SADW(SHR) \
+    abs((int) ((M0 >> SHR) & 0xffff) - (int) ((M1 >> SHR) & 0xffff))
+    M0 = SADW(0) + SADW(16) + SADW(32) + SADW(48);
+#undef SADW
+}
+
+void OPPROTO op_iwmmxt_addl_M0_wRn(void)
+{
+    M0 += env->iwmmxt.regs[PARAM1] & 0xffffffff;
+}
+
+void OPPROTO op_iwmmxt_mulsw_M0_wRn(void)
+{
+#define MULS(SHR) ((uint64_t) ((( \
+        EXTEND16S((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff) \
+    ) >> PARAM2) & 0xffff) << SHR)
+    M0 = MULS(0) | MULS(16) | MULS(32) | MULS(48);
+#undef MULS
+}
+
+void OPPROTO op_iwmmxt_muluw_M0_wRn(void)
+{
+#define MULU(SHR) ((uint64_t) ((( \
+        ((M0 >> SHR) & 0xffff) * ((M1 >> SHR) & 0xffff) \
+    ) >> PARAM2) & 0xffff) << SHR)
+    M0 = MULU(0) | MULU(16) | MULU(32) | MULU(48);
+#undef MULU
+}
+
+void OPPROTO op_iwmmxt_macsw_M0_wRn(void)
+{
+#define MACS(SHR) ( \
+        EXTEND16((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff))
+    M0 = (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48));
+#undef MACS
+}
+
+void OPPROTO op_iwmmxt_macuw_M0_wRn(void)
+{
+#define MACU(SHR) ( \
+        (uint32_t) ((M0 >> SHR) & 0xffff) * \
+        (uint32_t) ((M1 >> SHR) & 0xffff))
+    M0 = MACU(0) + MACU(16) + MACU(32) + MACU(48);
+#undef MACU
+}
+
+void OPPROTO op_iwmmxt_addsq_M0_wRn(void)
+{
+    M0 = (int64_t) M0 + (int64_t) M1;
+}
+
+void OPPROTO op_iwmmxt_adduq_M0_wRn(void)
+{
+    M0 += M1;
+}
+
+void OPPROTO op_iwmmxt_movq_wRn_M0(void)
+{
+    M1 = M0;
+}
+
+void OPPROTO op_iwmmxt_movl_wCx_T0(void)
+{
+    env->iwmmxt.cregs[PARAM1] = T0;
+}
+
+void OPPROTO op_iwmmxt_movl_T0_wCx(void)
+{
+    T0 = env->iwmmxt.cregs[PARAM1];
+}
+
+void OPPROTO op_iwmmxt_movl_T1_wCx(void)
+{
+    T1 = env->iwmmxt.cregs[PARAM1];
+}
+
+void OPPROTO op_iwmmxt_set_mup(void)
+{
+    env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 2;
+}
+
+void OPPROTO op_iwmmxt_set_cup(void)
+{
+    env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 1;
+}
+
+void OPPROTO op_iwmmxt_setpsr_nz(void)
+{
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        SIMD64_SET((M0 == 0), SIMD_ZBIT) |
+        SIMD64_SET((M0 & (1ULL << 63)), SIMD_NBIT);
+}
+
+void OPPROTO op_iwmmxt_negq_M0(void)
+{
+    M0 = ~M0;
+}
+
+#define NZBIT8(x, i) \
+    SIMD8_SET(NBIT8((x) & 0xff), SIMD_NBIT, i) | \
+    SIMD8_SET(ZBIT8((x) & 0xff), SIMD_ZBIT, i)
+#define NZBIT16(x, i) \
+    SIMD16_SET(NBIT16((x) & 0xffff), SIMD_NBIT, i) | \
+    SIMD16_SET(ZBIT16((x) & 0xffff), SIMD_ZBIT, i)
+#define NZBIT32(x, i) \
+    SIMD32_SET(NBIT32((x) & 0xffffffff), SIMD_NBIT, i) | \
+    SIMD32_SET(ZBIT32((x) & 0xffffffff), SIMD_ZBIT, i)
+#define NZBIT64(x) \
+    SIMD64_SET(NBIT64(x), SIMD_NBIT) | \
+    SIMD64_SET(ZBIT64(x), SIMD_ZBIT)
+#define IWMMXT_OP_UNPACK(S, SH0, SH1, SH2, SH3)			\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, b_M0_wRn))(void)	\
+{								\
+    M0 =							\
+        (((M0 >> SH0) & 0xff) << 0) | (((M1 >> SH0) & 0xff) << 8) |	\
+        (((M0 >> SH1) & 0xff) << 16) | (((M1 >> SH1) & 0xff) << 24) |	\
+        (((M0 >> SH2) & 0xff) << 32) | (((M1 >> SH2) & 0xff) << 40) |	\
+        (((M0 >> SH3) & 0xff) << 48) | (((M1 >> SH3) & 0xff) << 56);	\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) |		\
+        NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) |		\
+        NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) |		\
+        NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7);		\
+}								\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, w_M0_wRn))(void)	\
+{								\
+    M0 =							\
+        (((M0 >> SH0) & 0xffff) << 0) |				\
+        (((M1 >> SH0) & 0xffff) << 16) |			\
+        (((M0 >> SH2) & 0xffff) << 32) |			\
+        (((M1 >> SH2) & 0xffff) << 48);				\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 16, 1) |		\
+        NZBIT8(M0 >> 32, 2) | NZBIT8(M0 >> 48, 3);		\
+}								\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, l_M0_wRn))(void)	\
+{								\
+    M0 =							\
+        (((M0 >> SH0) & 0xffffffff) << 0) |			\
+        (((M1 >> SH0) & 0xffffffff) << 32);			\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);		\
+}								\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, ub_M0))(void)	\
+{								\
+    M0 =							\
+        (((M0 >> SH0) & 0xff) << 0) |				\
+        (((M0 >> SH1) & 0xff) << 16) |				\
+        (((M0 >> SH2) & 0xff) << 32) |				\
+        (((M0 >> SH3) & 0xff) << 48);				\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |		\
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);		\
+}								\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, uw_M0))(void)	\
+{								\
+    M0 =							\
+        (((M0 >> SH0) & 0xffff) << 0) |				\
+        (((M0 >> SH2) & 0xffff) << 32);				\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);		\
+}								\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, ul_M0))(void)	\
+{								\
+    M0 = (((M0 >> SH0) & 0xffffffff) << 0);			\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0);	\
+}								\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, sb_M0))(void)	\
+{								\
+    M0 =							\
+        ((uint64_t) EXTEND8H((M0 >> SH0) & 0xff) << 0) |	\
+        ((uint64_t) EXTEND8H((M0 >> SH1) & 0xff) << 16) |	\
+        ((uint64_t) EXTEND8H((M0 >> SH2) & 0xff) << 32) |	\
+        ((uint64_t) EXTEND8H((M0 >> SH3) & 0xff) << 48);	\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |		\
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);		\
+}								\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, sw_M0))(void)	\
+{								\
+    M0 =							\
+        ((uint64_t) EXTEND16((M0 >> SH0) & 0xffff) << 0) |	\
+        ((uint64_t) EXTEND16((M0 >> SH2) & 0xffff) << 32);	\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);		\
+}								\
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, sl_M0))(void)	\
+{								\
+    M0 = EXTEND32((M0 >> SH0) & 0xffffffff);			\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0);	\
+}
+IWMMXT_OP_UNPACK(l, 0, 8, 16, 24)
+IWMMXT_OP_UNPACK(h, 32, 40, 48, 56)
+
+#define IWMMXT_OP_CMP(SUFF, Tb, Tw, Tl, O)				\
+void OPPROTO glue(op_iwmmxt_, glue(SUFF, b_M0_wRn))(void)	\
+{								\
+    M0 =							\
+        CMP(0, Tb, O, 0xff) | CMP(8, Tb, O, 0xff) |		\
+        CMP(16, Tb, O, 0xff) | CMP(24, Tb, O, 0xff) |		\
+        CMP(32, Tb, O, 0xff) | CMP(40, Tb, O, 0xff) |		\
+        CMP(48, Tb, O, 0xff) | CMP(56, Tb, O, 0xff);		\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) |		\
+        NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) |		\
+        NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) |		\
+        NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7);		\
+}								\
+void OPPROTO glue(op_iwmmxt_, glue(SUFF, w_M0_wRn))(void)	\
+{								\
+    M0 = CMP(0, Tw, O, 0xffff) | CMP(16, Tw, O, 0xffff) |	\
+        CMP(32, Tw, O, 0xffff) | CMP(48, Tw, O, 0xffff);	\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |		\
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);		\
+}								\
+void OPPROTO glue(op_iwmmxt_, glue(SUFF, l_M0_wRn))(void)	\
+{								\
+    M0 = CMP(0, Tl, O, 0xffffffff) |				\
+        CMP(32, Tl, O, 0xffffffff);				\
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =			\
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);		\
+}
+#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((M0 >> SHR) & MASK) OPER \
+            (TYPE) ((M1 >> SHR) & MASK)) ? (uint64_t) MASK : 0) << SHR)
+IWMMXT_OP_CMP(cmpeq, uint8_t, uint16_t, uint32_t, ==)
+IWMMXT_OP_CMP(cmpgts, int8_t, int16_t, int32_t, >)
+IWMMXT_OP_CMP(cmpgtu, uint8_t, uint16_t, uint32_t, >)
+#undef CMP
+#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((M0 >> SHR) & MASK) OPER \
+            (TYPE) ((M1 >> SHR) & MASK)) ? M0 : M1) & ((uint64_t) MASK << SHR))
+IWMMXT_OP_CMP(mins, int8_t, int16_t, int32_t, <)
+IWMMXT_OP_CMP(minu, uint8_t, uint16_t, uint32_t, <)
+IWMMXT_OP_CMP(maxs, int8_t, int16_t, int32_t, >)
+IWMMXT_OP_CMP(maxu, uint8_t, uint16_t, uint32_t, >)
+#undef CMP
+#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((M0 >> SHR) & MASK) \
+            OPER (TYPE) ((M1 >> SHR) & MASK)) & MASK) << SHR)
+IWMMXT_OP_CMP(subn, uint8_t, uint16_t, uint32_t, -)
+IWMMXT_OP_CMP(addn, uint8_t, uint16_t, uint32_t, +)
+#undef CMP
+/* TODO Signed- and Unsigned-Saturation */
+#define CMP(SHR, TYPE, OPER, MASK) ((uint64_t) (((TYPE) ((M0 >> SHR) & MASK) \
+            OPER (TYPE) ((M1 >> SHR) & MASK)) & MASK) << SHR)
+IWMMXT_OP_CMP(subu, uint8_t, uint16_t, uint32_t, -)
+IWMMXT_OP_CMP(addu, uint8_t, uint16_t, uint32_t, +)
+IWMMXT_OP_CMP(subs, int8_t, int16_t, int32_t, -)
+IWMMXT_OP_CMP(adds, int8_t, int16_t, int32_t, +)
+#undef CMP
+#undef IWMMXT_OP_CMP
+
+void OPPROTO op_iwmmxt_avgb_M0_wRn(void)
+{
+#define AVGB(SHR) ((( \
+        ((M0 >> SHR) & 0xff) + ((M1 >> SHR) & 0xff) + PARAM2) >> 1) << SHR)
+    M0 =
+        AVGB(0) | AVGB(8) | AVGB(16) | AVGB(24) |
+        AVGB(32) | AVGB(40) | AVGB(48) | AVGB(56);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        SIMD8_SET(ZBIT8((M0 >> 0) & 0xff), SIMD_ZBIT, 0) |
+        SIMD8_SET(ZBIT8((M0 >> 8) & 0xff), SIMD_ZBIT, 1) |
+        SIMD8_SET(ZBIT8((M0 >> 16) & 0xff), SIMD_ZBIT, 2) |
+        SIMD8_SET(ZBIT8((M0 >> 24) & 0xff), SIMD_ZBIT, 3) |
+        SIMD8_SET(ZBIT8((M0 >> 32) & 0xff), SIMD_ZBIT, 4) |
+        SIMD8_SET(ZBIT8((M0 >> 40) & 0xff), SIMD_ZBIT, 5) |
+        SIMD8_SET(ZBIT8((M0 >> 48) & 0xff), SIMD_ZBIT, 6) |
+        SIMD8_SET(ZBIT8((M0 >> 56) & 0xff), SIMD_ZBIT, 7);
+#undef AVGB
+}
+
+void OPPROTO op_iwmmxt_avgw_M0_wRn(void)
+{
+#define AVGW(SHR) ((( \
+        ((M0 >> SHR) & 0xffff) + ((M1 >> SHR) & 0xffff) + PARAM2) >> 1) << SHR)
+    M0 = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        SIMD16_SET(ZBIT16((M0 >> 0) & 0xffff), SIMD_ZBIT, 0) |
+        SIMD16_SET(ZBIT16((M0 >> 16) & 0xffff), SIMD_ZBIT, 1) |
+        SIMD16_SET(ZBIT16((M0 >> 32) & 0xffff), SIMD_ZBIT, 2) |
+        SIMD16_SET(ZBIT16((M0 >> 48) & 0xffff), SIMD_ZBIT, 3);
+#undef AVGW
+}
+
+void OPPROTO op_iwmmxt_msadb_M0_wRn(void)
+{
+    M0 = ((((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) +
+           ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff)) & 0xffffffff) |
+         ((((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) +
+           ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff)) << 32);
+}
+
+void OPPROTO op_iwmmxt_align_M0_T0_wRn(void)
+{
+    M0 >>= T0 << 3;
+    M0 |= M1 << (64 - (T0 << 3));
+}
+
+void OPPROTO op_iwmmxt_insr_M0_T0_T1(void)
+{
+    M0 &= ~((uint64_t) T1 << PARAM1);
+    M0 |= (uint64_t) (T0 & T1) << PARAM1;
+}
+
+void OPPROTO op_iwmmxt_extrsb_T0_M0(void)
+{
+    T0 = EXTEND8((M0 >> PARAM1) & 0xff);
+}
+
+void OPPROTO op_iwmmxt_extrsw_T0_M0(void)
+{
+    T0 = EXTEND16((M0 >> PARAM1) & 0xffff);
+}
+
+void OPPROTO op_iwmmxt_extru_T0_M0_T1(void)
+{
+    T0 = (M0 >> PARAM1) & T1;
+}
+
+void OPPROTO op_iwmmxt_bcstb_M0_T0(void)
+{
+    T0 &= 0xff;
+    M0 =
+        ((uint64_t) T0 << 0) | ((uint64_t) T0 << 8) |
+        ((uint64_t) T0 << 16) | ((uint64_t) T0 << 24) |
+        ((uint64_t) T0 << 32) | ((uint64_t) T0 << 40) |
+        ((uint64_t) T0 << 48) | ((uint64_t) T0 << 56);
+}
+
+void OPPROTO op_iwmmxt_bcstw_M0_T0(void)
+{
+    T0 &= 0xffff;
+    M0 =
+        ((uint64_t) T0 << 0) | ((uint64_t) T0 << 16) |
+        ((uint64_t) T0 << 32) | ((uint64_t) T0 << 48);
+}
+
+void OPPROTO op_iwmmxt_bcstl_M0_T0(void)
+{
+    M0 = ((uint64_t) T0 << 0) | ((uint64_t) T0 << 32);
+}
+
+void OPPROTO op_iwmmxt_addcb_M0(void)
+{
+    M0 =
+        ((M0 >> 0) & 0xff) + ((M0 >> 8) & 0xff) +
+        ((M0 >> 16) & 0xff) + ((M0 >> 24) & 0xff) +
+        ((M0 >> 32) & 0xff) + ((M0 >> 40) & 0xff) +
+        ((M0 >> 48) & 0xff) + ((M0 >> 56) & 0xff);
+}
+
+void OPPROTO op_iwmmxt_addcw_M0(void)
+{
+    M0 =
+        ((M0 >> 0) & 0xffff) + ((M0 >> 16) & 0xffff) +
+        ((M0 >> 32) & 0xffff) + ((M0 >> 48) & 0xffff);
+}
+
+void OPPROTO op_iwmmxt_addcl_M0(void)
+{
+    M0 = (M0 & 0xffffffff) + (M0 >> 32);
+}
+
+void OPPROTO op_iwmmxt_msbb_T0_M0(void)
+{
+    T0 =
+        ((M0 >> 7) & 0x01) | ((M0 >> 14) & 0x02) |
+        ((M0 >> 21) & 0x04) | ((M0 >> 28) & 0x08) |
+        ((M0 >> 35) & 0x10) | ((M0 >> 42) & 0x20) |
+        ((M0 >> 49) & 0x40) | ((M0 >> 56) & 0x80);
+}
+
+void OPPROTO op_iwmmxt_msbw_T0_M0(void)
+{
+    T0 =
+        ((M0 >> 15) & 0x01) | ((M0 >> 30) & 0x02) |
+        ((M0 >> 45) & 0x04) | ((M0 >> 52) & 0x08);
+}
+
+void OPPROTO op_iwmmxt_msbl_T0_M0(void)
+{
+    T0 = ((M0 >> 31) & 0x01) | ((M0 >> 62) & 0x02);
+}
+
+void OPPROTO op_iwmmxt_srlw_M0_T0(void)
+{
+    M0 =
+        (((M0 & (0xffffll << 0)) >> T0) & (0xffffll << 0)) |
+        (((M0 & (0xffffll << 16)) >> T0) & (0xffffll << 16)) |
+        (((M0 & (0xffffll << 32)) >> T0) & (0xffffll << 32)) |
+        (((M0 & (0xffffll << 48)) >> T0) & (0xffffll << 48));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_srll_M0_T0(void)
+{
+    M0 =
+        ((M0 & (0xffffffffll << 0)) >> T0) |
+        ((M0 >> T0) & (0xffffffffll << 32));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_srlq_M0_T0(void)
+{
+    M0 >>= T0;
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
+}
+
+void OPPROTO op_iwmmxt_sllw_M0_T0(void)
+{
+    M0 =
+        (((M0 & (0xffffll << 0)) << T0) & (0xffffll << 0)) |
+        (((M0 & (0xffffll << 16)) << T0) & (0xffffll << 16)) |
+        (((M0 & (0xffffll << 32)) << T0) & (0xffffll << 32)) |
+        (((M0 & (0xffffll << 48)) << T0) & (0xffffll << 48));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_slll_M0_T0(void)
+{
+    M0 =
+        ((M0 << T0) & (0xffffffffll << 0)) |
+        ((M0 & (0xffffffffll << 32)) << T0);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_sllq_M0_T0(void)
+{
+    M0 <<= T0;
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
+}
+
+void OPPROTO op_iwmmxt_sraw_M0_T0(void)
+{
+    M0 =
+        ((uint64_t) ((EXTEND16(M0 >> 0) >> T0) & 0xffff) << 0) |
+        ((uint64_t) ((EXTEND16(M0 >> 16) >> T0) & 0xffff) << 16) |
+        ((uint64_t) ((EXTEND16(M0 >> 32) >> T0) & 0xffff) << 32) |
+        ((uint64_t) ((EXTEND16(M0 >> 48) >> T0) & 0xffff) << 48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_sral_M0_T0(void)
+{
+    M0 =
+        (((EXTEND32(M0 >> 0) >> T0) & 0xffffffff) << 0) |
+        (((EXTEND32(M0 >> 32) >> T0) & 0xffffffff) << 32);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_sraq_M0_T0(void)
+{
+    M0 = (int64_t) M0 >> T0;
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
+}
+
+void OPPROTO op_iwmmxt_rorw_M0_T0(void)
+{
+    M0 =
+        ((((M0 & (0xffffll << 0)) >> T0) |
+          ((M0 & (0xffffll << 0)) << (16 - T0))) & (0xffffll << 0)) |
+        ((((M0 & (0xffffll << 16)) >> T0) |
+          ((M0 & (0xffffll << 16)) << (16 - T0))) & (0xffffll << 16)) |
+        ((((M0 & (0xffffll << 32)) >> T0) |
+          ((M0 & (0xffffll << 32)) << (16 - T0))) & (0xffffll << 32)) |
+        ((((M0 & (0xffffll << 48)) >> T0) |
+          ((M0 & (0xffffll << 48)) << (16 - T0))) & (0xffffll << 48));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_rorl_M0_T0(void)
+{
+    M0 =
+        ((M0 & (0xffffffffll << 0)) >> T0) |
+        ((M0 >> T0) & (0xffffffffll << 32)) |
+        ((M0 << (32 - T0)) & (0xffffffffll << 0)) |
+        ((M0 & (0xffffffffll << 32)) << (32 - T0));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_rorq_M0_T0(void)
+{
+    M0 = (M0 >> T0) | (M0 << (64 - T0));
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
+}
+
+void OPPROTO op_iwmmxt_shufh_M0_T0(void)
+{
+    M0 =
+        (((M0 >> ((T0 << 4) & 0x30)) & 0xffff) << 0) |
+        (((M0 >> ((T0 << 2) & 0x30)) & 0xffff) << 16) |
+        (((M0 >> ((T0 << 0) & 0x30)) & 0xffff) << 32) |
+        (((M0 >> ((T0 >> 2) & 0x30)) & 0xffff) << 48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+/* TODO: Unsigned-Saturation */
+void OPPROTO op_iwmmxt_packuw_M0_wRn(void)
+{
+    M0 =
+        (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) |
+        (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) |
+        (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) |
+        (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) |
+        NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) |
+        NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) |
+        NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7);
+}
+
+void OPPROTO op_iwmmxt_packul_M0_wRn(void)
+{
+    M0 =
+        (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) |
+        (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_packuq_M0_wRn(void)
+{
+    M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+/* TODO: Signed-Saturation */
+void OPPROTO op_iwmmxt_packsw_M0_wRn(void)
+{
+    M0 =
+        (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) |
+        (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) |
+        (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) |
+        (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) |
+        NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) |
+        NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) |
+        NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7);
+}
+
+void OPPROTO op_iwmmxt_packsl_M0_wRn(void)
+{
+    M0 =
+        (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) |
+        (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+        NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_packsq_M0_wRn(void)
+{
+    M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32);
+    env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+        NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_muladdsl_M0_T0_T1(void)
+{
+    M0 += (int32_t) EXTEND32(T0) * (int32_t) EXTEND32(T1);
+}
+
+void OPPROTO op_iwmmxt_muladdsw_M0_T0_T1(void)
+{
+    M0 += EXTEND32(EXTEND16S((T0 >> 0) & 0xffff) *
+                   EXTEND16S((T1 >> 0) & 0xffff));
+    M0 += EXTEND32(EXTEND16S((T0 >> 16) & 0xffff) *
+                   EXTEND16S((T1 >> 16) & 0xffff));
+}
+
+void OPPROTO op_iwmmxt_muladdswl_M0_T0_T1(void)
+{
+    M0 += EXTEND32(EXTEND16S(T0 & 0xffff) *
+                   EXTEND16S(T1 & 0xffff));
+}
diff --git a/target-arm/op_mem.h b/target-arm/op_mem.h
index 29fd85b..6bccb06 100644
--- a/target-arm/op_mem.h
+++ b/target-arm/op_mem.h
@@ -67,4 +67,24 @@
 
 #undef VFP_MEM_OP
 
+/* iwMMXt load/store.  Address is in T1 */
+#define MMX_MEM_OP(name, ldname) \
+void OPPROTO glue(op_iwmmxt_ld##name,MEMSUFFIX)(void) \
+{ \
+    M0 = glue(ld##ldname,MEMSUFFIX)(T1); \
+    FORCE_RET(); \
+} \
+void OPPROTO glue(op_iwmmxt_st##name,MEMSUFFIX)(void) \
+{ \
+    glue(st##name,MEMSUFFIX)(T1, M0); \
+    FORCE_RET(); \
+}
+
+MMX_MEM_OP(b, ub)
+MMX_MEM_OP(w, uw)
+MMX_MEM_OP(l, l)
+MMX_MEM_OP(q, q)
+
+#undef MMX_MEM_OP
+
 #undef MEMSUFFIX
diff --git a/target-arm/op_template.h b/target-arm/op_template.h
index fb2add1..33d53c0 100644
--- a/target-arm/op_template.h
+++ b/target-arm/op_template.h
@@ -1,7 +1,7 @@
 /*
  *  ARM micro operations (templates for various register related
  *  operations)
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
diff --git a/target-arm/translate.c b/target-arm/translate.c
index cd91bdc..bb01f2f 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -1,8 +1,9 @@
 /*
  *  ARM translation
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *  Copyright (c) 2005 CodeSourcery, LLC
+ *  Copyright (c) 2007 OpenedHand, Ltd.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -45,6 +46,7 @@
     struct TranslationBlock *tb;
     int singlestep_enabled;
     int thumb;
+    int is_mem;
 #if !defined(CONFIG_USER_ONLY)
     int user;
 #endif
@@ -114,7 +116,7 @@
     1, /* bic */
     1, /* mvn */
 };
-    
+
 static GenOpFunc1 *gen_shift_T1_im[4] = {
     gen_op_shll_T1_im,
     gen_op_shrl_T1_im,
@@ -290,6 +292,7 @@
 #define gen_ldst(name, s) gen_op_##name##_raw()
 #else
 #define gen_ldst(name, s) do { \
+    s->is_mem = 1; \
     if (IS_USER(s)) \
         gen_op_##name##_user(); \
     else \
@@ -387,13 +390,13 @@
                                         int extra)
 {
     int val, rm;
-    
+
     if (insn & (1 << 22)) {
         /* immediate */
         val = (insn & 0xf) | ((insn >> 4) & 0xf0);
-        val += extra;
         if (!(insn & (1 << 23)))
             val = -val;
+        val += extra;
         if (val != 0)
             gen_op_addl_T1_im(val);
     } else {
@@ -490,9 +493,1098 @@
         gen_op_vfp_setreg_F0s(vfp_reg_offset(dp, reg));
 }
 
+#define ARM_CP_RW_BIT	(1 << 20)
+
+static inline int gen_iwmmxt_address(DisasContext *s, uint32_t insn)
+{
+    int rd;
+    uint32_t offset;
+
+    rd = (insn >> 16) & 0xf;
+    gen_movl_T1_reg(s, rd);
+
+    offset = (insn & 0xff) << ((insn >> 7) & 2);
+    if (insn & (1 << 24)) {
+        /* Pre indexed */
+        if (insn & (1 << 23))
+            gen_op_addl_T1_im(offset);
+        else
+            gen_op_addl_T1_im(-offset);
+
+        if (insn & (1 << 21))
+            gen_movl_reg_T1(s, rd);
+    } else if (insn & (1 << 21)) {
+        /* Post indexed */
+        if (insn & (1 << 23))
+            gen_op_movl_T0_im(offset);
+        else
+            gen_op_movl_T0_im(- offset);
+        gen_op_addl_T0_T1();
+        gen_movl_reg_T0(s, rd);
+    } else if (!(insn & (1 << 23)))
+        return 1;
+    return 0;
+}
+
+static inline int gen_iwmmxt_shift(uint32_t insn, uint32_t mask)
+{
+    int rd = (insn >> 0) & 0xf;
+
+    if (insn & (1 << 8))
+        if (rd < ARM_IWMMXT_wCGR0 || rd > ARM_IWMMXT_wCGR3)
+            return 1;
+        else
+            gen_op_iwmmxt_movl_T0_wCx(rd);
+    else
+        gen_op_iwmmxt_movl_T0_T1_wRn(rd);
+
+    gen_op_movl_T1_im(mask);
+    gen_op_andl_T0_T1();
+    return 0;
+}
+
+/* Disassemble an iwMMXt instruction.  Returns nonzero if an error occured
+   (ie. an undefined instruction).  */
+static int disas_iwmmxt_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    int rd, wrd;
+    int rdhi, rdlo, rd0, rd1, i;
+
+    if ((insn & 0x0e000e00) == 0x0c000000) {
+        if ((insn & 0x0fe00ff0) == 0x0c400000) {
+            wrd = insn & 0xf;
+            rdlo = (insn >> 12) & 0xf;
+            rdhi = (insn >> 16) & 0xf;
+            if (insn & ARM_CP_RW_BIT) {			/* TMRRC */
+                gen_op_iwmmxt_movl_T0_T1_wRn(wrd);
+                gen_movl_reg_T0(s, rdlo);
+                gen_movl_reg_T1(s, rdhi);
+            } else {					/* TMCRR */
+                gen_movl_T0_reg(s, rdlo);
+                gen_movl_T1_reg(s, rdhi);
+                gen_op_iwmmxt_movl_wRn_T0_T1(wrd);
+                gen_op_iwmmxt_set_mup();
+            }
+            return 0;
+        }
+
+        wrd = (insn >> 12) & 0xf;
+        if (gen_iwmmxt_address(s, insn))
+            return 1;
+        if (insn & ARM_CP_RW_BIT) {
+            if ((insn >> 28) == 0xf) {			/* WLDRW wCx */
+                gen_ldst(ldl, s);
+                gen_op_iwmmxt_movl_wCx_T0(wrd);
+            } else {
+                if (insn & (1 << 8))
+                    if (insn & (1 << 22))		/* WLDRD */
+                        gen_ldst(iwmmxt_ldq, s);
+                    else				/* WLDRW wRd */
+                        gen_ldst(iwmmxt_ldl, s);
+                else
+                    if (insn & (1 << 22))		/* WLDRH */
+                        gen_ldst(iwmmxt_ldw, s);
+                    else				/* WLDRB */
+                        gen_ldst(iwmmxt_ldb, s);
+                gen_op_iwmmxt_movq_wRn_M0(wrd);
+            }
+        } else {
+            if ((insn >> 28) == 0xf) {			/* WSTRW wCx */
+                gen_op_iwmmxt_movl_T0_wCx(wrd);
+                gen_ldst(stl, s);
+            } else {
+                gen_op_iwmmxt_movq_M0_wRn(wrd);
+                if (insn & (1 << 8))
+                    if (insn & (1 << 22))		/* WSTRD */
+                        gen_ldst(iwmmxt_stq, s);
+                    else				/* WSTRW wRd */
+                        gen_ldst(iwmmxt_stl, s);
+                else
+                    if (insn & (1 << 22))		/* WSTRH */
+                        gen_ldst(iwmmxt_ldw, s);
+                    else				/* WSTRB */
+                        gen_ldst(iwmmxt_stb, s);
+            }
+        }
+        return 0;
+    }
+
+    if ((insn & 0x0f000000) != 0x0e000000)
+        return 1;
+
+    switch (((insn >> 12) & 0xf00) | ((insn >> 4) & 0xff)) {
+    case 0x000:						/* WOR */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_iwmmxt_orq_M0_wRn(rd1);
+        gen_op_iwmmxt_setpsr_nz();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x011:						/* TMCR */
+        if (insn & 0xf)
+            return 1;
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        switch (wrd) {
+        case ARM_IWMMXT_wCID:
+        case ARM_IWMMXT_wCASF:
+            break;
+        case ARM_IWMMXT_wCon:
+            gen_op_iwmmxt_set_cup();
+            /* Fall through.  */
+        case ARM_IWMMXT_wCSSF:
+            gen_op_iwmmxt_movl_T0_wCx(wrd);
+            gen_movl_T1_reg(s, rd);
+            gen_op_bicl_T0_T1();
+            gen_op_iwmmxt_movl_wCx_T0(wrd);
+            break;
+        case ARM_IWMMXT_wCGR0:
+        case ARM_IWMMXT_wCGR1:
+        case ARM_IWMMXT_wCGR2:
+        case ARM_IWMMXT_wCGR3:
+            gen_op_iwmmxt_set_cup();
+            gen_movl_reg_T0(s, rd);
+            gen_op_iwmmxt_movl_wCx_T0(wrd);
+            break;
+        default:
+            return 1;
+        }
+        break;
+    case 0x100:						/* WXOR */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_iwmmxt_xorq_M0_wRn(rd1);
+        gen_op_iwmmxt_setpsr_nz();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x111:						/* TMRC */
+        if (insn & 0xf)
+            return 1;
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movl_T0_wCx(wrd);
+        gen_movl_reg_T0(s, rd);
+        break;
+    case 0x300:						/* WANDN */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_iwmmxt_negq_M0();
+        gen_op_iwmmxt_andq_M0_wRn(rd1);
+        gen_op_iwmmxt_setpsr_nz();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x200:						/* WAND */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_iwmmxt_andq_M0_wRn(rd1);
+        gen_op_iwmmxt_setpsr_nz();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x810: case 0xa10:				/* WMADD */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 0) & 0xf;
+        rd1 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 21))
+            gen_op_iwmmxt_maddsq_M0_wRn(rd1);
+        else
+            gen_op_iwmmxt_madduq_M0_wRn(rd1);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x10e: case 0x50e: case 0x90e: case 0xd0e:	/* WUNPCKIL */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_iwmmxt_unpacklb_M0_wRn(rd1);
+            break;
+        case 1:
+            gen_op_iwmmxt_unpacklw_M0_wRn(rd1);
+            break;
+        case 2:
+            gen_op_iwmmxt_unpackll_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x10c: case 0x50c: case 0x90c: case 0xd0c:	/* WUNPCKIH */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_iwmmxt_unpackhb_M0_wRn(rd1);
+            break;
+        case 1:
+            gen_op_iwmmxt_unpackhw_M0_wRn(rd1);
+            break;
+        case 2:
+            gen_op_iwmmxt_unpackhl_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x012: case 0x112: case 0x412: case 0x512:	/* WSAD */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 22))
+            gen_op_iwmmxt_sadw_M0_wRn(rd1);
+        else
+            gen_op_iwmmxt_sadb_M0_wRn(rd1);
+        if (!(insn & (1 << 20)))
+            gen_op_iwmmxt_addl_M0_wRn(wrd);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x010: case 0x110: case 0x210: case 0x310:	/* WMUL */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 21))
+            gen_op_iwmmxt_mulsw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0);
+        else
+            gen_op_iwmmxt_muluw_M0_wRn(rd1, (insn & (1 << 20)) ? 16 : 0);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x410: case 0x510: case 0x610: case 0x710:	/* WMAC */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 21))
+            gen_op_iwmmxt_macsw_M0_wRn(rd1);
+        else
+            gen_op_iwmmxt_macuw_M0_wRn(rd1);
+        if (!(insn & (1 << 20))) {
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_addsq_M0_wRn(wrd);
+            else
+                gen_op_iwmmxt_adduq_M0_wRn(wrd);
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x006: case 0x406: case 0x806: case 0xc06:	/* WCMPEQ */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_iwmmxt_cmpeqb_M0_wRn(rd1);
+            break;
+        case 1:
+            gen_op_iwmmxt_cmpeqw_M0_wRn(rd1);
+            break;
+        case 2:
+            gen_op_iwmmxt_cmpeql_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x800: case 0x900: case 0xc00: case 0xd00:	/* WAVG2 */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (insn & (1 << 22))
+            gen_op_iwmmxt_avgw_M0_wRn(rd1, (insn >> 20) & 1);
+        else
+            gen_op_iwmmxt_avgb_M0_wRn(rd1, (insn >> 20) & 1);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x802: case 0x902: case 0xa02: case 0xb02:	/* WALIGNR */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_iwmmxt_movl_T0_wCx(ARM_IWMMXT_wCGR0 + ((insn >> 20) & 3));
+        gen_op_movl_T1_im(7);
+        gen_op_andl_T0_T1();
+        gen_op_iwmmxt_align_M0_T0_wRn(rd1);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x601: case 0x605: case 0x609: case 0x60d:	/* TINSR */
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        gen_movl_T0_reg(s, rd);
+        gen_op_iwmmxt_movq_M0_wRn(wrd);
+        switch ((insn >> 6) & 3) {
+        case 0:
+            gen_op_movl_T1_im(0xff);
+            gen_op_iwmmxt_insr_M0_T0_T1((insn & 7) << 3);
+            break;
+        case 1:
+            gen_op_movl_T1_im(0xffff);
+            gen_op_iwmmxt_insr_M0_T0_T1((insn & 3) << 4);
+            break;
+        case 2:
+            gen_op_movl_T1_im(0xffffffff);
+            gen_op_iwmmxt_insr_M0_T0_T1((insn & 1) << 5);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x107: case 0x507: case 0x907: case 0xd07:	/* TEXTRM */
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        if (rd == 15)
+            return 1;
+        gen_op_iwmmxt_movq_M0_wRn(wrd);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & 8)
+                gen_op_iwmmxt_extrsb_T0_M0((insn & 7) << 3);
+            else {
+                gen_op_movl_T1_im(0xff);
+                gen_op_iwmmxt_extru_T0_M0_T1((insn & 7) << 3);
+            }
+            break;
+        case 1:
+            if (insn & 8)
+                gen_op_iwmmxt_extrsw_T0_M0((insn & 3) << 4);
+            else {
+                gen_op_movl_T1_im(0xffff);
+                gen_op_iwmmxt_extru_T0_M0_T1((insn & 3) << 4);
+            }
+            break;
+        case 2:
+            gen_op_movl_T1_im(0xffffffff);
+            gen_op_iwmmxt_extru_T0_M0_T1((insn & 1) << 5);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_movl_reg_TN[0][rd]();
+        break;
+    case 0x117: case 0x517: case 0x917: case 0xd17:	/* TEXTRC */
+        if ((insn & 0x000ff008) != 0x0003f000)
+            return 1;
+        gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_shrl_T1_im(((insn & 7) << 2) + 0);
+            break;
+        case 1:
+            gen_op_shrl_T1_im(((insn & 3) << 3) + 4);
+            break;
+        case 2:
+            gen_op_shrl_T1_im(((insn & 1) << 4) + 12);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_shll_T1_im(28);
+        gen_op_movl_T0_T1();
+        gen_op_movl_cpsr_T0(0xf0000000);
+        break;
+    case 0x401: case 0x405: case 0x409: case 0x40d:	/* TBCST */
+        rd = (insn >> 12) & 0xf;
+        wrd = (insn >> 16) & 0xf;
+        gen_movl_T0_reg(s, rd);
+        switch ((insn >> 6) & 3) {
+        case 0:
+            gen_op_iwmmxt_bcstb_M0_T0();
+            break;
+        case 1:
+            gen_op_iwmmxt_bcstw_M0_T0();
+            break;
+        case 2:
+            gen_op_iwmmxt_bcstl_M0_T0();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x113: case 0x513: case 0x913: case 0xd13:	/* TANDC */
+        if ((insn & 0x000ff00f) != 0x0003f000)
+            return 1;
+        gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            for (i = 0; i < 7; i ++) {
+                gen_op_shll_T1_im(4);
+                gen_op_andl_T0_T1();
+            }
+            break;
+        case 1:
+            for (i = 0; i < 3; i ++) {
+                gen_op_shll_T1_im(8);
+                gen_op_andl_T0_T1();
+            }
+            break;
+        case 2:
+            gen_op_shll_T1_im(16);
+            gen_op_andl_T0_T1();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_movl_cpsr_T0(0xf0000000);
+        break;
+    case 0x01c: case 0x41c: case 0x81c: case 0xc1c:	/* WACC */
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_iwmmxt_addcb_M0();
+            break;
+        case 1:
+            gen_op_iwmmxt_addcw_M0();
+            break;
+        case 2:
+            gen_op_iwmmxt_addcl_M0();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x115: case 0x515: case 0x915: case 0xd15:	/* TORC */
+        if ((insn & 0x000ff00f) != 0x0003f000)
+            return 1;
+        gen_op_iwmmxt_movl_T1_wCx(ARM_IWMMXT_wCASF);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            for (i = 0; i < 7; i ++) {
+                gen_op_shll_T1_im(4);
+                gen_op_orl_T0_T1();
+            }
+            break;
+        case 1:
+            for (i = 0; i < 3; i ++) {
+                gen_op_shll_T1_im(8);
+                gen_op_orl_T0_T1();
+            }
+            break;
+        case 2:
+            gen_op_shll_T1_im(16);
+            gen_op_orl_T0_T1();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_movl_T1_im(0xf0000000);
+        gen_op_andl_T0_T1();
+        gen_op_movl_cpsr_T0(0xf0000000);
+        break;
+    case 0x103: case 0x503: case 0x903: case 0xd03:	/* TMOVMSK */
+        rd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        if ((insn & 0xf) != 0)
+            return 1;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            gen_op_iwmmxt_msbb_T0_M0();
+            break;
+        case 1:
+            gen_op_iwmmxt_msbw_T0_M0();
+            break;
+        case 2:
+            gen_op_iwmmxt_msbl_T0_M0();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_movl_reg_T0(s, rd);
+        break;
+    case 0x106: case 0x306: case 0x506: case 0x706:	/* WCMPGT */
+    case 0x906: case 0xb06: case 0xd06: case 0xf06:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_cmpgtsb_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_cmpgtub_M0_wRn(rd1);
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_cmpgtsw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_cmpgtuw_M0_wRn(rd1);
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_cmpgtsl_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_cmpgtul_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x00e: case 0x20e: case 0x40e: case 0x60e:	/* WUNPCKEL */
+    case 0x80e: case 0xa0e: case 0xc0e: case 0xe0e:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpacklsb_M0();
+            else
+                gen_op_iwmmxt_unpacklub_M0();
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpacklsw_M0();
+            else
+                gen_op_iwmmxt_unpackluw_M0();
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpacklsl_M0();
+            else
+                gen_op_iwmmxt_unpacklul_M0();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x00c: case 0x20c: case 0x40c: case 0x60c:	/* WUNPCKEH */
+    case 0x80c: case 0xa0c: case 0xc0c: case 0xe0c:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpackhsb_M0();
+            else
+                gen_op_iwmmxt_unpackhub_M0();
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpackhsw_M0();
+            else
+                gen_op_iwmmxt_unpackhuw_M0();
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_unpackhsl_M0();
+            else
+                gen_op_iwmmxt_unpackhul_M0();
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x204: case 0x604: case 0xa04: case 0xe04:	/* WSRL */
+    case 0x214: case 0x614: case 0xa14: case 0xe14:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (gen_iwmmxt_shift(insn, 0xff))
+            return 1;
+        switch ((insn >> 22) & 3) {
+        case 0:
+            return 1;
+        case 1:
+            gen_op_iwmmxt_srlw_M0_T0();
+            break;
+        case 2:
+            gen_op_iwmmxt_srll_M0_T0();
+            break;
+        case 3:
+            gen_op_iwmmxt_srlq_M0_T0();
+            break;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x004: case 0x404: case 0x804: case 0xc04:	/* WSRA */
+    case 0x014: case 0x414: case 0x814: case 0xc14:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (gen_iwmmxt_shift(insn, 0xff))
+            return 1;
+        switch ((insn >> 22) & 3) {
+        case 0:
+            return 1;
+        case 1:
+            gen_op_iwmmxt_sraw_M0_T0();
+            break;
+        case 2:
+            gen_op_iwmmxt_sral_M0_T0();
+            break;
+        case 3:
+            gen_op_iwmmxt_sraq_M0_T0();
+            break;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x104: case 0x504: case 0x904: case 0xd04:	/* WSLL */
+    case 0x114: case 0x514: case 0x914: case 0xd14:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (gen_iwmmxt_shift(insn, 0xff))
+            return 1;
+        switch ((insn >> 22) & 3) {
+        case 0:
+            return 1;
+        case 1:
+            gen_op_iwmmxt_sllw_M0_T0();
+            break;
+        case 2:
+            gen_op_iwmmxt_slll_M0_T0();
+            break;
+        case 3:
+            gen_op_iwmmxt_sllq_M0_T0();
+            break;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x304: case 0x704: case 0xb04: case 0xf04:	/* WROR */
+    case 0x314: case 0x714: case 0xb14: case 0xf14:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            return 1;
+        case 1:
+            if (gen_iwmmxt_shift(insn, 0xf))
+                return 1;
+            gen_op_iwmmxt_rorw_M0_T0();
+            break;
+        case 2:
+            if (gen_iwmmxt_shift(insn, 0x1f))
+                return 1;
+            gen_op_iwmmxt_rorl_M0_T0();
+            break;
+        case 3:
+            if (gen_iwmmxt_shift(insn, 0x3f))
+                return 1;
+            gen_op_iwmmxt_rorq_M0_T0();
+            break;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x116: case 0x316: case 0x516: case 0x716:	/* WMIN */
+    case 0x916: case 0xb16: case 0xd16: case 0xf16:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_minsb_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_minub_M0_wRn(rd1);
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_minsw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_minuw_M0_wRn(rd1);
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_minsl_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_minul_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x016: case 0x216: case 0x416: case 0x616:	/* WMAX */
+    case 0x816: case 0xa16: case 0xc16: case 0xe16:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 22) & 3) {
+        case 0:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_maxsb_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_maxub_M0_wRn(rd1);
+            break;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_maxsw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_maxuw_M0_wRn(rd1);
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_maxsl_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_maxul_M0_wRn(rd1);
+            break;
+        case 3:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x002: case 0x102: case 0x202: case 0x302:	/* WALIGNI */
+    case 0x402: case 0x502: case 0x602: case 0x702:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_movl_T0_im((insn >> 20) & 3);
+        gen_op_iwmmxt_align_M0_T0_wRn(rd1);
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    case 0x01a: case 0x11a: case 0x21a: case 0x31a:	/* WSUB */
+    case 0x41a: case 0x51a: case 0x61a: case 0x71a:
+    case 0x81a: case 0x91a: case 0xa1a: case 0xb1a:
+    case 0xc1a: case 0xd1a: case 0xe1a: case 0xf1a:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 20) & 0xf) {
+        case 0x0:
+            gen_op_iwmmxt_subnb_M0_wRn(rd1);
+            break;
+        case 0x1:
+            gen_op_iwmmxt_subub_M0_wRn(rd1);
+            break;
+        case 0x3:
+            gen_op_iwmmxt_subsb_M0_wRn(rd1);
+            break;
+        case 0x4:
+            gen_op_iwmmxt_subnw_M0_wRn(rd1);
+            break;
+        case 0x5:
+            gen_op_iwmmxt_subuw_M0_wRn(rd1);
+            break;
+        case 0x7:
+            gen_op_iwmmxt_subsw_M0_wRn(rd1);
+            break;
+        case 0x8:
+            gen_op_iwmmxt_subnl_M0_wRn(rd1);
+            break;
+        case 0x9:
+            gen_op_iwmmxt_subul_M0_wRn(rd1);
+            break;
+        case 0xb:
+            gen_op_iwmmxt_subsl_M0_wRn(rd1);
+            break;
+        default:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x01e: case 0x11e: case 0x21e: case 0x31e:	/* WSHUFH */
+    case 0x41e: case 0x51e: case 0x61e: case 0x71e:
+    case 0x81e: case 0x91e: case 0xa1e: case 0xb1e:
+    case 0xc1e: case 0xd1e: case 0xe1e: case 0xf1e:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        gen_op_movl_T0_im(((insn >> 16) & 0xf0) | (insn & 0x0f));
+        gen_op_iwmmxt_shufh_M0_T0();
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x018: case 0x118: case 0x218: case 0x318:	/* WADD */
+    case 0x418: case 0x518: case 0x618: case 0x718:
+    case 0x818: case 0x918: case 0xa18: case 0xb18:
+    case 0xc18: case 0xd18: case 0xe18: case 0xf18:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        switch ((insn >> 20) & 0xf) {
+        case 0x0:
+            gen_op_iwmmxt_addnb_M0_wRn(rd1);
+            break;
+        case 0x1:
+            gen_op_iwmmxt_addub_M0_wRn(rd1);
+            break;
+        case 0x3:
+            gen_op_iwmmxt_addsb_M0_wRn(rd1);
+            break;
+        case 0x4:
+            gen_op_iwmmxt_addnw_M0_wRn(rd1);
+            break;
+        case 0x5:
+            gen_op_iwmmxt_adduw_M0_wRn(rd1);
+            break;
+        case 0x7:
+            gen_op_iwmmxt_addsw_M0_wRn(rd1);
+            break;
+        case 0x8:
+            gen_op_iwmmxt_addnl_M0_wRn(rd1);
+            break;
+        case 0x9:
+            gen_op_iwmmxt_addul_M0_wRn(rd1);
+            break;
+        case 0xb:
+            gen_op_iwmmxt_addsl_M0_wRn(rd1);
+            break;
+        default:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x008: case 0x108: case 0x208: case 0x308:	/* WPACK */
+    case 0x408: case 0x508: case 0x608: case 0x708:
+    case 0x808: case 0x908: case 0xa08: case 0xb08:
+    case 0xc08: case 0xd08: case 0xe08: case 0xf08:
+        wrd = (insn >> 12) & 0xf;
+        rd0 = (insn >> 16) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        gen_op_iwmmxt_movq_M0_wRn(rd0);
+        if (!(insn & (1 << 20)))
+            return 1;
+        switch ((insn >> 22) & 3) {
+        case 0:
+            return 1;
+        case 1:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_packsw_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_packuw_M0_wRn(rd1);
+            break;
+        case 2:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_packsl_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_packul_M0_wRn(rd1);
+            break;
+        case 3:
+            if (insn & (1 << 21))
+                gen_op_iwmmxt_packsq_M0_wRn(rd1);
+            else
+                gen_op_iwmmxt_packuq_M0_wRn(rd1);
+            break;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        gen_op_iwmmxt_set_cup();
+        break;
+    case 0x201: case 0x203: case 0x205: case 0x207:
+    case 0x209: case 0x20b: case 0x20d: case 0x20f:
+    case 0x211: case 0x213: case 0x215: case 0x217:
+    case 0x219: case 0x21b: case 0x21d: case 0x21f:
+        wrd = (insn >> 5) & 0xf;
+        rd0 = (insn >> 12) & 0xf;
+        rd1 = (insn >> 0) & 0xf;
+        if (rd0 == 0xf || rd1 == 0xf)
+            return 1;
+        gen_op_iwmmxt_movq_M0_wRn(wrd);
+        switch ((insn >> 16) & 0xf) {
+        case 0x0:					/* TMIA */
+            gen_op_movl_TN_reg[0][rd0]();
+            gen_op_movl_TN_reg[1][rd1]();
+            gen_op_iwmmxt_muladdsl_M0_T0_T1();
+            break;
+        case 0x8:					/* TMIAPH */
+            gen_op_movl_TN_reg[0][rd0]();
+            gen_op_movl_TN_reg[1][rd1]();
+            gen_op_iwmmxt_muladdsw_M0_T0_T1();
+            break;
+        case 0xc: case 0xd: case 0xe: case 0xf:		/* TMIAxy */
+            gen_op_movl_TN_reg[1][rd0]();
+            if (insn & (1 << 16))
+                gen_op_shrl_T1_im(16);
+            gen_op_movl_T0_T1();
+            gen_op_movl_TN_reg[1][rd1]();
+            if (insn & (1 << 17))
+                gen_op_shrl_T1_im(16);
+            gen_op_iwmmxt_muladdswl_M0_T0_T1();
+            break;
+        default:
+            return 1;
+        }
+        gen_op_iwmmxt_movq_wRn_M0(wrd);
+        gen_op_iwmmxt_set_mup();
+        break;
+    default:
+        return 1;
+    }
+
+    return 0;
+}
+
+/* Disassemble an XScale DSP instruction.  Returns nonzero if an error occured
+   (ie. an undefined instruction).  */
+static int disas_dsp_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    int acc, rd0, rd1, rdhi, rdlo;
+
+    if ((insn & 0x0ff00f10) == 0x0e200010) {
+        /* Multiply with Internal Accumulate Format */
+        rd0 = (insn >> 12) & 0xf;
+        rd1 = insn & 0xf;
+        acc = (insn >> 5) & 7;
+
+        if (acc != 0)
+            return 1;
+
+        switch ((insn >> 16) & 0xf) {
+        case 0x0:					/* MIA */
+            gen_op_movl_TN_reg[0][rd0]();
+            gen_op_movl_TN_reg[1][rd1]();
+            gen_op_iwmmxt_muladdsl_M0_T0_T1();
+            break;
+        case 0x8:					/* MIAPH */
+            gen_op_movl_TN_reg[0][rd0]();
+            gen_op_movl_TN_reg[1][rd1]();
+            gen_op_iwmmxt_muladdsw_M0_T0_T1();
+            break;
+        case 0xc:					/* MIABB */
+        case 0xd:					/* MIABT */
+        case 0xe:					/* MIATB */
+        case 0xf:					/* MIATT */
+            gen_op_movl_TN_reg[1][rd0]();
+            if (insn & (1 << 16))
+                gen_op_shrl_T1_im(16);
+            gen_op_movl_T0_T1();
+            gen_op_movl_TN_reg[1][rd1]();
+            if (insn & (1 << 17))
+                gen_op_shrl_T1_im(16);
+            gen_op_iwmmxt_muladdswl_M0_T0_T1();
+            break;
+        default:
+            return 1;
+        }
+
+        gen_op_iwmmxt_movq_wRn_M0(acc);
+        return 0;
+    }
+
+    if ((insn & 0x0fe00ff8) == 0x0c400000) {
+        /* Internal Accumulator Access Format */
+        rdhi = (insn >> 16) & 0xf;
+        rdlo = (insn >> 12) & 0xf;
+        acc = insn & 7;
+
+        if (acc != 0)
+            return 1;
+
+        if (insn & ARM_CP_RW_BIT) {			/* MRA */
+            gen_op_iwmmxt_movl_T0_T1_wRn(acc);
+            gen_op_movl_reg_TN[0][rdlo]();
+            gen_op_movl_T0_im((1 << (40 - 32)) - 1);
+            gen_op_andl_T0_T1();
+            gen_op_movl_reg_TN[0][rdhi]();
+        } else {					/* MAR */
+            gen_op_movl_TN_reg[0][rdlo]();
+            gen_op_movl_TN_reg[1][rdhi]();
+            gen_op_iwmmxt_movl_wRn_T0_T1(acc);
+        }
+        return 0;
+    }
+
+    return 1;
+}
+
+/* Disassemble system coprocessor instruction.  Return nonzero if
+   instruction is not defined.  */
+static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
+{
+    uint32_t rd = (insn >> 12) & 0xf;
+    uint32_t cp = (insn >> 8) & 0xf;
+    if (IS_USER(s)) {
+        return 1;
+    }
+
+    if (insn & ARM_CP_RW_BIT) {
+        if (!env->cp[cp].cp_read)
+            return 1;
+        gen_op_movl_T0_im((uint32_t) s->pc);
+        gen_op_movl_reg_TN[0][15]();
+        gen_op_movl_T0_cp(insn);
+        gen_movl_reg_T0(s, rd);
+    } else {
+        if (!env->cp[cp].cp_write)
+            return 1;
+        gen_op_movl_T0_im((uint32_t) s->pc);
+        gen_op_movl_reg_TN[0][15]();
+        gen_movl_T0_reg(s, rd);
+        gen_op_movl_cp_T0(insn);
+    }
+    return 0;
+}
+
 /* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
    instruction is not defined.  */
-static int disas_cp15_insn(DisasContext *s, uint32_t insn)
+static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
 {
     uint32_t rd;
 
@@ -510,7 +1602,7 @@
         return 0;
     }
     rd = (insn >> 12) & 0xf;
-    if (insn & (1 << 20)) {
+    if (insn & ARM_CP_RW_BIT) {
         gen_op_movl_T0_cp15(insn);
         /* If the destination register is r15 then sets condition codes.  */
         if (rd != 15)
@@ -518,8 +1610,13 @@
     } else {
         gen_movl_T0_reg(s, rd);
         gen_op_movl_cp15_T0(insn);
+        /* Normally we would always end the TB here, but Linux
+         * arch/arm/mach-pxa/sleep.S expects two instructions following
+         * an MMU enable to execute from cache.  Imitate this behaviour.  */
+        if (!arm_feature(env, ARM_FEATURE_XSCALE) ||
+                (insn & 0x0fff0fff) != 0x0e010f10)
+            gen_lookup_tb(s);
     }
-    gen_lookup_tb(s);
     return 0;
 }
 
@@ -557,7 +1654,7 @@
                    we only set half the register.  */
                 gen_mov_F0_vreg(1, rn);
                 gen_op_vfp_mrrd();
-                if (insn & (1 << 20)) {
+                if (insn & ARM_CP_RW_BIT) {
                     /* vfp->arm */
                     if (insn & (1 << 21))
                         gen_movl_reg_T1(s, rd);
@@ -574,7 +1671,7 @@
                 }
             } else {
                 rn = ((insn >> 15) & 0x1e) | ((insn >> 7) & 1);
-                if (insn & (1 << 20)) {
+                if (insn & ARM_CP_RW_BIT) {
                     /* vfp->arm */
                     if (insn & (1 << 21)) {
                         /* system register */
@@ -687,7 +1784,7 @@
             delta_m = 0;
             delta_d = 0;
             bank_mask = 0;
-            
+
             if (veclen > 0) {
                 if (dp)
                     bank_mask = 0xc;
@@ -908,7 +2005,7 @@
             } else
                 rm = ((insn << 1) & 0x1e) | ((insn >> 5) & 1);
 
-            if (insn & (1 << 20)) {
+            if (insn & ARM_CP_RW_BIT) {
                 /* vfp->arm */
                 if (dp) {
                     gen_mov_F0_vreg(1, rm);
@@ -975,7 +2072,7 @@
                 else
                     offset = 4;
                 for (i = 0; i < n; i++) {
-                    if (insn & (1 << 20)) {
+                    if (insn & ARM_CP_RW_BIT) {
                         /* load */
                         gen_vfp_ld(s, dp);
                         gen_mov_vreg_F0(dp, rd + i);
@@ -1108,10 +2205,10 @@
 static void disas_arm_insn(CPUState * env, DisasContext *s)
 {
     unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
-    
+
     insn = ldl_code(s->pc);
     s->pc += 4;
-    
+
     cond = insn >> 28;
     if (cond == 0xf){
         /* Unconditional instructions.  */
@@ -1133,6 +2230,13 @@
             gen_op_movl_T0_im(val);
             gen_bx(s);
             return;
+        } else if ((insn & 0x0e000f00) == 0x0c000100) {
+            if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+                /* iWMMXt register transfer.  */
+                if (env->cp15.c15_cpar & (1 << 1))
+                    if (!disas_iwmmxt_insn(env, s, insn))
+                        return;
+            }
         } else if ((insn & 0x0fe00000) == 0x0c400000) {
             /* Coprocessor double register transfer.  */
         } else if ((insn & 0x0f000010) == 0x0e000010) {
@@ -1228,9 +2332,9 @@
 
             /* branch link/exchange thumb (blx) */
             val = (uint32_t)s->pc;
-            gen_op_movl_T0_im(val);
-            gen_movl_reg_T0(s, 14);
+            gen_op_movl_T1_im(val);
             gen_movl_T0_reg(s, rm);
+            gen_movl_reg_T1(s, 14);
             gen_bx(s);
             break;
         case 0x5: /* saturating add/subtract */
@@ -1299,7 +2403,7 @@
                 (insn & 0x00000090) != 0x90) ||
                ((insn & 0x0e000000) == (1 << 25))) {
         int set_cc, logic_cc, shiftop;
-        
+
         op1 = (insn >> 21) & 0xf;
         set_cc = (insn >> 20) & 1;
         logic_cc = table_logic_cc[op1] & set_cc;
@@ -1490,14 +2594,14 @@
                             gen_movl_T1_reg(s, rn);
                             gen_op_addl_T0_T1();
                         }
-                        if (insn & (1 << 20)) 
+                        if (insn & (1 << 20))
                             gen_op_logic_T0_cc();
                         gen_movl_reg_T0(s, rd);
                     } else {
                         /* 64 bit mul */
                         gen_movl_T0_reg(s, rs);
                         gen_movl_T1_reg(s, rm);
-                        if (insn & (1 << 22)) 
+                        if (insn & (1 << 22))
                             gen_op_imull_T0_T1();
                         else
                             gen_op_mull_T0_T1();
@@ -1508,7 +2612,7 @@
                             gen_op_addq_lo_T0_T1(rn);
                             gen_op_addq_lo_T0_T1(rd);
                         }
-                        if (insn & (1 << 20)) 
+                        if (insn & (1 << 20))
                             gen_op_logicq_cc();
                         gen_movl_reg_T0(s, rn);
                         gen_movl_reg_T1(s, rd);
@@ -1522,7 +2626,7 @@
                     } else {
                         /* SWP instruction */
                         rm = (insn) & 0xf;
-                        
+
                         gen_movl_T0_reg(s, rm);
                         gen_movl_T1_reg(s, rn);
                         if (insn & (1 << 22)) {
@@ -1535,6 +2639,7 @@
                 }
             } else {
                 int address_offset;
+                int load;
                 /* Misc load/store */
                 rn = (insn >> 16) & 0xf;
                 rd = (insn >> 12) & 0xf;
@@ -1556,7 +2661,7 @@
                         gen_ldst(ldsw, s);
                         break;
                     }
-                    gen_movl_reg_T0(s, rd);
+                    load = 1;
                 } else if (sh & 2) {
                     /* doubleword */
                     if (sh & 1) {
@@ -1566,20 +2671,27 @@
                         gen_op_addl_T1_im(4);
                         gen_movl_T0_reg(s, rd + 1);
                         gen_ldst(stl, s);
+                        load = 0;
                     } else {
                         /* load */
                         gen_ldst(ldl, s);
                         gen_movl_reg_T0(s, rd);
                         gen_op_addl_T1_im(4);
                         gen_ldst(ldl, s);
-                        gen_movl_reg_T0(s, rd + 1);
+                        rd++;
+                        load = 1;
                     }
                     address_offset = -4;
                 } else {
                     /* store */
                     gen_movl_T0_reg(s, rd);
                     gen_ldst(stw, s);
+                    load = 0;
                 }
+                /* Perform base writeback before the loaded value to
+                   ensure correct behavior with overlapping index registers.
+                   ldrd with base writeback is is undefined if the
+                   destination and index registers overlap.  */
                 if (!(insn & (1 << 24))) {
                     gen_add_datah_offset(s, insn, address_offset);
                     gen_movl_reg_T1(s, rn);
@@ -1588,6 +2700,10 @@
                         gen_op_addl_T1_im(address_offset);
                     gen_movl_reg_T1(s, rn);
                 }
+                if (load) {
+                    /* Complete the load.  */
+                    gen_movl_reg_T0(s, rd);
+                }
             }
             break;
         case 0x4:
@@ -1612,6 +2728,7 @@
                 gen_add_data_offset(s, insn);
             if (insn & (1 << 20)) {
                 /* load */
+                s->is_mem = 1;
 #if defined(CONFIG_USER_ONLY)
                 if (insn & (1 << 22))
                     gen_op_ldub_raw();
@@ -1630,10 +2747,6 @@
                         gen_op_ldl_kernel();
                 }
 #endif
-                if (rd == 15)
-                    gen_bx(s);
-                else
-                    gen_movl_reg_T0(s, rd);
             } else {
                 /* store */
                 gen_movl_T0_reg(s, rd);
@@ -1662,6 +2775,13 @@
             } else if (insn & (1 << 21))
                 gen_movl_reg_T1(s, rn); {
             }
+            if (insn & (1 << 20)) {
+                /* Complete the load.  */
+                if (rd == 15)
+                    gen_bx(s);
+                else
+                    gen_movl_reg_T0(s, rd);
+            }
             break;
         case 0x08:
         case 0x09:
@@ -1679,7 +2799,7 @@
                 }
                 rn = (insn >> 16) & 0xf;
                 gen_movl_T1_reg(s, rn);
-                
+
                 /* compute total size */
                 loaded_base = 0;
                 n = 0;
@@ -1724,8 +2844,8 @@
                         } else {
                             /* store */
                             if (i == 15) {
-                                /* special case: r15 = PC + 12 */
-                                val = (long)s->pc + 8;
+                                /* special case: r15 = PC + 8 */
+                                val = (long)s->pc + 4;
                                 gen_op_movl_TN_im[0](val);
                             } else if (user) {
                                 gen_op_movl_T0_user(i);
@@ -1777,7 +2897,7 @@
         case 0xb:
             {
                 int32_t offset;
-                
+
                 /* branch (and link) */
                 val = (int32_t)s->pc;
                 if (insn & (1 << 24)) {
@@ -1794,14 +2914,32 @@
         case 0xe:
             /* Coprocessor.  */
             op1 = (insn >> 8) & 0xf;
+            if (arm_feature(env, ARM_FEATURE_XSCALE) &&
+                    ((env->cp15.c15_cpar ^ 0x3fff) & (1 << op1)))
+                goto illegal_op;
             switch (op1) {
+            case 0 ... 1:
+                if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+                    if (disas_iwmmxt_insn(env, s, insn))
+                        goto illegal_op;
+                } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+                    if (disas_dsp_insn(env, s, insn))
+                        goto illegal_op;
+                } else
+                    goto illegal_op;
+                break;
+            case 2 ... 9:
+            case 12 ... 14:
+                if (disas_cp_insn (env, s, insn))
+                    goto illegal_op;
+                break;
             case 10:
             case 11:
                 if (disas_vfp_insn (env, s, insn))
                     goto illegal_op;
                 break;
             case 15:
-                if (disas_cp15_insn (s, insn))
+                if (disas_cp15_insn (env, s, insn))
                     goto illegal_op;
                 break;
             default:
@@ -2362,7 +3500,7 @@
         val = (uint32_t)s->pc + 2;
         gen_op_movl_T1_im(val | 1);
         gen_movl_reg_T1(s, 14);
-        
+
         val += offset << 1;
         if (insn & (1 << 12)) {
             /* bl */
@@ -2385,8 +3523,8 @@
 /* generate intermediate code in gen_opc_buf and gen_opparam_buf for
    basic block 'tb'. If search_pc is TRUE, also generate PC
    information for each intermediate instruction. */
-static inline int gen_intermediate_code_internal(CPUState *env, 
-                                                 TranslationBlock *tb, 
+static inline int gen_intermediate_code_internal(CPUState *env,
+                                                 TranslationBlock *tb,
                                                  int search_pc)
 {
     DisasContext dc1, *dc = &dc1;
@@ -2394,10 +3532,10 @@
     int j, lj;
     target_ulong pc_start;
     uint32_t next_page_start;
-    
+
     /* generate intermediate code */
     pc_start = tb->pc;
-       
+
     dc->tb = tb;
 
     gen_opc_ptr = gen_opc_buf;
@@ -2409,6 +3547,7 @@
     dc->singlestep_enabled = env->singlestep_enabled;
     dc->condjmp = 0;
     dc->thumb = env->thumb;
+    dc->is_mem = 0;
 #if !defined(CONFIG_USER_ONLY)
     dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
 #endif
@@ -2447,6 +3586,12 @@
             gen_set_label(dc->condlabel);
             dc->condjmp = 0;
         }
+        /* Terminate the TB on memory ops if watchpoints are present.  */
+        /* FIXME: This should be replacd by the deterministic execution
+         * IRQ raising bits.  */
+        if (dc->is_mem && env->nb_watchpoints)
+            break;
+
         /* Translation stops when a conditional branch is enoutered.
          * Otherwise the subsequent code could get translated several times.
          * Also stop translation when a page boundary is reached.  This
@@ -2511,7 +3656,6 @@
         lj++;
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
-        tb->size = 0;
     } else {
         tb->size = dc->pc - pc_start;
     }
@@ -2532,7 +3676,7 @@
   "usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
   "???", "???", "???", "und", "???", "???", "???", "sys"
 };
-void cpu_dump_state(CPUState *env, FILE *f, 
+void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
 {
@@ -2558,13 +3702,13 @@
             cpu_fprintf(f, " ");
     }
     psr = cpsr_read(env);
-    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d %x\n", 
-                psr, 
+    cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d\n",
+                psr,
                 psr & (1 << 31) ? 'N' : '-',
                 psr & (1 << 30) ? 'Z' : '-',
                 psr & (1 << 29) ? 'C' : '-',
                 psr & (1 << 28) ? 'V' : '-',
-                psr & CPSR_T ? 'T' : 'A', 
+                psr & CPSR_T ? 'T' : 'A',
                 cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
 
     for (i = 0; i < 16; i++) {
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 7f44e9f..de2669e 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -1,6 +1,6 @@
 /*
  * i386 virtual CPU header
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -84,6 +84,7 @@
 #define DESC_AVL_MASK   (1 << 20)
 #define DESC_P_MASK     (1 << 15)
 #define DESC_DPL_SHIFT  13
+#define DESC_DPL_MASK   (1 << DESC_DPL_SHIFT)
 #define DESC_S_MASK     (1 << 12)
 #define DESC_TYPE_SHIFT 8
 #define DESC_A_MASK     (1 << 8)
@@ -116,12 +117,12 @@
 #define NT_MASK	         	0x00004000
 #define RF_MASK			0x00010000
 #define VM_MASK			0x00020000
-#define AC_MASK			0x00040000 
+#define AC_MASK			0x00040000
 #define VIF_MASK                0x00080000
 #define VIP_MASK                0x00100000
 #define ID_MASK                 0x00200000
 
-/* hidden flags - used internally by qemu to represent additionnal cpu
+/* hidden flags - used internally by qemu to represent additional cpu
    states. Only the CPL, INHIBIT_IRQ and HALTED are not redundant. We avoid
    using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring
    with eflags. */
@@ -149,6 +150,8 @@
 #define HF_VM_SHIFT         17 /* must be same as eflags */
 #define HF_HALTED_SHIFT     18 /* CPU halted */
 #define HF_SMM_SHIFT        19 /* CPU in SMM mode */
+#define HF_GIF_SHIFT        20 /* if set CPU takes interrupts */
+#define HF_HIF_SHIFT        21 /* shadow copy of IF_MASK when in SVM */
 
 #define HF_CPL_MASK          (3 << HF_CPL_SHIFT)
 #define HF_SOFTMMU_MASK      (1 << HF_SOFTMMU_SHIFT)
@@ -168,6 +171,8 @@
 #define HF_VM_MASK           (1 << HF_VM_SHIFT)
 #define HF_HALTED_MASK       (1 << HF_HALTED_SHIFT)
 #define HF_SMM_MASK          (1 << HF_SMM_SHIFT)
+#define HF_GIF_MASK          (1 << HF_GIF_SHIFT)
+#define HF_HIF_MASK          (1 << HF_HIF_SHIFT)
 
 #define CR0_PE_SHIFT 0
 #define CR0_MP_SHIFT 1
@@ -255,6 +260,8 @@
 #define MSR_GSBASE                      0xc0000101
 #define MSR_KERNELGSBASE                0xc0000102
 
+#define MSR_VM_HSAVE_PA                 0xc0010117
+
 /* cpuid_features bits */
 #define CPUID_FP87 (1 << 0)
 #define CPUID_VME  (1 << 1)
@@ -289,6 +296,8 @@
 #define CPUID_EXT2_FFXSR   (1 << 25)
 #define CPUID_EXT2_LM      (1 << 29)
 
+#define CPUID_EXT3_SVM     (1 << 2)
+
 #define EXCP00_DIVZ	0
 #define EXCP01_SSTP	1
 #define EXCP02_NMI	2
@@ -482,7 +491,7 @@
 	int i32;
         int64_t i64;
     } fp_convert;
-    
+
     float_status sse_status;
     uint32_t mxcsr;
     XMMReg xmm_regs[CPU_NB_REGS];
@@ -495,6 +504,16 @@
     uint32_t sysenter_eip;
     uint64_t efer;
     uint64_t star;
+
+    target_phys_addr_t vm_hsave;
+    target_phys_addr_t vm_vmcb;
+    uint64_t intercept;
+    uint16_t intercept_cr_read;
+    uint16_t intercept_cr_write;
+    uint16_t intercept_dr_read;
+    uint16_t intercept_dr_write;
+    uint32_t intercept_exceptions;
+
 #ifdef TARGET_X86_64
     target_ulong lstar;
     target_ulong cstar;
@@ -514,7 +533,7 @@
     uint32_t saved_esp;
     int native_fp_regs; /* if true, the FPU state is in the native CPU regs */
 #endif
-    
+
     /* exception/interrupt handling */
     jmp_buf jmp_env;
     int exception_index;
@@ -523,8 +542,9 @@
     target_ulong exception_next_eip;
     target_ulong dr[8]; /* debug registers */
     uint32_t smbase;
-    int interrupt_request; 
+    int interrupt_request;
     int user_mode_only; /* user mode only simulation */
+    int old_exception;  /* exception in flight */
 
     CPU_COMMON
 
@@ -539,7 +559,9 @@
     uint32_t cpuid_xlevel;
     uint32_t cpuid_model[12];
     uint32_t cpuid_ext2_features;
-    
+    uint32_t cpuid_ext3_features;
+    uint32_t cpuid_apic_id;
+
 #ifdef USE_KQEMU
     int kqemu_enabled;
     int last_io_time;
@@ -565,15 +587,15 @@
 
 /* this function must always be used to load data in the segment
    cache: it synchronizes the hflags with the segment cache values */
-static inline void cpu_x86_load_seg_cache(CPUX86State *env, 
+static inline void cpu_x86_load_seg_cache(CPUX86State *env,
                                           int seg_reg, unsigned int selector,
                                           target_ulong base,
-                                          unsigned int limit, 
+                                          unsigned int limit,
                                           unsigned int flags)
 {
     SegmentCache *sc;
     unsigned int new_hflags;
-    
+
     sc = &env->segs[seg_reg];
     sc->selector = selector;
     sc->base = base;
@@ -588,7 +610,7 @@
                 /* long mode */
                 env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
                 env->hflags &= ~(HF_ADDSEG_MASK);
-            } else 
+            } else
 #endif
             {
                 /* legacy / compatibility case */
@@ -602,7 +624,7 @@
             >> (DESC_B_SHIFT - HF_SS32_SHIFT);
         if (env->hflags & HF_CS64_MASK) {
             /* zero base assumed for DS, ES and SS in long mode */
-        } else if (!(env->cr[0] & CR0_PE_MASK) || 
+        } else if (!(env->cr[0] & CR0_PE_MASK) ||
                    (env->eflags & VM_MASK) ||
                    !(env->hflags & HF_CS32_MASK)) {
             /* XXX: try to avoid this test. The problem comes from the
@@ -612,12 +634,12 @@
                translate-i386.c. */
             new_hflags |= HF_ADDSEG_MASK;
         } else {
-            new_hflags |= ((env->segs[R_DS].base | 
+            new_hflags |= ((env->segs[R_DS].base |
                             env->segs[R_ES].base |
-                            env->segs[R_SS].base) != 0) << 
+                            env->segs[R_SS].base) != 0) <<
                 HF_ADDSEG_SHIFT;
         }
-        env->hflags = (env->hflags & 
+        env->hflags = (env->hflags &
                        ~(HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags;
     }
 }
@@ -645,7 +667,7 @@
 /* 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.  */
-int cpu_x86_signal_handler(int host_signum, void *pinfo, 
+int cpu_x86_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 void cpu_x86_set_a20(CPUX86State *env, int a20_state);
 
@@ -676,6 +698,15 @@
 #endif
 
 #define TARGET_PAGE_BITS 12
+
+#define CPUState CPUX86State
+#define cpu_init cpu_x86_init
+#define cpu_exec cpu_x86_exec
+#define cpu_gen_code cpu_x86_gen_code
+#define cpu_signal_handler cpu_x86_signal_handler
+
 #include "cpu-all.h"
 
+#include "svm.h"
+
 #endif /* CPU_I386_H */
diff --git a/target-i386/exec.h b/target-i386/exec.h
index 377f7bd..1cb7346 100644
--- a/target-i386/exec.h
+++ b/target-i386/exec.h
@@ -1,5 +1,5 @@
 /*
- *  i386 execution defines 
+ *  i386 execution defines
  *
  *  Copyright (c) 2003 Fabrice Bellard
  *
@@ -162,17 +162,17 @@
 void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3);
 void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4);
 void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr);
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, 
+int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
                              int is_write, int is_user, int is_softmmu);
-void tlb_fill(target_ulong addr, int is_write, int is_user, 
+void tlb_fill(target_ulong addr, int is_write, int is_user,
               void *retaddr);
 void __hidden cpu_lock(void);
 void __hidden cpu_unlock(void);
-void do_interrupt(int intno, int is_int, int error_code, 
+void do_interrupt(int intno, int is_int, int error_code,
                   target_ulong next_eip, int is_hw);
-void do_interrupt_user(int intno, int is_int, int error_code, 
+void do_interrupt_user(int intno, int is_int, int error_code,
                        target_ulong next_eip);
-void raise_interrupt(int intno, int is_int, int error_code, 
+void raise_interrupt(int intno, int is_int, int error_code,
                      int next_eip_addend);
 void raise_exception_err(int exception_index, int error_code);
 void raise_exception(int exception_index);
@@ -190,6 +190,7 @@
 void helper_idivq_EAX_T0(void);
 void helper_bswapq_T0(void);
 void helper_cmpxchg8b(void);
+void helper_single_step(void);
 void helper_cpuid(void);
 void helper_enter_level(int level, int data32);
 void helper_enter64_level(int level, int data64);
@@ -442,7 +443,7 @@
 static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr)
 {
     CPU86_LDoubleU temp;
-    
+
     temp.d = f;
     stq(ptr, temp.l.lower);
     stw(ptr + 8, temp.l.upper);
@@ -501,6 +502,15 @@
 void helper_hlt(void);
 void helper_monitor(void);
 void helper_mwait(void);
+void helper_vmrun(target_ulong addr);
+void helper_vmmcall(void);
+void helper_vmload(target_ulong addr);
+void helper_vmsave(target_ulong addr);
+void helper_stgi(void);
+void helper_clgi(void);
+void helper_skinit(void);
+void helper_invlpga(void);
+void vmexit(uint64_t exit_code, uint64_t exit_info_1);
 
 extern const uint8_t parity_table[256];
 extern const uint8_t rclw_table[32];
@@ -516,7 +526,7 @@
 {
     CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
     DF = 1 - (2 * ((eflags >> 10) & 1));
-    env->eflags = (env->eflags & ~update_mask) | 
+    env->eflags = (env->eflags & ~update_mask) |
         (eflags & update_mask);
 }
 
@@ -575,3 +585,17 @@
     env->regs[R_EDI] = EDI;
 #endif
 }
+
+static inline int cpu_halted(CPUState *env) {
+    /* handle exit of HALTED state */
+    if (!(env->hflags & HF_HALTED_MASK))
+        return 0;
+    /* disable halt condition */
+    if ((env->interrupt_request & CPU_INTERRUPT_HARD) &&
+        (env->eflags & IF_MASK)) {
+        env->hflags &= ~HF_HALTED_MASK;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 9f8b2e1..154708e 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1,6 +1,6 @@
 /*
  *  i386 helpers
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -66,7 +66,7 @@
 
 /* modulo 17 table */
 const uint8_t rclw_table[32] = {
-    0, 1, 2, 3, 4, 5, 6, 7, 
+    0, 1, 2, 3, 4, 5, 6, 7,
     8, 9,10,11,12,13,14,15,
    16, 0, 1, 2, 3, 4, 5, 6,
     7, 8, 9,10,11,12,13,14,
@@ -74,9 +74,9 @@
 
 /* modulo 9 table */
 const uint8_t rclb_table[32] = {
-    0, 1, 2, 3, 4, 5, 6, 7, 
+    0, 1, 2, 3, 4, 5, 6, 7,
     8, 0, 1, 2, 3, 4, 5, 6,
-    7, 8, 0, 1, 2, 3, 4, 5, 
+    7, 8, 0, 1, 2, 3, 4, 5,
     6, 7, 8, 0, 1, 2, 3, 4,
 };
 
@@ -90,7 +90,7 @@
     1.44269504088896340739L,  /*l2e*/
     3.32192809488736234781L,  /*l2t*/
 };
-    
+
 /* thread support */
 
 spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
@@ -105,14 +105,6 @@
     spin_unlock(&global_cpu_lock);
 }
 
-void cpu_loop_exit(void)
-{
-    /* NOTE: the register at this point must be saved by hand because
-       longjmp restore them */
-    regs_to_env();
-    longjmp(env->jmp_env, 1);
-}
-
 /* return non zero if error */
 static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
                                int selector)
@@ -133,7 +125,7 @@
     *e2_ptr = ldl_kernel(ptr + 4);
     return 0;
 }
-                                     
+
 static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
 {
     unsigned int limit;
@@ -159,15 +151,15 @@
 static inline void load_seg_vm(int seg, int selector)
 {
     selector &= 0xffff;
-    cpu_x86_load_seg_cache(env, seg, selector, 
+    cpu_x86_load_seg_cache(env, seg, selector,
                            (selector << 4), 0xffff, 0);
 }
 
-static inline void get_ss_esp_from_tss(uint32_t *ss_ptr, 
+static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
                                        uint32_t *esp_ptr, int dpl)
 {
     int type, index, shift;
-    
+
 #if 0
     {
         int i;
@@ -238,12 +230,12 @@
         }
         if (!(e2 & DESC_P_MASK))
             raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
-        cpu_x86_load_seg_cache(env, seg_reg, selector, 
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
                        get_seg_base(e1, e2),
                        get_seg_limit(e1, e2),
                        e2);
     } else {
-        if (seg_reg == R_SS || seg_reg == R_CS) 
+        if (seg_reg == R_SS || seg_reg == R_CS)
             raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
     }
 }
@@ -253,7 +245,7 @@
 #define SWITCH_TSS_CALL 2
 
 /* XXX: restore CPU state in registers (PowerPC case) */
-static void switch_tss(int tss_selector, 
+static void switch_tss(int tss_selector,
                        uint32_t e1, uint32_t e2, int source,
                        uint32_t next_eip)
 {
@@ -297,7 +289,7 @@
         tss_limit_max = 43;
     tss_limit = get_seg_limit(e1, e2);
     tss_base = get_seg_base(e1, e2);
-    if ((tss_selector & 4) != 0 || 
+    if ((tss_selector & 4) != 0 ||
         tss_limit < tss_limit_max)
         raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
     old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
@@ -332,7 +324,7 @@
         new_segs[R_GS] = 0;
         new_trap = 0;
     }
-    
+
     /* NOTE: we must avoid memory exceptions during the task switch,
        so we make dummy accesses before */
     /* XXX: it can still fail in some cases, so a bigger hack is
@@ -342,7 +334,7 @@
     v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
     stb_kernel(env->tr.base, v1);
     stb_kernel(env->tr.base + old_tss_limit_max, v2);
-    
+
     /* clear busy bit (it is restartable) */
     if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
         target_ulong ptr;
@@ -355,7 +347,7 @@
     old_eflags = compute_eflags();
     if (source == SWITCH_TSS_IRET)
         old_eflags &= ~NT_MASK;
-    
+
     /* save the current state in the old TSS */
     if (type & 8) {
         /* 32 bit */
@@ -386,7 +378,7 @@
         for(i = 0; i < 4; i++)
             stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
     }
-    
+
     /* now if an exception occurs, it will occurs in the next task
        context */
 
@@ -413,15 +405,15 @@
     env->tr.base = tss_base;
     env->tr.limit = tss_limit;
     env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
-    
+
     if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
         cpu_x86_update_cr3(env, new_cr3);
     }
-    
+
     /* load all registers without an exception, then reload them with
        possible exception */
     env->eip = new_eip;
-    eflags_mask = TF_MASK | AC_MASK | ID_MASK | 
+    eflags_mask = TF_MASK | AC_MASK | ID_MASK |
         IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
     if (!(type & 8))
         eflags_mask &= 0xffff;
@@ -436,7 +428,7 @@
     ESI = new_regs[6];
     EDI = new_regs[7];
     if (new_eflags & VM_MASK) {
-        for(i = 0; i < 6; i++) 
+        for(i = 0; i < 6; i++)
             load_seg_vm(i, new_segs[i]);
         /* in vm86, CPL is always 3 */
         cpu_x86_set_cpl(env, 3);
@@ -447,7 +439,7 @@
         for(i = 0; i < 6; i++)
             cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
     }
-    
+
     env->ldt.selector = new_ldt & ~4;
     env->ldt.base = 0;
     env->ldt.limit = 0;
@@ -471,7 +463,7 @@
             raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
         load_seg_cache_raw_dt(&env->ldt, e1, e2);
     }
-    
+
     /* load the segments */
     if (!(new_eflags & VM_MASK)) {
         tss_load_seg(R_CS, new_segs[R_CS]);
@@ -481,7 +473,7 @@
         tss_load_seg(R_FS, new_segs[R_FS]);
         tss_load_seg(R_GS, new_segs[R_GS]);
     }
-    
+
     /* check that EIP is in the CS segment limits */
     if (new_eip > env->segs[R_CS].limit) {
         /* XXX: different exception if CALL ? */
@@ -493,7 +485,7 @@
 static inline void check_io(int addr, int size)
 {
     int io_offset, val, mask;
-    
+
     /* TSS must be a valid 32 bit one */
     if (!(env->tr.flags & DESC_P_MASK) ||
         ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
@@ -601,7 +593,18 @@
     int has_error_code, new_stack, shift;
     uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
     uint32_t old_eip, sp_mask;
+    int svm_should_check = 1;
 
+    if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) {
+        next_eip = EIP;
+        svm_should_check = 0;
+    }
+
+    if (svm_should_check
+        && (INTERCEPTEDl(_exceptions, 1 << intno)
+        && !is_int)) {
+        raise_interrupt(intno, is_int, error_code, 0);
+    }
     has_error_code = 0;
     if (!is_int && !is_hw) {
         switch(intno) {
@@ -686,7 +689,7 @@
     if (!(e2 & DESC_P_MASK))
         raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
     if (!(e2 & DESC_C_MASK) && dpl < cpl) {
-        /* to inner priviledge */
+        /* to inner privilege */
         get_ss_esp_from_tss(&ss, &esp, dpl);
         if ((ss & 0xfffc) == 0)
             raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
@@ -707,7 +710,7 @@
         sp_mask = get_sp_mask(ss_e2);
         ssp = get_seg_base(ss_e1, ss_e2);
     } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
-        /* to same priviledge */
+        /* to same privilege */
         if (env->eflags & VM_MASK)
             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
         new_stack = 0;
@@ -767,7 +770,7 @@
             PUSHW(ssp, esp, sp_mask, error_code);
         }
     }
-    
+
     if (new_stack) {
         if (env->eflags & VM_MASK) {
             cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
@@ -776,13 +779,13 @@
             cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
         }
         ss = (ss & ~3) | dpl;
-        cpu_x86_load_seg_cache(env, R_SS, ss, 
+        cpu_x86_load_seg_cache(env, R_SS, ss,
                                ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
     }
     SET_ESP(esp, sp_mask);
 
     selector = (selector & ~3) | dpl;
-    cpu_x86_load_seg_cache(env, R_CS, selector, 
+    cpu_x86_load_seg_cache(env, R_CS, selector,
                    get_seg_base(e1, e2),
                    get_seg_limit(e1, e2),
                    e2);
@@ -813,9 +816,9 @@
 static inline target_ulong get_rsp_from_tss(int level)
 {
     int index;
-    
+
 #if 0
-    printf("TR: base=" TARGET_FMT_lx " limit=%x\n", 
+    printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
            env->tr.base, env->tr.limit);
 #endif
 
@@ -837,7 +840,17 @@
     int has_error_code, new_stack;
     uint32_t e1, e2, e3, ss;
     target_ulong old_eip, esp, offset;
+    int svm_should_check = 1;
 
+    if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) {
+        next_eip = EIP;
+        svm_should_check = 0;
+    }
+    if (svm_should_check
+        && INTERCEPTEDl(_exceptions, 1 << intno)
+        && !is_int) {
+        raise_interrupt(intno, is_int, error_code, 0);
+    }
     has_error_code = 0;
     if (!is_int && !is_hw) {
         switch(intno) {
@@ -900,7 +913,7 @@
     if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
         raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
     if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
-        /* to inner priviledge */
+        /* to inner privilege */
         if (ist != 0)
             esp = get_rsp_from_tss(ist + 3);
         else
@@ -909,7 +922,7 @@
         ss = 0;
         new_stack = 1;
     } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
-        /* to same priviledge */
+        /* to same privilege */
         if (env->eflags & VM_MASK)
             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
         new_stack = 0;
@@ -933,7 +946,7 @@
     if (has_error_code) {
         PUSHQ(esp, error_code);
     }
-    
+
     if (new_stack) {
         ss = 0 | dpl;
         cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
@@ -941,7 +954,7 @@
     ESP = esp;
 
     selector = (selector & ~3) | dpl;
-    cpu_x86_load_seg_cache(env, R_CS, selector, 
+    cpu_x86_load_seg_cache(env, R_CS, selector,
                    get_seg_base(e1, e2),
                    get_seg_limit(e1, e2),
                    e2);
@@ -970,16 +983,16 @@
 
         ECX = env->eip + next_eip_addend;
         env->regs[11] = compute_eflags();
-        
+
         code64 = env->hflags & HF_CS64_MASK;
 
         cpu_x86_set_cpl(env, 0);
-        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
-                           0, 0xffffffff, 
+        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+                           0, 0xffffffff,
                                DESC_G_MASK | DESC_P_MASK |
                                DESC_S_MASK |
                                DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
-        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK |
@@ -989,18 +1002,18 @@
             env->eip = env->lstar;
         else
             env->eip = env->cstar;
-    } else 
+    } else
 #endif
     {
         ECX = (uint32_t)(env->eip + next_eip_addend);
-        
+
         cpu_x86_set_cpl(env, 0);
-        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc, 
-                           0, 0xffffffff, 
+        cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
+                           0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK |
                                DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
-        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc, 
+        cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK |
@@ -1025,39 +1038,39 @@
 #ifdef TARGET_X86_64
     if (env->hflags & HF_LMA_MASK) {
         if (dflag == 2) {
-            cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3, 
-                                   0, 0xffffffff, 
+            cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
+                                   0, 0xffffffff,
                                    DESC_G_MASK | DESC_P_MASK |
                                    DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
-                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | 
+                                   DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
                                    DESC_L_MASK);
             env->eip = ECX;
         } else {
-            cpu_x86_load_seg_cache(env, R_CS, selector | 3, 
-                                   0, 0xffffffff, 
+            cpu_x86_load_seg_cache(env, R_CS, selector | 3,
+                                   0, 0xffffffff,
                                    DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                    DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
                                    DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
             env->eip = (uint32_t)ECX;
         }
-        cpu_x86_load_seg_cache(env, R_SS, selector + 8, 
+        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
                                DESC_W_MASK | DESC_A_MASK);
-        load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK | 
+        load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
                     IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
         cpu_x86_set_cpl(env, 3);
-    } else 
+    } else
 #endif
     {
-        cpu_x86_load_seg_cache(env, R_CS, selector | 3, 
-                               0, 0xffffffff, 
+        cpu_x86_load_seg_cache(env, R_CS, selector | 3,
+                               0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
                                DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
         env->eip = (uint32_t)ECX;
-        cpu_x86_load_seg_cache(env, R_SS, selector + 8, 
+        cpu_x86_load_seg_cache(env, R_SS, selector + 8,
                                0, 0xffffffff,
                                DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
@@ -1084,7 +1097,17 @@
     int selector;
     uint32_t offset, esp;
     uint32_t old_cs, old_eip;
+    int svm_should_check = 1;
 
+    if ((env->intercept & INTERCEPT_SVM_MASK) && !is_int && next_eip==-1) {
+        next_eip = EIP;
+        svm_should_check = 0;
+    }
+    if (svm_should_check
+        && INTERCEPTEDl(_exceptions, 1 << intno)
+        && !is_int) {
+        raise_interrupt(intno, is_int, error_code, 0);
+    }
     /* real mode (simpler !) */
     dt = &env->idt;
     if (intno * 4 + 3 > dt->limit)
@@ -1103,7 +1126,7 @@
     PUSHW(ssp, esp, 0xffff, compute_eflags());
     PUSHW(ssp, esp, 0xffff, old_cs);
     PUSHW(ssp, esp, 0xffff, old_eip);
-    
+
     /* update processor state */
     ESP = (ESP & ~0xffff) | (esp & 0xffff);
     env->eip = offset;
@@ -1113,7 +1136,7 @@
 }
 
 /* fake user mode interrupt */
-void do_interrupt_user(int intno, int is_int, int error_code, 
+void do_interrupt_user(int intno, int is_int, int error_code,
                        target_ulong next_eip)
 {
     SegmentCache *dt;
@@ -1124,7 +1147,7 @@
     dt = &env->idt;
     ptr = dt->base + (intno * 8);
     e2 = ldl_kernel(ptr + 4);
-    
+
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
     cpl = env->hflags & HF_CPL_MASK;
     /* check privledge if software int */
@@ -1141,9 +1164,9 @@
 /*
  * Begin execution of an interruption. is_int is TRUE if coming from
  * the int instruction. next_eip is the EIP value AFTER the interrupt
- * instruction. It is only relevant if is_int is TRUE.  
+ * instruction. It is only relevant if is_int is TRUE.
  */
-void do_interrupt(int intno, int is_int, int error_code, 
+void do_interrupt(int intno, int is_int, int error_code,
                   target_ulong next_eip, int is_hw)
 {
     if (loglevel & CPU_LOG_INT) {
@@ -1192,14 +1215,53 @@
 }
 
 /*
+ * Check nested exceptions and change to double or triple fault if
+ * needed. It should only be called, if this is not an interrupt.
+ * Returns the new exception number.
+ */
+int check_exception(int intno, int *error_code)
+{
+    char first_contributory = env->old_exception == 0 ||
+                              (env->old_exception >= 10 &&
+                               env->old_exception <= 13);
+    char second_contributory = intno == 0 ||
+                               (intno >= 10 && intno <= 13);
+
+    if (loglevel & CPU_LOG_INT)
+        fprintf(logfile, "check_exception old: %x new %x\n",
+                env->old_exception, intno);
+
+    if (env->old_exception == EXCP08_DBLE)
+        cpu_abort(env, "triple fault");
+
+    if ((first_contributory && second_contributory)
+        || (env->old_exception == EXCP0E_PAGE &&
+            (second_contributory || (intno == EXCP0E_PAGE)))) {
+        intno = EXCP08_DBLE;
+        *error_code = 0;
+    }
+
+    if (second_contributory || (intno == EXCP0E_PAGE) ||
+        (intno == EXCP08_DBLE))
+        env->old_exception = intno;
+
+    return intno;
+}
+
+/*
  * Signal an interruption. It is executed in the main CPU loop.
  * is_int is TRUE if coming from the int instruction. next_eip is the
  * EIP value AFTER the interrupt instruction. It is only relevant if
- * is_int is TRUE.  
+ * is_int is TRUE.
  */
-void raise_interrupt(int intno, int is_int, int error_code, 
+void raise_interrupt(int intno, int is_int, int error_code,
                      int next_eip_addend)
 {
+    if (!is_int) {
+        svm_check_intercept_param(SVM_EXIT_EXCP_BASE + intno, error_code);
+        intno = check_exception(intno, &error_code);
+    }
+
     env->exception_index = intno;
     env->error_code = error_code;
     env->exception_is_int = is_int;
@@ -1210,6 +1272,8 @@
 /* same as raise_exception_err, but do not restore global registers */
 static void raise_exception_err_norestore(int exception_index, int error_code)
 {
+    exception_index = check_exception(exception_index, &error_code);
+
     env->exception_index = exception_index;
     env->error_code = error_code;
     env->exception_is_int = 0;
@@ -1231,7 +1295,7 @@
 
 /* SMM support */
 
-#if defined(CONFIG_USER_ONLY) 
+#if defined(CONFIG_USER_ONLY)
 
 void do_smm_enter(void)
 {
@@ -1264,7 +1328,7 @@
     cpu_smm_update(env);
 
     sm_state = env->smbase + 0x8000;
-    
+
 #ifdef TARGET_X86_64
     for(i = 0; i < 6; i++) {
         dt = &env->segs[i];
@@ -1282,7 +1346,7 @@
     stq_phys(sm_state + 0x7e78, env->ldt.base);
     stl_phys(sm_state + 0x7e74, env->ldt.limit);
     stw_phys(sm_state + 0x7e72, (env->ldt.flags >> 8) & 0xf0ff);
-    
+
     stq_phys(sm_state + 0x7e88, env->idt.base);
     stl_phys(sm_state + 0x7e84, env->idt.limit);
 
@@ -1290,7 +1354,7 @@
     stq_phys(sm_state + 0x7e98, env->tr.base);
     stl_phys(sm_state + 0x7e94, env->tr.limit);
     stw_phys(sm_state + 0x7e92, (env->tr.flags >> 8) & 0xf0ff);
-    
+
     stq_phys(sm_state + 0x7ed0, env->efer);
 
     stq_phys(sm_state + 0x7ff8, EAX);
@@ -1301,7 +1365,7 @@
     stq_phys(sm_state + 0x7fd0, EBP);
     stq_phys(sm_state + 0x7fc8, ESI);
     stq_phys(sm_state + 0x7fc0, EDI);
-    for(i = 8; i < 16; i++) 
+    for(i = 8; i < 16; i++)
         stq_phys(sm_state + 0x7ff8 - i * 8, env->regs[i]);
     stq_phys(sm_state + 0x7f78, env->eip);
     stl_phys(sm_state + 0x7f70, compute_eflags());
@@ -1329,17 +1393,17 @@
     stl_phys(sm_state + 0x7fd0, EAX);
     stl_phys(sm_state + 0x7fcc, env->dr[6]);
     stl_phys(sm_state + 0x7fc8, env->dr[7]);
-    
+
     stl_phys(sm_state + 0x7fc4, env->tr.selector);
     stl_phys(sm_state + 0x7f64, env->tr.base);
     stl_phys(sm_state + 0x7f60, env->tr.limit);
     stl_phys(sm_state + 0x7f5c, (env->tr.flags >> 8) & 0xf0ff);
-    
+
     stl_phys(sm_state + 0x7fc0, env->ldt.selector);
     stl_phys(sm_state + 0x7f80, env->ldt.base);
     stl_phys(sm_state + 0x7f7c, env->ldt.limit);
     stl_phys(sm_state + 0x7f78, (env->ldt.flags >> 8) & 0xf0ff);
-    
+
     stl_phys(sm_state + 0x7f74, env->gdt.base);
     stl_phys(sm_state + 0x7f70, env->gdt.limit);
 
@@ -1377,8 +1441,8 @@
     cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffffffff, 0);
     cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffffffff, 0);
     cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffffffff, 0);
-    
-    cpu_x86_update_cr0(env, 
+
+    cpu_x86_update_cr0(env,
                        env->cr[0] & ~(CR0_PE_MASK | CR0_EM_MASK | CR0_TS_MASK | CR0_PG_MASK));
     cpu_x86_update_cr4(env, 0);
     env->dr[7] = 0x00000400;
@@ -1401,7 +1465,7 @@
 
     for(i = 0; i < 6; i++) {
         offset = 0x7e00 + i * 16;
-        cpu_x86_load_seg_cache(env, i, 
+        cpu_x86_load_seg_cache(env, i,
                                lduw_phys(sm_state + offset),
                                ldq_phys(sm_state + offset + 8),
                                ldl_phys(sm_state + offset + 4),
@@ -1415,7 +1479,7 @@
     env->ldt.base = ldq_phys(sm_state + 0x7e78);
     env->ldt.limit = ldl_phys(sm_state + 0x7e74);
     env->ldt.flags = (lduw_phys(sm_state + 0x7e72) & 0xf0ff) << 8;
-    
+
     env->idt.base = ldq_phys(sm_state + 0x7e88);
     env->idt.limit = ldl_phys(sm_state + 0x7e84);
 
@@ -1423,7 +1487,7 @@
     env->tr.base = ldq_phys(sm_state + 0x7e98);
     env->tr.limit = ldl_phys(sm_state + 0x7e94);
     env->tr.flags = (lduw_phys(sm_state + 0x7e92) & 0xf0ff) << 8;
-    
+
     EAX = ldq_phys(sm_state + 0x7ff8);
     ECX = ldq_phys(sm_state + 0x7ff0);
     EDX = ldq_phys(sm_state + 0x7fe8);
@@ -1432,10 +1496,10 @@
     EBP = ldq_phys(sm_state + 0x7fd0);
     ESI = ldq_phys(sm_state + 0x7fc8);
     EDI = ldq_phys(sm_state + 0x7fc0);
-    for(i = 8; i < 16; i++) 
+    for(i = 8; i < 16; i++)
         env->regs[i] = ldq_phys(sm_state + 0x7ff8 - i * 8);
     env->eip = ldq_phys(sm_state + 0x7f78);
-    load_eflags(ldl_phys(sm_state + 0x7f70), 
+    load_eflags(ldl_phys(sm_state + 0x7f70),
                 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
     env->dr[6] = ldl_phys(sm_state + 0x7f68);
     env->dr[7] = ldl_phys(sm_state + 0x7f60);
@@ -1451,7 +1515,7 @@
 #else
     cpu_x86_update_cr0(env, ldl_phys(sm_state + 0x7ffc));
     cpu_x86_update_cr3(env, ldl_phys(sm_state + 0x7ff8));
-    load_eflags(ldl_phys(sm_state + 0x7ff4), 
+    load_eflags(ldl_phys(sm_state + 0x7ff4),
                 ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
     env->eip = ldl_phys(sm_state + 0x7ff0);
     EDI = ldl_phys(sm_state + 0x7fec);
@@ -1464,17 +1528,17 @@
     EAX = ldl_phys(sm_state + 0x7fd0);
     env->dr[6] = ldl_phys(sm_state + 0x7fcc);
     env->dr[7] = ldl_phys(sm_state + 0x7fc8);
-    
+
     env->tr.selector = ldl_phys(sm_state + 0x7fc4) & 0xffff;
     env->tr.base = ldl_phys(sm_state + 0x7f64);
     env->tr.limit = ldl_phys(sm_state + 0x7f60);
     env->tr.flags = (ldl_phys(sm_state + 0x7f5c) & 0xf0ff) << 8;
-    
+
     env->ldt.selector = ldl_phys(sm_state + 0x7fc0) & 0xffff;
     env->ldt.base = ldl_phys(sm_state + 0x7f80);
     env->ldt.limit = ldl_phys(sm_state + 0x7f7c);
     env->ldt.flags = (ldl_phys(sm_state + 0x7f78) & 0xf0ff) << 8;
-    
+
     env->gdt.base = ldl_phys(sm_state + 0x7f74);
     env->gdt.limit = ldl_phys(sm_state + 0x7f70);
 
@@ -1486,7 +1550,7 @@
             offset = 0x7f84 + i * 12;
         else
             offset = 0x7f2c + (i - 3) * 12;
-        cpu_x86_load_seg_cache(env, i, 
+        cpu_x86_load_seg_cache(env, i,
                                ldl_phys(sm_state + 0x7fa8 + i * 4) & 0xffff,
                                ldl_phys(sm_state + offset + 8),
                                ldl_phys(sm_state + offset + 4),
@@ -1532,7 +1596,7 @@
 {
     unsigned int den, r;
     uint64_t num, q;
-    
+
     num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
     den = T0;
     if (den == 0) {
@@ -1554,7 +1618,7 @@
 {
     int den, r;
     int64_t num, q;
-    
+
     num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
     den = T0;
     if (den == 0) {
@@ -1590,20 +1654,26 @@
     CC_SRC = eflags;
 }
 
+void helper_single_step()
+{
+    env->dr[6] |= 0x4000;
+    raise_exception(EXCP01_SSTP);
+}
+
 void helper_cpuid(void)
 {
     uint32_t index;
     index = (uint32_t)EAX;
-    
+
     /* test if maximum index reached */
     if (index & 0x80000000) {
-        if (index > env->cpuid_xlevel) 
+        if (index > env->cpuid_xlevel)
             index = env->cpuid_level;
     } else {
-        if (index > env->cpuid_level) 
+        if (index > env->cpuid_level)
             index = env->cpuid_level;
     }
-        
+
     switch(index) {
     case 0:
         EAX = env->cpuid_level;
@@ -1613,16 +1683,16 @@
         break;
     case 1:
         EAX = env->cpuid_version;
-        EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
+        EBX = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
         ECX = env->cpuid_ext_features;
         EDX = env->cpuid_features;
         break;
     case 2:
         /* cache info: needed for Pentium Pro compatibility */
-        EAX = 0x410601;
+        EAX = 1;
         EBX = 0;
         ECX = 0;
-        EDX = 0;
+        EDX = 0x2c307d;
         break;
     case 0x80000000:
         EAX = env->cpuid_xlevel;
@@ -1633,7 +1703,7 @@
     case 0x80000001:
         EAX = env->cpuid_features;
         EBX = 0;
-        ECX = 0;
+        ECX = env->cpuid_ext3_features;
         EDX = env->cpuid_ext2_features;
         break;
     case 0x80000002:
@@ -1745,7 +1815,7 @@
     uint32_t e1, e2;
     int index, entry_limit;
     target_ulong ptr;
-    
+
     selector = T0 & 0xffff;
     if ((selector & 0xfffc) == 0) {
         /* XXX: NULL selector case: invalid LDT */
@@ -1760,7 +1830,7 @@
         if (env->hflags & HF_LMA_MASK)
             entry_limit = 15;
         else
-#endif            
+#endif
             entry_limit = 7;
         if ((index + entry_limit) > dt->limit)
             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
@@ -1793,7 +1863,7 @@
     uint32_t e1, e2;
     int index, type, entry_limit;
     target_ulong ptr;
-    
+
     selector = T0 & 0xffff;
     if ((selector & 0xfffc) == 0) {
         /* NULL selector case: invalid TR */
@@ -1809,7 +1879,7 @@
         if (env->hflags & HF_LMA_MASK)
             entry_limit = 15;
         else
-#endif            
+#endif
             entry_limit = 7;
         if ((index + entry_limit) > dt->limit)
             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
@@ -1817,18 +1887,21 @@
         e1 = ldl_kernel(ptr);
         e2 = ldl_kernel(ptr + 4);
         type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
-        if ((e2 & DESC_S_MASK) || 
+        if ((e2 & DESC_S_MASK) ||
             (type != 1 && type != 9))
             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
         if (!(e2 & DESC_P_MASK))
             raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
 #ifdef TARGET_X86_64
         if (env->hflags & HF_LMA_MASK) {
-            uint32_t e3;
+            uint32_t e3, e4;
             e3 = ldl_kernel(ptr + 8);
+            e4 = ldl_kernel(ptr + 12);
+            if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
+                raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
             load_seg_cache_raw_dt(&env->tr, e1, e2);
             env->tr.base |= (target_ulong)e3 << 32;
-        } else 
+        } else
 #endif
         {
             load_seg_cache_raw_dt(&env->tr, e1, e2);
@@ -1860,7 +1933,7 @@
             raise_exception_err(EXCP0D_GPF, 0);
         cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
     } else {
-        
+
         if (selector & 0x4)
             dt = &env->ldt;
         else
@@ -1871,7 +1944,7 @@
         ptr = dt->base + index;
         e1 = ldl_kernel(ptr);
         e2 = ldl_kernel(ptr + 4);
-        
+
         if (!(e2 & DESC_S_MASK))
             raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
         rpl = selector & 3;
@@ -1886,10 +1959,10 @@
             /* must be readable segment */
             if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
                 raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
-            
+
             if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
                 /* if not conforming code, test rights */
-                if (dpl < cpl || dpl < rpl) 
+                if (dpl < cpl || dpl < rpl)
                     raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
             }
         }
@@ -1907,12 +1980,12 @@
             stl_kernel(ptr + 4, e2);
         }
 
-        cpu_x86_load_seg_cache(env, seg_reg, selector, 
+        cpu_x86_load_seg_cache(env, seg_reg, selector,
                        get_seg_base(e1, e2),
                        get_seg_limit(e1, e2),
                        e2);
 #if 0
-        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n", 
+        fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
                 selector, (unsigned long)sc->base, sc->limit, sc->flags);
 #endif
     }
@@ -1924,7 +1997,7 @@
     int new_cs, gate_cs, type;
     uint32_t e1, e2, cpl, dpl, rpl, limit;
     target_ulong new_eip, next_eip;
-    
+
     new_cs = T0;
     new_eip = T1;
     if ((new_cs & 0xfffc) == 0)
@@ -1951,7 +2024,7 @@
         if (!(e2 & DESC_P_MASK))
             raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
         limit = get_seg_limit(e1, e2);
-        if (new_eip > limit && 
+        if (new_eip > limit &&
             !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
             raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
         cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
@@ -1987,10 +2060,10 @@
                 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
             dpl = (e2 >> DESC_DPL_SHIFT) & 3;
             /* must be code segment */
-            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) != 
+            if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
                  (DESC_S_MASK | DESC_CS_MASK)))
                 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
-            if (((e2 & DESC_C_MASK) && (dpl > cpl)) || 
+            if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
                 (!(e2 & DESC_C_MASK) && (dpl != cpl)))
                 raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
             if (!(e2 & DESC_P_MASK))
@@ -2043,7 +2116,7 @@
     uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
     uint32_t val, limit, old_sp_mask;
     target_ulong ssp, old_ssp, next_eip, new_eip;
-    
+
     new_cs = T0;
     new_eip = T1;
     next_eip = env->eip + next_eip_addend;
@@ -2094,10 +2167,10 @@
             /* from this point, not restartable */
             ESP = rsp;
             cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
-                                   get_seg_base(e1, e2), 
+                                   get_seg_base(e1, e2),
                                    get_seg_limit(e1, e2), e2);
             EIP = new_eip;
-        } else 
+        } else
 #endif
         {
             sp = ESP;
@@ -2110,7 +2183,7 @@
                 PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
                 PUSHW(ssp, sp, sp_mask, next_eip);
             }
-            
+
             limit = get_seg_limit(e1, e2);
             if (new_eip > limit)
                 raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
@@ -2165,11 +2238,11 @@
             raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
 
         if (!(e2 & DESC_C_MASK) && dpl < cpl) {
-            /* to inner priviledge */
+            /* to inner privilege */
             get_ss_esp_from_tss(&ss, &sp, dpl);
 #ifdef DEBUG_PCALL
             if (loglevel & CPU_LOG_PCALL)
-                fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n", 
+                fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
                         ss, sp, param_count, ESP);
 #endif
             if ((ss & 0xfffc) == 0)
@@ -2187,12 +2260,12 @@
                 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
             if (!(ss_e2 & DESC_P_MASK))
                 raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
-            
+
             //            push_size = ((param_count * 2) + 8) << shift;
 
             old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
             old_ssp = env->segs[R_SS].base;
-            
+
             sp_mask = get_sp_mask(ss_e2);
             ssp = get_seg_base(ss_e1, ss_e2);
             if (shift) {
@@ -2212,7 +2285,7 @@
             }
             new_stack = 1;
         } else {
-            /* to same priviledge */
+            /* to same privilege */
             sp = ESP;
             sp_mask = get_sp_mask(env->segs[R_SS].flags);
             ssp = env->segs[R_SS].base;
@@ -2232,14 +2305,14 @@
 
         if (new_stack) {
             ss = (ss & ~3) | dpl;
-            cpu_x86_load_seg_cache(env, R_SS, ss, 
+            cpu_x86_load_seg_cache(env, R_SS, ss,
                                    ssp,
                                    get_seg_limit(ss_e1, ss_e2),
                                    ss_e2);
         }
 
         selector = (selector & ~3) | dpl;
-        cpu_x86_load_seg_cache(env, R_CS, selector, 
+        cpu_x86_load_seg_cache(env, R_CS, selector,
                        get_seg_base(e1, e2),
                        get_seg_limit(e1, e2),
                        e2);
@@ -2297,7 +2370,7 @@
     /* XXX: on x86_64, we do not want to nullify FS and GS because
        they may still contain a valid base. I would be interested to
        know how a real x86_64 CPU behaves */
-    if ((seg_reg == R_FS || seg_reg == R_GS) && 
+    if ((seg_reg == R_FS || seg_reg == R_GS) &&
         (env->segs[seg_reg].selector & 0xfffc) == 0)
         return;
 
@@ -2319,7 +2392,7 @@
     uint32_t e1, e2, ss_e1, ss_e2;
     int cpl, dpl, rpl, eflags_mask, iopl;
     target_ulong ssp, sp, new_eip, new_esp, sp_mask;
-    
+
 #ifdef TARGET_X86_64
     if (shift == 2)
         sp_mask = -1;
@@ -2371,7 +2444,7 @@
         !(e2 & DESC_CS_MASK))
         raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
     cpl = env->hflags & HF_CPL_MASK;
-    rpl = new_cs & 3; 
+    rpl = new_cs & 3;
     if (rpl < cpl)
         raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
     dpl = (e2 >> DESC_DPL_SHIFT) & 3;
@@ -2384,17 +2457,17 @@
     }
     if (!(e2 & DESC_P_MASK))
         raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
-    
+
     sp += addend;
-    if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) || 
+    if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
                        ((env->hflags & HF_CS64_MASK) && !is_iret))) {
         /* return to same priledge level */
-        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
+        cpu_x86_load_seg_cache(env, R_CS, new_cs,
                        get_seg_base(e1, e2),
                        get_seg_limit(e1, e2),
                        e2);
     } else {
-        /* return to different priviledge level */
+        /* return to different privilege level */
 #ifdef TARGET_X86_64
         if (shift == 2) {
             POPQ(sp, new_esp);
@@ -2423,13 +2496,13 @@
             /* NULL ss is allowed in long mode if cpl != 3*/
             /* XXX: test CS64 ? */
             if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
-                cpu_x86_load_seg_cache(env, R_SS, new_ss, 
+                cpu_x86_load_seg_cache(env, R_SS, new_ss,
                                        0, 0xffffffff,
                                        DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                                        DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
                                        DESC_W_MASK | DESC_A_MASK);
                 ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
-            } else 
+            } else
 #endif
             {
                 raise_exception_err(EXCP0D_GPF, 0);
@@ -2448,13 +2521,13 @@
                 raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
             if (!(ss_e2 & DESC_P_MASK))
                 raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
-            cpu_x86_load_seg_cache(env, R_SS, new_ss, 
+            cpu_x86_load_seg_cache(env, R_SS, new_ss,
                                    get_seg_base(ss_e1, ss_e2),
                                    get_seg_limit(ss_e1, ss_e2),
                                    ss_e2);
         }
 
-        cpu_x86_load_seg_cache(env, R_CS, new_cs, 
+        cpu_x86_load_seg_cache(env, R_CS, new_cs,
                        get_seg_base(e1, e2),
                        get_seg_limit(e1, e2),
                        e2);
@@ -2498,9 +2571,9 @@
     POPL(ssp, sp, sp_mask, new_ds);
     POPL(ssp, sp, sp_mask, new_fs);
     POPL(ssp, sp, sp_mask, new_gs);
-    
+
     /* modify processor state */
-    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK | 
+    load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
                 IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
     load_seg_vm(R_CS, new_cs & 0xffff);
     cpu_x86_set_cpl(env, 3);
@@ -2518,7 +2591,7 @@
 {
     int tss_selector, type;
     uint32_t e1, e2;
-    
+
     /* specific case for TSS */
     if (env->eflags & NT_MASK) {
 #ifdef TARGET_X86_64
@@ -2565,12 +2638,12 @@
     }
     env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
     cpu_x86_set_cpl(env, 0);
-    cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, 
-                           0, 0xffffffff, 
+    cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                           0, 0xffffffff,
                            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                            DESC_S_MASK |
                            DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
-    cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, 
+    cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
                            0, 0xffffffff,
                            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                            DESC_S_MASK |
@@ -2588,12 +2661,12 @@
         raise_exception_err(EXCP0D_GPF, 0);
     }
     cpu_x86_set_cpl(env, 3);
-    cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, 
-                           0, 0xffffffff, 
+    cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
+                           0, 0xffffffff,
                            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                            DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
                            DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
-    cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, 
+    cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
                            0, 0xffffffff,
                            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
                            DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
@@ -2610,7 +2683,7 @@
 
 void helper_movl_crN_T0(int reg)
 {
-#if !defined(CONFIG_USER_ONLY) 
+#if !defined(CONFIG_USER_ONLY)
     switch(reg) {
     case 0:
         cpu_x86_update_cr0(env, T0);
@@ -2654,7 +2727,7 @@
     EDX = (uint32_t)(val >> 32);
 }
 
-#if defined(CONFIG_USER_ONLY) 
+#if defined(CONFIG_USER_ONLY)
 void helper_wrmsr(void)
 {
 }
@@ -2694,7 +2767,7 @@
                 update_mask |= MSR_EFER_FFXSR;
             if (env->cpuid_ext2_features & CPUID_EXT2_NX)
                 update_mask |= MSR_EFER_NXE;
-            env->efer = (env->efer & ~update_mask) | 
+            env->efer = (env->efer & ~update_mask) |
             (val & update_mask);
         }
         break;
@@ -2704,6 +2777,9 @@
     case MSR_PAT:
         env->pat = val;
         break;
+    case MSR_VM_HSAVE_PA:
+        env->vm_hsave = val;
+        break;
 #ifdef TARGET_X86_64
     case MSR_LSTAR:
         env->lstar = val;
@@ -2726,7 +2802,7 @@
 #endif
     default:
         /* XXX: exception ? */
-        break; 
+        break;
     }
 }
 
@@ -2755,6 +2831,9 @@
     case MSR_PAT:
         val = env->pat;
         break;
+    case MSR_VM_HSAVE_PA:
+        val = env->vm_hsave;
+        break;
 #ifdef TARGET_X86_64
     case MSR_LSTAR:
         val = env->lstar;
@@ -2778,7 +2857,7 @@
     default:
         /* XXX: exception ? */
         val = 0;
-        break; 
+        break;
     }
     EAX = (uint32_t)(val);
     EDX = (uint32_t)(val >> 32);
@@ -2965,7 +3044,7 @@
 
 CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
 {
-    if (b == 0.0) 
+    if (b == 0.0)
         fpu_set_exception(FPUS_ZE);
     return a / b;
 }
@@ -2974,8 +3053,8 @@
 {
     if (env->cr[0] & CR0_NE_MASK) {
         raise_exception(EXCP10_COPR);
-    } 
-#if !defined(CONFIG_USER_ONLY) 
+    }
+#if !defined(CONFIG_USER_ONLY)
     else {
         cpu_set_ferr(env);
     }
@@ -3039,13 +3118,13 @@
 void helper_fyl2x(void)
 {
     CPU86_LDouble fptemp;
-    
+
     fptemp = ST0;
     if (fptemp>0.0){
         fptemp = log(fptemp)/log(2.0);	 /* log2(ST) */
         ST1 *= fptemp;
         fpop();
-    } else { 
+    } else {
         env->fpus &= (~0x4700);
         env->fpus |= 0x400;
     }
@@ -3096,30 +3175,51 @@
     CPU86_LDouble dblq, fpsrcop, fptemp;
     CPU86_LDoubleU fpsrcop1, fptemp1;
     int expdif;
-    int q;
+    signed long long int q;
+
+    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
+        ST0 = 0.0 / 0.0; /* NaN */
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+        return;
+    }
 
     fpsrcop = ST0;
     fptemp = ST1;
     fpsrcop1.d = fpsrcop;
     fptemp1.d = fptemp;
     expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+
+    if (expdif < 0) {
+        /* optimisation? taken from the AMD docs */
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+        /* ST0 is unchanged */
+        return;
+    }
+
     if (expdif < 53) {
         dblq = fpsrcop / fptemp;
-        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
-        ST0 = fpsrcop - fptemp*dblq;
-        q = (int)dblq; /* cutting off top bits is assumed here */
+        /* round dblq towards nearest integer */
+        dblq = rint(dblq);
+        ST0 = fpsrcop - fptemp * dblq;
+
+        /* convert dblq to q by truncating towards zero */
+        if (dblq < 0.0)
+           q = (signed long long int)(-dblq);
+        else
+           q = (signed long long int)dblq;
+
         env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
-				/* (C0,C1,C3) <-- (q2,q1,q0) */
-        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
-        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
-        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
+                                /* (C0,C3,C1) <-- (q2,q1,q0) */
+        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
+        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
+        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
     } else {
         env->fpus |= 0x400;  /* C2 <-- 1 */
-        fptemp = pow(2.0, expdif-50);
+        fptemp = pow(2.0, expdif - 50);
         fpsrcop = (ST0 / ST1) / fptemp;
-        /* fpsrcop = integer obtained by rounding to the nearest */
-        fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
-            floor(fpsrcop): ceil(fpsrcop);
+        /* fpsrcop = integer obtained by chopping */
+        fpsrcop = (fpsrcop < 0.0) ?
+                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
         ST0 -= (ST1 * fpsrcop * fptemp);
     }
 }
@@ -3129,30 +3229,52 @@
     CPU86_LDouble dblq, fpsrcop, fptemp;
     CPU86_LDoubleU fpsrcop1, fptemp1;
     int expdif;
-    int q;
-    
-    fpsrcop = ST0;
-    fptemp = ST1;
+    signed long long int q;
+
+    if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
+       ST0 = 0.0 / 0.0; /* NaN */
+       env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+       return;
+    }
+
+    fpsrcop = (CPU86_LDouble)ST0;
+    fptemp = (CPU86_LDouble)ST1;
     fpsrcop1.d = fpsrcop;
     fptemp1.d = fptemp;
     expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
-    if ( expdif < 53 ) {
-        dblq = fpsrcop / fptemp;
-        dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
-        ST0 = fpsrcop - fptemp*dblq;
-        q = (int)dblq; /* cutting off top bits is assumed here */
+
+    if (expdif < 0) {
+        /* optimisation? taken from the AMD docs */
         env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
-				/* (C0,C1,C3) <-- (q2,q1,q0) */
-        env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
-        env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
-        env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
+        /* ST0 is unchanged */
+        return;
+    }
+
+    if ( expdif < 53 ) {
+        dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
+        /* round dblq towards zero */
+        dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
+        ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
+
+        /* convert dblq to q by truncating towards zero */
+        if (dblq < 0.0)
+           q = (signed long long int)(-dblq);
+        else
+           q = (signed long long int)dblq;
+
+        env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+                                /* (C0,C3,C1) <-- (q2,q1,q0) */
+        env->fpus |= (q & 0x4) << (8 - 2);  /* (C0) <-- q2 */
+        env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
+        env->fpus |= (q & 0x1) << (9 - 0);  /* (C1) <-- q0 */
     } else {
+        int N = 32 + (expdif % 32); /* as per AMD docs */
         env->fpus |= 0x400;  /* C2 <-- 1 */
-        fptemp = pow(2.0, expdif-50);
+        fptemp = pow(2.0, (double)(expdif - N));
         fpsrcop = (ST0 / ST1) / fptemp;
         /* fpsrcop = integer obtained by chopping */
-        fpsrcop = (fpsrcop < 0.0)?
-            -(floor(fabs(fpsrcop))): floor(fpsrcop);
+        fpsrcop = (fpsrcop < 0.0) ?
+                  -(floor(fabs(fpsrcop))) : floor(fpsrcop);
         ST0 -= (ST1 * fpsrcop * fptemp);
     }
 }
@@ -3166,7 +3288,7 @@
         fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
         ST1 *= fptemp;
         fpop();
-    } else { 
+    } else {
         env->fpus &= (~0x4700);
         env->fpus |= 0x400;
     }
@@ -3177,7 +3299,7 @@
     CPU86_LDouble fptemp;
 
     fptemp = ST0;
-    if (fptemp<0.0) { 
+    if (fptemp<0.0) {
         env->fpus &= (~0x4700);  /* (C3,C2,C1,C0) <-- 0000 */
         env->fpus |= 0x400;
     }
@@ -3207,7 +3329,7 @@
 
 void helper_fscale(void)
 {
-    ST0 = ldexp (ST0, (int)(ST1)); 
+    ST0 = ldexp (ST0, (int)(ST1));
 }
 
 void helper_fsin(void)
@@ -3406,7 +3528,7 @@
         helper_fstt(tmp, addr);
         addr += 16;
     }
-    
+
     if (env->cr[4] & CR4_OSFXSR_MASK) {
         /* XXX: finish it */
         stl(ptr + 0x18, env->mxcsr); /* mxcsr */
@@ -3534,50 +3656,6 @@
     add128(plow, phigh, 1, 0);
 }
 
-static void mul64(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
-{
-    uint32_t a0, a1, b0, b1;
-    uint64_t v;
-
-    a0 = a;
-    a1 = a >> 32;
-
-    b0 = b;
-    b1 = b >> 32;
-    
-    v = (uint64_t)a0 * (uint64_t)b0;
-    *plow = v;
-    *phigh = 0;
-
-    v = (uint64_t)a0 * (uint64_t)b1;
-    add128(plow, phigh, v << 32, v >> 32);
-    
-    v = (uint64_t)a1 * (uint64_t)b0;
-    add128(plow, phigh, v << 32, v >> 32);
-    
-    v = (uint64_t)a1 * (uint64_t)b1;
-    *phigh += v;
-#ifdef DEBUG_MULDIV
-    printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n",
-           a, b, *phigh, *plow);
-#endif
-}
-
-static void imul64(uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
-{
-    int sa, sb;
-    sa = (a < 0);
-    if (sa)
-        a = -a;
-    sb = (b < 0);
-    if (sb)
-        b = -b;
-    mul64(plow, phigh, a, b);
-    if (sa ^ sb) {
-        neg128(plow, phigh);
-    }
-}
-
 /* return TRUE if overflow */
 static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
 {
@@ -3645,7 +3723,7 @@
 {
     uint64_t r0, r1;
 
-    mul64(&r0, &r1, EAX, T0);
+    mulu64(&r1, &r0, EAX, T0);
     EAX = r0;
     EDX = r1;
     CC_DST = r0;
@@ -3656,7 +3734,7 @@
 {
     uint64_t r0, r1;
 
-    imul64(&r0, &r1, EAX, T0);
+    muls64(&r1, &r0, EAX, T0);
     EAX = r0;
     EDX = r1;
     CC_DST = r0;
@@ -3667,7 +3745,7 @@
 {
     uint64_t r0, r1;
 
-    imul64(&r0, &r1, T0, T1);
+    muls64(&r1, &r0, T0, T1);
     T0 = r0;
     CC_DST = r0;
     CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
@@ -3783,7 +3861,7 @@
 #endif
 }
 
-#if !defined(CONFIG_USER_ONLY) 
+#if !defined(CONFIG_USER_ONLY)
 
 #define MMUSUFFIX _mmu
 #define GETPC() (__builtin_return_address(0))
@@ -3837,3 +3915,491 @@
     }
     env = saved_env;
 }
+
+
+/* Secure Virtual Machine helpers */
+
+void helper_stgi(void)
+{
+    env->hflags |= HF_GIF_MASK;
+}
+
+void helper_clgi(void)
+{
+    env->hflags &= ~HF_GIF_MASK;
+}
+
+#if defined(CONFIG_USER_ONLY)
+
+void helper_vmrun(target_ulong addr) { }
+void helper_vmmcall(void) { }
+void helper_vmload(target_ulong addr) { }
+void helper_vmsave(target_ulong addr) { }
+void helper_skinit(void) { }
+void helper_invlpga(void) { }
+void vmexit(uint64_t exit_code, uint64_t exit_info_1) { }
+int svm_check_intercept_param(uint32_t type, uint64_t param)
+{
+    return 0;
+}
+
+#else
+
+static inline uint32_t
+vmcb2cpu_attrib(uint16_t vmcb_attrib, uint32_t vmcb_base, uint32_t vmcb_limit)
+{
+    return    ((vmcb_attrib & 0x00ff) << 8)          /* Type, S, DPL, P */
+	    | ((vmcb_attrib & 0x0f00) << 12)         /* AVL, L, DB, G */
+	    | ((vmcb_base >> 16) & 0xff)             /* Base 23-16 */
+	    | (vmcb_base & 0xff000000)               /* Base 31-24 */
+	    | (vmcb_limit & 0xf0000);                /* Limit 19-16 */
+}
+
+static inline uint16_t cpu2vmcb_attrib(uint32_t cpu_attrib)
+{
+    return    ((cpu_attrib >> 8) & 0xff)             /* Type, S, DPL, P */
+	    | ((cpu_attrib & 0xf00000) >> 12);       /* AVL, L, DB, G */
+}
+
+extern uint8_t *phys_ram_base;
+void helper_vmrun(target_ulong addr)
+{
+    uint32_t event_inj;
+    uint32_t int_ctl;
+
+    if (loglevel & CPU_LOG_TB_IN_ASM)
+        fprintf(logfile,"vmrun! " TARGET_FMT_lx "\n", addr);
+
+    env->vm_vmcb = addr;
+    regs_to_env();
+
+    /* save the current CPU state in the hsave page */
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
+    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base), env->idt.base);
+    stl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0), env->cr[0]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr2), env->cr[2]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3), env->cr[3]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4), env->cr[4]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8), env->cr[8]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6), env->dr[6]);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7), env->dr[7]);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer), env->efer);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags), compute_eflags());
+
+    SVM_SAVE_SEG(env->vm_hsave, segs[R_ES], es);
+    SVM_SAVE_SEG(env->vm_hsave, segs[R_CS], cs);
+    SVM_SAVE_SEG(env->vm_hsave, segs[R_SS], ss);
+    SVM_SAVE_SEG(env->vm_hsave, segs[R_DS], ds);
+
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip), EIP);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp), ESP);
+    stq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax), EAX);
+
+    /* load the interception bitmaps so we do not need to access the
+       vmcb in svm mode */
+    /* We shift all the intercept bits so we can OR them with the TB
+       flags later on */
+    env->intercept            = (ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept)) << INTERCEPT_INTR) | INTERCEPT_SVM_MASK;
+    env->intercept_cr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_read));
+    env->intercept_cr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_cr_write));
+    env->intercept_dr_read    = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_read));
+    env->intercept_dr_write   = lduw_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_dr_write));
+    env->intercept_exceptions = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.intercept_exceptions));
+
+    env->gdt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base));
+    env->gdt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit));
+
+    env->idt.base  = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base));
+    env->idt.limit = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit));
+
+    /* clear exit_info_2 so we behave like the real hardware */
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), 0);
+
+    cpu_x86_update_cr0(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0)));
+    cpu_x86_update_cr4(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4)));
+    cpu_x86_update_cr3(env, ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3)));
+    env->cr[2] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2));
+    int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl));
+    if (int_ctl & V_INTR_MASKING_MASK) {
+        env->cr[8] = int_ctl & V_TPR_MASK;
+        if (env->eflags & IF_MASK)
+            env->hflags |= HF_HIF_MASK;
+    }
+
+#ifdef TARGET_X86_64
+    env->efer = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer));
+    env->hflags &= ~HF_LMA_MASK;
+    if (env->efer & MSR_EFER_LMA)
+       env->hflags |= HF_LMA_MASK;
+#endif
+    env->eflags = 0;
+    load_eflags(ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags)),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    CC_OP = CC_OP_EFLAGS;
+    CC_DST = 0xffffffff;
+
+    SVM_LOAD_SEG(env->vm_vmcb, ES, es);
+    SVM_LOAD_SEG(env->vm_vmcb, CS, cs);
+    SVM_LOAD_SEG(env->vm_vmcb, SS, ss);
+    SVM_LOAD_SEG(env->vm_vmcb, DS, ds);
+
+    EIP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip));
+    env->eip = EIP;
+    ESP = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp));
+    EAX = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax));
+    env->dr[7] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7));
+    env->dr[6] = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6));
+    cpu_x86_set_cpl(env, ldub_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl)));
+
+    /* FIXME: guest state consistency checks */
+
+    switch(ldub_phys(env->vm_vmcb + offsetof(struct vmcb, control.tlb_ctl))) {
+        case TLB_CONTROL_DO_NOTHING:
+            break;
+        case TLB_CONTROL_FLUSH_ALL_ASID:
+            /* FIXME: this is not 100% correct but should work for now */
+            tlb_flush(env, 1);
+        break;
+    }
+
+    helper_stgi();
+
+    regs_to_env();
+
+    /* maybe we need to inject an event */
+    event_inj = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj));
+    if (event_inj & SVM_EVTINJ_VALID) {
+        uint8_t vector = event_inj & SVM_EVTINJ_VEC_MASK;
+        uint16_t valid_err = event_inj & SVM_EVTINJ_VALID_ERR;
+        uint32_t event_inj_err = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj_err));
+        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.event_inj), event_inj & ~SVM_EVTINJ_VALID);
+
+        if (loglevel & CPU_LOG_TB_IN_ASM)
+            fprintf(logfile, "Injecting(%#hx): ", valid_err);
+        /* FIXME: need to implement valid_err */
+        switch (event_inj & SVM_EVTINJ_TYPE_MASK) {
+        case SVM_EVTINJ_TYPE_INTR:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 1;
+                env->exception_next_eip = -1;
+                if (loglevel & CPU_LOG_TB_IN_ASM)
+                    fprintf(logfile, "INTR");
+                break;
+        case SVM_EVTINJ_TYPE_NMI:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 1;
+                env->exception_next_eip = EIP;
+                if (loglevel & CPU_LOG_TB_IN_ASM)
+                    fprintf(logfile, "NMI");
+                break;
+        case SVM_EVTINJ_TYPE_EXEPT:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 0;
+                env->exception_next_eip = -1;
+                if (loglevel & CPU_LOG_TB_IN_ASM)
+                    fprintf(logfile, "EXEPT");
+                break;
+        case SVM_EVTINJ_TYPE_SOFT:
+                env->exception_index = vector;
+                env->error_code = event_inj_err;
+                env->exception_is_int = 1;
+                env->exception_next_eip = EIP;
+                if (loglevel & CPU_LOG_TB_IN_ASM)
+                    fprintf(logfile, "SOFT");
+                break;
+        }
+        if (loglevel & CPU_LOG_TB_IN_ASM)
+            fprintf(logfile, " %#x %#x\n", env->exception_index, env->error_code);
+    }
+    if ((int_ctl & V_IRQ_MASK) || (env->intercept & INTERCEPT_VINTR)) {
+        env->interrupt_request |= CPU_INTERRUPT_VIRQ;
+    }
+
+    cpu_loop_exit();
+}
+
+void helper_vmmcall(void)
+{
+    if (loglevel & CPU_LOG_TB_IN_ASM)
+        fprintf(logfile,"vmmcall!\n");
+}
+
+void helper_vmload(target_ulong addr)
+{
+    if (loglevel & CPU_LOG_TB_IN_ASM)
+        fprintf(logfile,"vmload! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
+                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
+                env->segs[R_FS].base);
+
+    SVM_LOAD_SEG2(addr, segs[R_FS], fs);
+    SVM_LOAD_SEG2(addr, segs[R_GS], gs);
+    SVM_LOAD_SEG2(addr, tr, tr);
+    SVM_LOAD_SEG2(addr, ldt, ldtr);
+
+#ifdef TARGET_X86_64
+    env->kernelgsbase = ldq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base));
+    env->lstar = ldq_phys(addr + offsetof(struct vmcb, save.lstar));
+    env->cstar = ldq_phys(addr + offsetof(struct vmcb, save.cstar));
+    env->fmask = ldq_phys(addr + offsetof(struct vmcb, save.sfmask));
+#endif
+    env->star = ldq_phys(addr + offsetof(struct vmcb, save.star));
+    env->sysenter_cs = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_cs));
+    env->sysenter_esp = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_esp));
+    env->sysenter_eip = ldq_phys(addr + offsetof(struct vmcb, save.sysenter_eip));
+}
+
+void helper_vmsave(target_ulong addr)
+{
+    if (loglevel & CPU_LOG_TB_IN_ASM)
+        fprintf(logfile,"vmsave! " TARGET_FMT_lx "\nFS: %016" PRIx64 " | " TARGET_FMT_lx "\n",
+                addr, ldq_phys(addr + offsetof(struct vmcb, save.fs.base)),
+                env->segs[R_FS].base);
+
+    SVM_SAVE_SEG(addr, segs[R_FS], fs);
+    SVM_SAVE_SEG(addr, segs[R_GS], gs);
+    SVM_SAVE_SEG(addr, tr, tr);
+    SVM_SAVE_SEG(addr, ldt, ldtr);
+
+#ifdef TARGET_X86_64
+    stq_phys(addr + offsetof(struct vmcb, save.kernel_gs_base), env->kernelgsbase);
+    stq_phys(addr + offsetof(struct vmcb, save.lstar), env->lstar);
+    stq_phys(addr + offsetof(struct vmcb, save.cstar), env->cstar);
+    stq_phys(addr + offsetof(struct vmcb, save.sfmask), env->fmask);
+#endif
+    stq_phys(addr + offsetof(struct vmcb, save.star), env->star);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_cs), env->sysenter_cs);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_esp), env->sysenter_esp);
+    stq_phys(addr + offsetof(struct vmcb, save.sysenter_eip), env->sysenter_eip);
+}
+
+void helper_skinit(void)
+{
+    if (loglevel & CPU_LOG_TB_IN_ASM)
+        fprintf(logfile,"skinit!\n");
+}
+
+void helper_invlpga(void)
+{
+    tlb_flush(env, 0);
+}
+
+int svm_check_intercept_param(uint32_t type, uint64_t param)
+{
+    switch(type) {
+    case SVM_EXIT_READ_CR0 ... SVM_EXIT_READ_CR0 + 8:
+        if (INTERCEPTEDw(_cr_read, (1 << (type - SVM_EXIT_READ_CR0)))) {
+            vmexit(type, param);
+            return 1;
+        }
+        break;
+    case SVM_EXIT_READ_DR0 ... SVM_EXIT_READ_DR0 + 8:
+        if (INTERCEPTEDw(_dr_read, (1 << (type - SVM_EXIT_READ_DR0)))) {
+            vmexit(type, param);
+            return 1;
+        }
+        break;
+    case SVM_EXIT_WRITE_CR0 ... SVM_EXIT_WRITE_CR0 + 8:
+        if (INTERCEPTEDw(_cr_write, (1 << (type - SVM_EXIT_WRITE_CR0)))) {
+            vmexit(type, param);
+            return 1;
+        }
+        break;
+    case SVM_EXIT_WRITE_DR0 ... SVM_EXIT_WRITE_DR0 + 8:
+        if (INTERCEPTEDw(_dr_write, (1 << (type - SVM_EXIT_WRITE_DR0)))) {
+            vmexit(type, param);
+            return 1;
+        }
+        break;
+    case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 16:
+        if (INTERCEPTEDl(_exceptions, (1 << (type - SVM_EXIT_EXCP_BASE)))) {
+            vmexit(type, param);
+            return 1;
+        }
+        break;
+    case SVM_EXIT_IOIO:
+        if (INTERCEPTED(1ULL << INTERCEPT_IOIO_PROT)) {
+            /* FIXME: this should be read in at vmrun (faster this way?) */
+            uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.iopm_base_pa));
+            uint16_t port = (uint16_t) (param >> 16);
+
+            if(ldub_phys(addr + port / 8) & (1 << (port % 8)))
+                vmexit(type, param);
+        }
+        break;
+
+    case SVM_EXIT_MSR:
+        if (INTERCEPTED(1ULL << INTERCEPT_MSR_PROT)) {
+            /* FIXME: this should be read in at vmrun (faster this way?) */
+            uint64_t addr = ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.msrpm_base_pa));
+            switch((uint32_t)ECX) {
+            case 0 ... 0x1fff:
+                T0 = (ECX * 2) % 8;
+                T1 = ECX / 8;
+                break;
+            case 0xc0000000 ... 0xc0001fff:
+                T0 = (8192 + ECX - 0xc0000000) * 2;
+                T1 = (T0 / 8);
+                T0 %= 8;
+                break;
+            case 0xc0010000 ... 0xc0011fff:
+                T0 = (16384 + ECX - 0xc0010000) * 2;
+                T1 = (T0 / 8);
+                T0 %= 8;
+                break;
+            default:
+                vmexit(type, param);
+                return 1;
+            }
+            if (ldub_phys(addr + T1) & ((1 << param) << T0))
+                vmexit(type, param);
+            return 1;
+        }
+        break;
+    default:
+        if (INTERCEPTED((1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR)))) {
+            vmexit(type, param);
+            return 1;
+        }
+        break;
+    }
+    return 0;
+}
+
+void vmexit(uint64_t exit_code, uint64_t exit_info_1)
+{
+    uint32_t int_ctl;
+
+    if (loglevel & CPU_LOG_TB_IN_ASM)
+        fprintf(logfile,"vmexit(%016" PRIx64 ", %016" PRIx64 ", %016" PRIx64 ", " TARGET_FMT_lx ")!\n",
+                exit_code, exit_info_1,
+                ldq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2)),
+                EIP);
+
+    if(env->hflags & HF_INHIBIT_IRQ_MASK) {
+        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), SVM_INTERRUPT_SHADOW_MASK);
+        env->hflags &= ~HF_INHIBIT_IRQ_MASK;
+    } else {
+        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_state), 0);
+    }
+
+    /* Save the VM state in the vmcb */
+    SVM_SAVE_SEG(env->vm_vmcb, segs[R_ES], es);
+    SVM_SAVE_SEG(env->vm_vmcb, segs[R_CS], cs);
+    SVM_SAVE_SEG(env->vm_vmcb, segs[R_SS], ss);
+    SVM_SAVE_SEG(env->vm_vmcb, segs[R_DS], ds);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.base), env->gdt.base);
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.gdtr.limit), env->gdt.limit);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.base), env->idt.base);
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, save.idtr.limit), env->idt.limit);
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.efer), env->efer);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr0), env->cr[0]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr2), env->cr[2]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr3), env->cr[3]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.cr4), env->cr[4]);
+
+    if ((int_ctl = ldl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl))) & V_INTR_MASKING_MASK) {
+        int_ctl &= ~V_TPR_MASK;
+        int_ctl |= env->cr[8] & V_TPR_MASK;
+        stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.int_ctl), int_ctl);
+    }
+
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rflags), compute_eflags());
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rip), env->eip);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rsp), ESP);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.rax), EAX);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr7), env->dr[7]);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, save.dr6), env->dr[6]);
+    stb_phys(env->vm_vmcb + offsetof(struct vmcb, save.cpl), env->hflags & HF_CPL_MASK);
+
+    /* Reload the host state from vm_hsave */
+    env->hflags &= ~HF_HIF_MASK;
+    env->intercept = 0;
+    env->intercept_exceptions = 0;
+    env->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
+
+    env->gdt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.base));
+    env->gdt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.gdtr.limit));
+
+    env->idt.base  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.base));
+    env->idt.limit = ldl_phys(env->vm_hsave + offsetof(struct vmcb, save.idtr.limit));
+
+    cpu_x86_update_cr0(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr0)) | CR0_PE_MASK);
+    cpu_x86_update_cr4(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr4)));
+    cpu_x86_update_cr3(env, ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr3)));
+    if (int_ctl & V_INTR_MASKING_MASK)
+        env->cr[8] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.cr8));
+    /* we need to set the efer after the crs so the hidden flags get set properly */
+#ifdef TARGET_X86_64
+    env->efer  = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.efer));
+    env->hflags &= ~HF_LMA_MASK;
+    if (env->efer & MSR_EFER_LMA)
+       env->hflags |= HF_LMA_MASK;
+#endif
+
+    env->eflags = 0;
+    load_eflags(ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rflags)),
+                ~(CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C | DF_MASK));
+    CC_OP = CC_OP_EFLAGS;
+
+    SVM_LOAD_SEG(env->vm_hsave, ES, es);
+    SVM_LOAD_SEG(env->vm_hsave, CS, cs);
+    SVM_LOAD_SEG(env->vm_hsave, SS, ss);
+    SVM_LOAD_SEG(env->vm_hsave, DS, ds);
+
+    EIP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rip));
+    ESP = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rsp));
+    EAX = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.rax));
+
+    env->dr[6] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr6));
+    env->dr[7] = ldq_phys(env->vm_hsave + offsetof(struct vmcb, save.dr7));
+
+    /* other setups */
+    cpu_x86_set_cpl(env, 0);
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code_hi), (uint32_t)(exit_code >> 32));
+    stl_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_code), exit_code);
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_1), exit_info_1);
+
+    helper_clgi();
+    /* FIXME: Resets the current ASID register to zero (host ASID). */
+
+    /* Clears the V_IRQ and V_INTR_MASKING bits inside the processor. */
+
+    /* Clears the TSC_OFFSET inside the processor. */
+
+    /* If the host is in PAE mode, the processor reloads the host's PDPEs
+       from the page table indicated the host's CR3. If the PDPEs contain
+       illegal state, the processor causes a shutdown. */
+
+    /* Forces CR0.PE = 1, RFLAGS.VM = 0. */
+    env->cr[0] |= CR0_PE_MASK;
+    env->eflags &= ~VM_MASK;
+
+    /* Disables all breakpoints in the host DR7 register. */
+
+    /* Checks the reloaded host state for consistency. */
+
+    /* If the host's rIP reloaded by #VMEXIT is outside the limit of the
+       host's code segment or non-canonical (in the case of long mode), a
+       #GP fault is delivered inside the host.) */
+
+    /* remove any pending exception */
+    env->exception_index = -1;
+    env->error_code = 0;
+    env->old_exception = -1;
+
+    regs_to_env();
+    cpu_loop_exit();
+}
+
+#endif
diff --git a/target-i386/helper2.c b/target-i386/helper2.c
index 94833dd..b0e9692 100644
--- a/target-i386/helper2.c
+++ b/target-i386/helper2.c
@@ -1,6 +1,6 @@
 /*
  *  i386 helpers (without register variable usage)
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -27,6 +27,7 @@
 
 #include "cpu.h"
 #include "exec-all.h"
+#include "svm.h"
 
 #ifdef USE_KVM
 #include "../qemu-kvm.h"
@@ -81,7 +82,7 @@
         ldt.seg_not_present = 0;
         ldt.useable = 1;
         modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
-        
+
         asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
     }
 #endif
@@ -117,10 +118,11 @@
                                CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
                                CPUID_PAT);
         env->pat = 0x0007040600070406ULL;
+        env->cpuid_ext3_features = CPUID_EXT3_SVM;
         env->cpuid_ext_features = CPUID_EXT_SSE3;
         env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
         env->cpuid_features |= CPUID_APIC;
-        env->cpuid_xlevel = 0;
+        env->cpuid_xlevel = 0x8000000e;
         {
             const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION;
             int c, len, i;
@@ -141,7 +143,6 @@
         /* currently not enabled for std i386 because not fully tested */
         env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
         env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
-        env->cpuid_xlevel = 0x80000008;
 
         /* these features are needed for Win64 and aren't fully implemented */
         env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
@@ -174,11 +175,14 @@
 
     tlb_flush(env, 1);
 
+    env->old_exception = -1;
+
     /* init to reset state */
 
 #ifdef CONFIG_SOFTMMU
     env->hflags |= HF_SOFTMMU_MASK;
 #endif
+    env->hflags |= HF_GIF_MASK;
 
     cpu_x86_update_cr0(env, 0x60000010);
     env->a20_mask = 0xffffffff;
@@ -190,19 +194,19 @@
     env->ldt.flags = DESC_P_MASK | (2 << DESC_TYPE_SHIFT);
     env->tr.limit = 0xffff;
     env->tr.flags = DESC_P_MASK | (11 << DESC_TYPE_SHIFT);
-    
-    cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0); 
+
+    cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, 0);
     cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0);
-    
+
     env->eip = 0xfff0;
     env->regs[R_EDX] = 0x600; /* indicate P6 processor */
-    
+
     env->eflags = 0x2;
-    
+
     /* FPU init */
     for(i = 0;i < 8; i++)
         env->fptags[i] = 1;
@@ -274,7 +278,7 @@
     "SARQ",
 };
 
-void cpu_dump_state(CPUState *env, FILE *f, 
+void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
 {
@@ -285,28 +289,28 @@
     eflags = env->eflags;
 #ifdef TARGET_X86_64
     if (env->hflags & HF_CS64_MASK) {
-        cpu_fprintf(f, 
+        cpu_fprintf(f,
                     "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
                     "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
                     "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
                     "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
                     "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
-                    env->regs[R_EAX], 
-                    env->regs[R_EBX], 
-                    env->regs[R_ECX], 
-                    env->regs[R_EDX], 
-                    env->regs[R_ESI], 
-                    env->regs[R_EDI], 
-                    env->regs[R_EBP], 
-                    env->regs[R_ESP], 
-                    env->regs[8], 
-                    env->regs[9], 
-                    env->regs[10], 
-                    env->regs[11], 
-                    env->regs[12], 
-                    env->regs[13], 
-                    env->regs[14], 
-                    env->regs[15], 
+                    env->regs[R_EAX],
+                    env->regs[R_EBX],
+                    env->regs[R_ECX],
+                    env->regs[R_EDX],
+                    env->regs[R_ESI],
+                    env->regs[R_EDI],
+                    env->regs[R_EBP],
+                    env->regs[R_ESP],
+                    env->regs[8],
+                    env->regs[9],
+                    env->regs[10],
+                    env->regs[11],
+                    env->regs[12],
+                    env->regs[13],
+                    env->regs[14],
+                    env->regs[15],
                     env->eip, eflags,
                     eflags & DF_MASK ? 'D' : '-',
                     eflags & CC_O ? 'O' : '-',
@@ -315,25 +319,25 @@
                     eflags & CC_A ? 'A' : '-',
                     eflags & CC_P ? 'P' : '-',
                     eflags & CC_C ? 'C' : '-',
-                    env->hflags & HF_CPL_MASK, 
+                    env->hflags & HF_CPL_MASK,
                     (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
                     (env->a20_mask >> 20) & 1,
                     (env->hflags >> HF_SMM_SHIFT) & 1,
                     (env->hflags >> HF_HALTED_SHIFT) & 1);
-    } else 
+    } else
 #endif
     {
         cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
                     "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
                     "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d SMM=%d HLT=%d\n",
-                    (uint32_t)env->regs[R_EAX], 
-                    (uint32_t)env->regs[R_EBX], 
-                    (uint32_t)env->regs[R_ECX], 
-                    (uint32_t)env->regs[R_EDX], 
-                    (uint32_t)env->regs[R_ESI], 
-                    (uint32_t)env->regs[R_EDI], 
-                    (uint32_t)env->regs[R_EBP], 
-                    (uint32_t)env->regs[R_ESP], 
+                    (uint32_t)env->regs[R_EAX],
+                    (uint32_t)env->regs[R_EBX],
+                    (uint32_t)env->regs[R_ECX],
+                    (uint32_t)env->regs[R_EDX],
+                    (uint32_t)env->regs[R_ESI],
+                    (uint32_t)env->regs[R_EDI],
+                    (uint32_t)env->regs[R_EBP],
+                    (uint32_t)env->regs[R_ESP],
                     (uint32_t)env->eip, eflags,
                     eflags & DF_MASK ? 'D' : '-',
                     eflags & CC_O ? 'O' : '-',
@@ -342,7 +346,7 @@
                     eflags & CC_A ? 'A' : '-',
                     eflags & CC_P ? 'P' : '-',
                     eflags & CC_C ? 'C' : '-',
-                    env->hflags & HF_CPL_MASK, 
+                    env->hflags & HF_CPL_MASK,
                     (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
                     (env->a20_mask >> 20) & 1,
                     (env->hflags >> HF_SMM_SHIFT) & 1,
@@ -375,9 +379,9 @@
         cpu_fprintf(f, "IDT=     %016" PRIx64 " %08x\n",
                     env->idt.base, env->idt.limit);
         cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
-                    (uint32_t)env->cr[0], 
-                    env->cr[2], 
-                    env->cr[3], 
+                    (uint32_t)env->cr[0],
+                    env->cr[2],
+                    env->cr[3],
                     (uint32_t)env->cr[4]);
     } else
 #endif
@@ -406,9 +410,9 @@
         cpu_fprintf(f, "IDT=     %08x %08x\n",
                     (uint32_t)env->idt.base, env->idt.limit);
         cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
-                    (uint32_t)env->cr[0], 
-                    (uint32_t)env->cr[2], 
-                    (uint32_t)env->cr[3], 
+                    (uint32_t)env->cr[0],
+                    (uint32_t)env->cr[2],
+                    (uint32_t)env->cr[3],
                     (uint32_t)env->cr[4]);
     }
     if (flags & X86_DUMP_CCOP) {
@@ -419,13 +423,13 @@
 #ifdef TARGET_X86_64
         if (env->hflags & HF_CS64_MASK) {
             cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
-                        env->cc_src, env->cc_dst, 
+                        env->cc_src, env->cc_dst,
                         cc_op_name);
-        } else 
+        } else
 #endif
         {
             cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
-                        (uint32_t)env->cc_src, (uint32_t)env->cc_dst, 
+                        (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
                         cc_op_name);
         }
     }
@@ -462,13 +466,13 @@
             else
                 cpu_fprintf(f, " ");
         }
-        if (env->hflags & HF_CS64_MASK) 
+        if (env->hflags & HF_CS64_MASK)
             nb = 16;
         else
             nb = 8;
         for(i=0;i<nb;i++) {
             cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
-                        i, 
+                        i,
                         env->xmm_regs[i].XMM_L(3),
                         env->xmm_regs[i].XMM_L(2),
                         env->xmm_regs[i].XMM_L(1),
@@ -533,7 +537,7 @@
     }
 #endif
     env->cr[0] = new_cr0 | CR0_ET_MASK;
-    
+
     /* update PE flag in hidden flags */
     pe_state = (env->cr[0] & CR0_PE_MASK);
     env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
@@ -583,9 +587,9 @@
     tlb_flush_page(env, addr);
 }
 
-#if defined(CONFIG_USER_ONLY) 
+#if defined(CONFIG_USER_ONLY)
 
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, 
+int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
                              int is_write, int is_user, int is_softmmu)
 {
     /* user mode only emulation */
@@ -597,7 +601,7 @@
     return 1;
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
@@ -607,12 +611,12 @@
 #define PHYS_ADDR_MASK 0xfffff000
 
 /* return value:
-   -1 = cannot handle fault 
-   0  = nothing more to do 
+   -1 = cannot handle fault
+   0  = nothing more to do
    1  = generate PF fault
    2  = soft MMU activation required for this block
 */
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr, 
+int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
                              int is_write1, int is_user, int is_softmmu)
 {
     uint64_t ptep, pte;
@@ -620,13 +624,13 @@
     int error_code, is_dirty, prot, page_size, ret, is_write;
     unsigned long paddr, page_offset;
     target_ulong vaddr, virt_addr;
-    
+
 #if defined(DEBUG_MMU)
-    printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n", 
+    printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
            addr, is_write1, is_user, env->eip);
 #endif
     is_write = is_write1 & 1;
-    
+
     if (!(env->cr[0] & CR0_PG_MASK)) {
         pte = addr;
         virt_addr = addr & TARGET_PAGE_MASK;
@@ -652,8 +656,8 @@
                 env->exception_index = EXCP0D_GPF;
                 return 1;
             }
-            
-            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & 
+
+            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
                 env->a20_mask;
             pml4e = ldq_phys(pml4e_addr);
             if (!(pml4e & PG_PRESENT_MASK)) {
@@ -669,7 +673,7 @@
                 stl_phys_notdirty(pml4e_addr, pml4e);
             }
             ptep = pml4e ^ PG_NX_MASK;
-            pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) & 
+            pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
                 env->a20_mask;
             pdpe = ldq_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK)) {
@@ -689,7 +693,7 @@
 #endif
         {
             /* XXX: load them when cr3 is loaded ? */
-            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & 
+            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
                 env->a20_mask;
             pdpe = ldq_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK)) {
@@ -723,8 +727,8 @@
                 if (is_write && !(ptep & PG_RW_MASK))
                     goto do_fault_protect;
             } else {
-                if ((env->cr[0] & CR0_WP_MASK) && 
-                    is_write && !(ptep & PG_RW_MASK)) 
+                if ((env->cr[0] & CR0_WP_MASK) &&
+                    is_write && !(ptep & PG_RW_MASK))
                     goto do_fault_protect;
             }
             is_dirty = is_write && !(pde & PG_DIRTY_MASK);
@@ -735,7 +739,7 @@
                 stl_phys_notdirty(pde_addr, pde);
             }
             /* align to page_size */
-            pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff); 
+            pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
             virt_addr = addr & ~(page_size - 1);
         } else {
             /* 4 KB page */
@@ -758,7 +762,7 @@
             ptep &= pte ^ PG_NX_MASK;
             ptep ^= PG_NX_MASK;
             if ((ptep & PG_NX_MASK) && is_write1 == 2)
-                goto do_fault_protect; 
+                goto do_fault_protect;
             if (is_user) {
                 if (!(ptep & PG_USER_MASK))
                     goto do_fault_protect;
@@ -766,7 +770,7 @@
                     goto do_fault_protect;
             } else {
                 if ((env->cr[0] & CR0_WP_MASK) &&
-                    is_write && !(ptep & PG_RW_MASK)) 
+                    is_write && !(ptep & PG_RW_MASK))
                     goto do_fault_protect;
             }
             is_dirty = is_write && !(pte & PG_DIRTY_MASK);
@@ -784,7 +788,7 @@
         uint32_t pde;
 
         /* page directory entry */
-        pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & 
+        pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) &
             env->a20_mask;
         pde = ldl_phys(pde_addr);
         if (!(pde & PG_PRESENT_MASK)) {
@@ -800,8 +804,8 @@
                 if (is_write && !(pde & PG_RW_MASK))
                     goto do_fault_protect;
             } else {
-                if ((env->cr[0] & CR0_WP_MASK) && 
-                    is_write && !(pde & PG_RW_MASK)) 
+                if ((env->cr[0] & CR0_WP_MASK) &&
+                    is_write && !(pde & PG_RW_MASK))
                     goto do_fault_protect;
             }
             is_dirty = is_write && !(pde & PG_DIRTY_MASK);
@@ -811,7 +815,7 @@
                     pde |= PG_DIRTY_MASK;
                 stl_phys_notdirty(pde_addr, pde);
             }
-        
+
             pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
             ptep = pte;
             virt_addr = addr & ~(page_size - 1);
@@ -822,7 +826,7 @@
             }
 
             /* page directory entry */
-            pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & 
+            pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
                 env->a20_mask;
             pte = ldl_phys(pte_addr);
             if (!(pte & PG_PRESENT_MASK)) {
@@ -838,7 +842,7 @@
                     goto do_fault_protect;
             } else {
                 if ((env->cr[0] & CR0_WP_MASK) &&
-                    is_write && !(ptep & PG_RW_MASK)) 
+                    is_write && !(ptep & PG_RW_MASK))
                     goto do_fault_protect;
             }
             is_dirty = is_write && !(pte & PG_DIRTY_MASK);
@@ -876,26 +880,33 @@
     page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
     paddr = (pte & TARGET_PAGE_MASK) + page_offset;
     vaddr = virt_addr + page_offset;
-    
+
     ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
     return ret;
  do_fault_protect:
     error_code = PG_ERROR_P_MASK;
  do_fault:
-    env->cr[2] = addr;
     error_code |= (is_write << PG_ERROR_W_BIT);
     if (is_user)
         error_code |= PG_ERROR_U_MASK;
-    if (is_write1 == 2 && 
-        (env->efer & MSR_EFER_NXE) && 
+    if (is_write1 == 2 &&
+        (env->efer & MSR_EFER_NXE) &&
         (env->cr[4] & CR4_PAE_MASK))
         error_code |= PG_ERROR_I_D_MASK;
+    if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE)) {
+        stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), addr);
+    } else {
+        env->cr[2] = addr;
+    }
     env->error_code = error_code;
     env->exception_index = EXCP0E_PAGE;
+    /* the VMM will handle this */
+    if (INTERCEPTEDl(_exceptions, 1 << EXCP0E_PAGE))
+        return 2;
     return 1;
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     uint32_t pde_addr, pte_addr;
     uint32_t pde, pte, paddr, page_offset, page_size;
@@ -914,22 +925,22 @@
             sext = (int64_t)addr >> 47;
             if (sext != 0 && sext != -1)
                 return -1;
-            
-            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) & 
+
+            pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
                 env->a20_mask;
             pml4e = ldl_phys(pml4e_addr);
             if (!(pml4e & PG_PRESENT_MASK))
                 return -1;
-            
-            pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) & 
+
+            pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
                 env->a20_mask;
             pdpe = ldl_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK))
                 return -1;
-        } else 
+        } else
 #endif
         {
-            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) & 
+            pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
                 env->a20_mask;
             pdpe = ldl_phys(pdpe_addr);
             if (!(pdpe & PG_PRESENT_MASK))
@@ -959,9 +970,9 @@
             page_size = 4096;
         } else {
             /* page directory entry */
-            pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask;
+            pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask;
             pde = ldl_phys(pde_addr);
-            if (!(pde & PG_PRESENT_MASK)) 
+            if (!(pde & PG_PRESENT_MASK))
                 return -1;
             if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
                 pte = pde & ~0x003ff000; /* align to 4MB */
@@ -1004,7 +1015,7 @@
 {
     int fptag, i, j;
     struct fpstate fp1, *fp = &fp1;
-    
+
     fp->fpuc = env->fpuc;
     fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
     fptag = 0;
@@ -1025,7 +1036,7 @@
     asm volatile ("frstor %0" : "=m" (*fp));
     env->native_fp_regs = 1;
 }
- 
+
 void save_native_fp_state(CPUState *env)
 {
     int fptag, i, j;
diff --git a/target-i386/op.c b/target-i386/op.c
index a8cfce2..7d8950e 100644
--- a/target-i386/op.c
+++ b/target-i386/op.c
@@ -1,6 +1,6 @@
 /*
  *  i386 micro operations
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -513,15 +513,15 @@
 } UREG64;
 #endif
 
-#ifdef TARGET_X86_64
-
 #define PARAMQ1 \
 ({\
     UREG64 __p;\
     __p.l.v1 = PARAM1;\
     __p.l.v0 = PARAM2;\
     __p.q;\
-}) 
+})
+
+#ifdef TARGET_X86_64
 
 void OPPROTO op_movq_T0_im64(void)
 {
@@ -730,6 +730,11 @@
     helper_cmpxchg8b();
 }
 
+void OPPROTO op_single_step(void)
+{
+    helper_single_step();
+}
+
 void OPPROTO op_movl_T0_0(void)
 {
     T0 = 0;
@@ -1144,7 +1149,7 @@
 {
     int selector;
     SegmentCache *sc;
-    
+
     selector = T0 & 0xffff;
     /* env->segs[] access */
     sc = (SegmentCache *)((char *)env + PARAM1);
@@ -1188,14 +1193,14 @@
     }
     FORCE_RET();
 }
-            
+
 void OPPROTO op_arpl_update(void)
 {
     int eflags;
     eflags = cc_table[CC_OP].compute_all();
     CC_SRC = (eflags & ~CC_Z) | T1;
 }
-    
+
 /* T0: segment, T1:eip */
 void OPPROTO op_ljmp_protected_T0_T1(void)
 {
@@ -1237,13 +1242,53 @@
     helper_ltr_T0();
 }
 
-/* CR registers access */
+/* CR registers access. */
 void OPPROTO op_movl_crN_T0(void)
 {
     helper_movl_crN_T0(PARAM1);
 }
 
-#if !defined(CONFIG_USER_ONLY) 
+/* These pseudo-opcodes check for SVM intercepts. */
+void OPPROTO op_svm_check_intercept(void)
+{
+    A0 = PARAM1 & PARAM2;
+    svm_check_intercept(PARAMQ1);
+}
+
+void OPPROTO op_svm_check_intercept_param(void)
+{
+    A0 = PARAM1 & PARAM2;
+    svm_check_intercept_param(PARAMQ1, T1);
+}
+
+void OPPROTO op_svm_vmexit(void)
+{
+    A0 = PARAM1 & PARAM2;
+    vmexit(PARAMQ1, T1);
+}
+
+void OPPROTO op_geneflags(void)
+{
+    CC_SRC = cc_table[CC_OP].compute_all();
+}
+
+/* This pseudo-opcode checks for IO intercepts. */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_svm_check_intercept_io(void)
+{
+    A0 = PARAM1 & PARAM2;
+    /* PARAMQ1 = TYPE (0 = OUT, 1 = IN; 4 = STRING; 8 = REP)
+       T0      = PORT
+       T1      = next eip */
+    stq_phys(env->vm_vmcb + offsetof(struct vmcb, control.exit_info_2), T1);
+    /* ASIZE does not appear on real hw */
+    svm_check_intercept_param(SVM_EXIT_IOIO,
+                              (PARAMQ1 & ~SVM_IOIO_ASIZE_MASK) |
+                              ((T0 & 0xffff) << 16));
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
 void OPPROTO op_movtl_T0_cr8(void)
 {
     T0 = cpu_get_apic_tpr(env);
@@ -1586,23 +1631,23 @@
     [CC_OP_SUBB] = { compute_all_subb, compute_c_subb  },
     [CC_OP_SUBW] = { compute_all_subw, compute_c_subw  },
     [CC_OP_SUBL] = { compute_all_subl, compute_c_subl  },
-    
+
     [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb  },
     [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw  },
     [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl  },
-    
+
     [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb },
     [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw },
     [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl },
-    
+
     [CC_OP_INCB] = { compute_all_incb, compute_c_incl },
     [CC_OP_INCW] = { compute_all_incw, compute_c_incl },
     [CC_OP_INCL] = { compute_all_incl, compute_c_incl },
-    
+
     [CC_OP_DECB] = { compute_all_decb, compute_c_incl },
     [CC_OP_DECW] = { compute_all_decw, compute_c_incl },
     [CC_OP_DECL] = { compute_all_decl, compute_c_incl },
-    
+
     [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
     [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
     [CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
@@ -1619,11 +1664,11 @@
     [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq  },
 
     [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq  },
-    
+
     [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq  },
-    
+
     [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq },
-    
+
     [CC_OP_INCQ] = { compute_all_incq, compute_c_incl },
 
     [CC_OP_DECQ] = { compute_all_decq, compute_c_incl },
@@ -2447,3 +2492,45 @@
 
 #define SHIFT 1
 #include "ops_sse.h"
+
+/* Secure Virtual Machine ops */
+
+void OPPROTO op_vmrun(void)
+{
+    helper_vmrun(EAX);
+}
+
+void OPPROTO op_vmmcall(void)
+{
+    helper_vmmcall();
+}
+
+void OPPROTO op_vmload(void)
+{
+    helper_vmload(EAX);
+}
+
+void OPPROTO op_vmsave(void)
+{
+    helper_vmsave(EAX);
+}
+
+void OPPROTO op_stgi(void)
+{
+    helper_stgi();
+}
+
+void OPPROTO op_clgi(void)
+{
+    helper_clgi();
+}
+
+void OPPROTO op_skinit(void)
+{
+    helper_skinit();
+}
+
+void OPPROTO op_invlpga(void)
+{
+    helper_invlpga();
+}
diff --git a/target-i386/opreg_template.h b/target-i386/opreg_template.h
index 6480636..eae4139 100644
--- a/target-i386/opreg_template.h
+++ b/target-i386/opreg_template.h
@@ -1,7 +1,7 @@
 /*
  *  i386 micro operations (templates for various register related
  *  operations)
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h
index df1527c..82d1ec0 100644
--- a/target-i386/ops_sse.h
+++ b/target-i386/ops_sse.h
@@ -1,6 +1,6 @@
 /*
  *  MMX/SSE/SSE2/PNI support
- * 
+ *
  *  Copyright (c) 2005 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -1213,7 +1213,7 @@
 {
     Reg *d = (Reg *)((char *)env + PARAM1);
     int pos = PARAM2;
-    
+
     d->W(pos) = T0;
 }
 
@@ -1221,7 +1221,7 @@
 {
     Reg *s = (Reg *)((char *)env + PARAM1);
     int pos = PARAM2;
-    
+
     T0 = s->W(pos);
 }
 
diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h
index 373b77a..d1df07f 100644
--- a/target-i386/ops_template.h
+++ b/target-i386/ops_template.h
@@ -1,7 +1,7 @@
 /*
  *  i386 micro operations (included several times to generate
  *  different operand sizes)
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -239,7 +239,7 @@
     zf = ((DATA_TYPE)CC_DST == 0) << 6;
     sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
     /* of is defined if shift count == 1 */
-    of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O; 
+    of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
     return cf | pf | af | zf | sf | of;
 }
 
@@ -502,7 +502,7 @@
 {
     int count;
     target_long res;
-    
+
     res = T0 & DATA_MASK;
     if (res != 0) {
         count = 0;
diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h
index 9f72a8c..ae17d8e 100644
--- a/target-i386/ops_template_mem.h
+++ b/target-i386/ops_template_mem.h
@@ -1,7 +1,7 @@
 /*
  *  i386 micro operations (included several times to generate
  *  different operand sizes)
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -84,8 +84,8 @@
         /* gcc 3.2 workaround. This is really a bug in gcc. */
         asm volatile("" : : "r" (T0));
 #endif
-        CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) | 
-            (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | 
+        CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
+            (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
             (T0 & CC_C);
         CC_OP = CC_OP_EFLAGS;
     }
@@ -109,7 +109,7 @@
         asm volatile("" : : "r" (T0));
 #endif
         CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
-            (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | 
+            (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
             ((T0 >> (DATA_BITS - 1)) & CC_C);
         CC_OP = CC_OP_EFLAGS;
     }
@@ -168,7 +168,7 @@
         glue(st, MEM_SUFFIX)(A0, T0);
 #endif
         CC_SRC = (eflags & ~(CC_C | CC_O)) |
-            (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | 
+            (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
             ((src >> (DATA_BITS - count)) & CC_C);
         CC_OP = CC_OP_EFLAGS;
     }
@@ -199,7 +199,7 @@
         glue(st, MEM_SUFFIX)(A0, T0);
 #endif
         CC_SRC = (eflags & ~(CC_C | CC_O)) |
-            (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) | 
+            (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
             ((src >> (count - 1)) & CC_C);
         CC_OP = CC_OP_EFLAGS;
     }
diff --git a/target-i386/svm.h b/target-i386/svm.h
new file mode 100644
index 0000000..982d054
--- /dev/null
+++ b/target-i386/svm.h
@@ -0,0 +1,358 @@
+#ifndef __SVM_H
+#define __SVM_H
+
+enum {
+        /* We shift all the intercept bits so we can OR them with the
+           TB flags later on */
+	INTERCEPT_INTR = HF_HIF_SHIFT,
+	INTERCEPT_NMI,
+	INTERCEPT_SMI,
+	INTERCEPT_INIT,
+	INTERCEPT_VINTR,
+	INTERCEPT_SELECTIVE_CR0,
+	INTERCEPT_STORE_IDTR,
+	INTERCEPT_STORE_GDTR,
+	INTERCEPT_STORE_LDTR,
+	INTERCEPT_STORE_TR,
+	INTERCEPT_LOAD_IDTR,
+	INTERCEPT_LOAD_GDTR,
+	INTERCEPT_LOAD_LDTR,
+	INTERCEPT_LOAD_TR,
+	INTERCEPT_RDTSC,
+	INTERCEPT_RDPMC,
+	INTERCEPT_PUSHF,
+	INTERCEPT_POPF,
+	INTERCEPT_CPUID,
+	INTERCEPT_RSM,
+	INTERCEPT_IRET,
+	INTERCEPT_INTn,
+	INTERCEPT_INVD,
+	INTERCEPT_PAUSE,
+	INTERCEPT_HLT,
+	INTERCEPT_INVLPG,
+	INTERCEPT_INVLPGA,
+	INTERCEPT_IOIO_PROT,
+	INTERCEPT_MSR_PROT,
+	INTERCEPT_TASK_SWITCH,
+	INTERCEPT_FERR_FREEZE,
+	INTERCEPT_SHUTDOWN,
+	INTERCEPT_VMRUN,
+	INTERCEPT_VMMCALL,
+	INTERCEPT_VMLOAD,
+	INTERCEPT_VMSAVE,
+	INTERCEPT_STGI,
+	INTERCEPT_CLGI,
+	INTERCEPT_SKINIT,
+	INTERCEPT_RDTSCP,
+	INTERCEPT_ICEBP,
+	INTERCEPT_WBINVD,
+};
+/* This is not really an intercept but rather a placeholder to
+   show that we are in an SVM (just like a hidden flag, but keeps the
+   TBs clean) */
+#define INTERCEPT_SVM 63
+#define INTERCEPT_SVM_MASK (1ULL << INTERCEPT_SVM)
+
+struct __attribute__ ((__packed__)) vmcb_control_area {
+	uint16_t intercept_cr_read;
+	uint16_t intercept_cr_write;
+	uint16_t intercept_dr_read;
+	uint16_t intercept_dr_write;
+	uint32_t intercept_exceptions;
+	uint64_t intercept;
+	uint8_t reserved_1[44];
+	uint64_t iopm_base_pa;
+	uint64_t msrpm_base_pa;
+	uint64_t tsc_offset;
+	uint32_t asid;
+	uint8_t tlb_ctl;
+	uint8_t reserved_2[3];
+	uint32_t int_ctl;
+	uint32_t int_vector;
+	uint32_t int_state;
+	uint8_t reserved_3[4];
+	uint32_t exit_code;
+	uint32_t exit_code_hi;
+	uint64_t exit_info_1;
+	uint64_t exit_info_2;
+	uint32_t exit_int_info;
+	uint32_t exit_int_info_err;
+	uint64_t nested_ctl;
+	uint8_t reserved_4[16];
+	uint32_t event_inj;
+	uint32_t event_inj_err;
+	uint64_t nested_cr3;
+	uint64_t lbr_ctl;
+	uint8_t reserved_5[832];
+};
+
+
+#define TLB_CONTROL_DO_NOTHING 0
+#define TLB_CONTROL_FLUSH_ALL_ASID 1
+
+#define V_TPR_MASK 0x0f
+
+#define V_IRQ_SHIFT 8
+#define V_IRQ_MASK (1 << V_IRQ_SHIFT)
+
+#define V_INTR_PRIO_SHIFT 16
+#define V_INTR_PRIO_MASK (0x0f << V_INTR_PRIO_SHIFT)
+
+#define V_IGN_TPR_SHIFT 20
+#define V_IGN_TPR_MASK (1 << V_IGN_TPR_SHIFT)
+
+#define V_INTR_MASKING_SHIFT 24
+#define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
+
+#define SVM_INTERRUPT_SHADOW_MASK 1
+
+#define SVM_IOIO_STR_SHIFT 2
+#define SVM_IOIO_REP_SHIFT 3
+#define SVM_IOIO_SIZE_SHIFT 4
+#define SVM_IOIO_ASIZE_SHIFT 7
+
+#define SVM_IOIO_TYPE_MASK 1
+#define SVM_IOIO_STR_MASK (1 << SVM_IOIO_STR_SHIFT)
+#define SVM_IOIO_REP_MASK (1 << SVM_IOIO_REP_SHIFT)
+#define SVM_IOIO_SIZE_MASK (7 << SVM_IOIO_SIZE_SHIFT)
+#define SVM_IOIO_ASIZE_MASK (7 << SVM_IOIO_ASIZE_SHIFT)
+
+struct __attribute__ ((__packed__)) vmcb_seg {
+	uint16_t selector;
+	uint16_t attrib;
+	uint32_t limit;
+	uint64_t base;
+};
+
+struct __attribute__ ((__packed__)) vmcb_save_area {
+	struct vmcb_seg es;
+	struct vmcb_seg cs;
+	struct vmcb_seg ss;
+	struct vmcb_seg ds;
+	struct vmcb_seg fs;
+	struct vmcb_seg gs;
+	struct vmcb_seg gdtr;
+	struct vmcb_seg ldtr;
+	struct vmcb_seg idtr;
+	struct vmcb_seg tr;
+	uint8_t reserved_1[43];
+	uint8_t cpl;
+	uint8_t reserved_2[4];
+	uint64_t efer;
+	uint8_t reserved_3[112];
+	uint64_t cr4;
+	uint64_t cr3;
+	uint64_t cr0;
+	uint64_t dr7;
+	uint64_t dr6;
+	uint64_t rflags;
+	uint64_t rip;
+	uint8_t reserved_4[88];
+	uint64_t rsp;
+	uint8_t reserved_5[24];
+	uint64_t rax;
+	uint64_t star;
+	uint64_t lstar;
+	uint64_t cstar;
+	uint64_t sfmask;
+	uint64_t kernel_gs_base;
+	uint64_t sysenter_cs;
+	uint64_t sysenter_esp;
+	uint64_t sysenter_eip;
+	uint64_t cr2;
+	/* qemu: cr8 added to reuse this as hsave */
+	uint64_t cr8;
+	uint8_t reserved_6[32 - 8]; /* originally 32 */
+	uint64_t g_pat;
+	uint64_t dbgctl;
+	uint64_t br_from;
+	uint64_t br_to;
+	uint64_t last_excp_from;
+	uint64_t last_excp_to;
+};
+
+struct __attribute__ ((__packed__)) vmcb {
+	struct vmcb_control_area control;
+	struct vmcb_save_area save;
+};
+
+#define SVM_CPUID_FEATURE_SHIFT 2
+#define SVM_CPUID_FUNC 0x8000000a
+
+#define MSR_EFER_SVME_MASK (1ULL << 12)
+
+#define SVM_SELECTOR_S_SHIFT 4
+#define SVM_SELECTOR_DPL_SHIFT 5
+#define SVM_SELECTOR_P_SHIFT 7
+#define SVM_SELECTOR_AVL_SHIFT 8
+#define SVM_SELECTOR_L_SHIFT 9
+#define SVM_SELECTOR_DB_SHIFT 10
+#define SVM_SELECTOR_G_SHIFT 11
+
+#define SVM_SELECTOR_TYPE_MASK (0xf)
+#define SVM_SELECTOR_S_MASK (1 << SVM_SELECTOR_S_SHIFT)
+#define SVM_SELECTOR_DPL_MASK (3 << SVM_SELECTOR_DPL_SHIFT)
+#define SVM_SELECTOR_P_MASK (1 << SVM_SELECTOR_P_SHIFT)
+#define SVM_SELECTOR_AVL_MASK (1 << SVM_SELECTOR_AVL_SHIFT)
+#define SVM_SELECTOR_L_MASK (1 << SVM_SELECTOR_L_SHIFT)
+#define SVM_SELECTOR_DB_MASK (1 << SVM_SELECTOR_DB_SHIFT)
+#define SVM_SELECTOR_G_MASK (1 << SVM_SELECTOR_G_SHIFT)
+
+#define SVM_SELECTOR_WRITE_MASK (1 << 1)
+#define SVM_SELECTOR_READ_MASK SVM_SELECTOR_WRITE_MASK
+#define SVM_SELECTOR_CODE_MASK (1 << 3)
+
+#define INTERCEPT_CR0_MASK 1
+#define INTERCEPT_CR3_MASK (1 << 3)
+#define INTERCEPT_CR4_MASK (1 << 4)
+
+#define INTERCEPT_DR0_MASK 1
+#define INTERCEPT_DR1_MASK (1 << 1)
+#define INTERCEPT_DR2_MASK (1 << 2)
+#define INTERCEPT_DR3_MASK (1 << 3)
+#define INTERCEPT_DR4_MASK (1 << 4)
+#define INTERCEPT_DR5_MASK (1 << 5)
+#define INTERCEPT_DR6_MASK (1 << 6)
+#define INTERCEPT_DR7_MASK (1 << 7)
+
+#define SVM_EVTINJ_VEC_MASK 0xff
+
+#define SVM_EVTINJ_TYPE_SHIFT 8
+#define SVM_EVTINJ_TYPE_MASK (7 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT)
+#define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT)
+
+#define SVM_EVTINJ_VALID (1 << 31)
+#define SVM_EVTINJ_VALID_ERR (1 << 11)
+
+#define SVM_EXITINTINFO_VEC_MASK SVM_EVTINJ_VEC_MASK
+
+#define	SVM_EXITINTINFO_TYPE_INTR SVM_EVTINJ_TYPE_INTR
+#define	SVM_EXITINTINFO_TYPE_NMI SVM_EVTINJ_TYPE_NMI
+#define	SVM_EXITINTINFO_TYPE_EXEPT SVM_EVTINJ_TYPE_EXEPT
+#define	SVM_EXITINTINFO_TYPE_SOFT SVM_EVTINJ_TYPE_SOFT
+
+#define SVM_EXITINTINFO_VALID SVM_EVTINJ_VALID
+#define SVM_EXITINTINFO_VALID_ERR SVM_EVTINJ_VALID_ERR
+
+#define	SVM_EXIT_READ_CR0 	0x000
+#define	SVM_EXIT_READ_CR3 	0x003
+#define	SVM_EXIT_READ_CR4 	0x004
+#define	SVM_EXIT_READ_CR8 	0x008
+#define	SVM_EXIT_WRITE_CR0 	0x010
+#define	SVM_EXIT_WRITE_CR3 	0x013
+#define	SVM_EXIT_WRITE_CR4 	0x014
+#define	SVM_EXIT_WRITE_CR8 	0x018
+#define	SVM_EXIT_READ_DR0 	0x020
+#define	SVM_EXIT_READ_DR1 	0x021
+#define	SVM_EXIT_READ_DR2 	0x022
+#define	SVM_EXIT_READ_DR3 	0x023
+#define	SVM_EXIT_READ_DR4 	0x024
+#define	SVM_EXIT_READ_DR5 	0x025
+#define	SVM_EXIT_READ_DR6 	0x026
+#define	SVM_EXIT_READ_DR7 	0x027
+#define	SVM_EXIT_WRITE_DR0 	0x030
+#define	SVM_EXIT_WRITE_DR1 	0x031
+#define	SVM_EXIT_WRITE_DR2 	0x032
+#define	SVM_EXIT_WRITE_DR3 	0x033
+#define	SVM_EXIT_WRITE_DR4 	0x034
+#define	SVM_EXIT_WRITE_DR5 	0x035
+#define	SVM_EXIT_WRITE_DR6 	0x036
+#define	SVM_EXIT_WRITE_DR7 	0x037
+#define SVM_EXIT_EXCP_BASE      0x040
+#define SVM_EXIT_INTR		0x060
+#define SVM_EXIT_NMI		0x061
+#define SVM_EXIT_SMI		0x062
+#define SVM_EXIT_INIT		0x063
+#define SVM_EXIT_VINTR		0x064
+#define SVM_EXIT_CR0_SEL_WRITE	0x065
+#define SVM_EXIT_IDTR_READ	0x066
+#define SVM_EXIT_GDTR_READ	0x067
+#define SVM_EXIT_LDTR_READ	0x068
+#define SVM_EXIT_TR_READ	0x069
+#define SVM_EXIT_IDTR_WRITE	0x06a
+#define SVM_EXIT_GDTR_WRITE	0x06b
+#define SVM_EXIT_LDTR_WRITE	0x06c
+#define SVM_EXIT_TR_WRITE	0x06d
+#define SVM_EXIT_RDTSC		0x06e
+#define SVM_EXIT_RDPMC		0x06f
+#define SVM_EXIT_PUSHF		0x070
+#define SVM_EXIT_POPF		0x071
+#define SVM_EXIT_CPUID		0x072
+#define SVM_EXIT_RSM		0x073
+#define SVM_EXIT_IRET		0x074
+#define SVM_EXIT_SWINT		0x075
+#define SVM_EXIT_INVD		0x076
+#define SVM_EXIT_PAUSE		0x077
+#define SVM_EXIT_HLT		0x078
+#define SVM_EXIT_INVLPG		0x079
+#define SVM_EXIT_INVLPGA	0x07a
+#define SVM_EXIT_IOIO		0x07b
+#define SVM_EXIT_MSR		0x07c
+#define SVM_EXIT_TASK_SWITCH	0x07d
+#define SVM_EXIT_FERR_FREEZE	0x07e
+#define SVM_EXIT_SHUTDOWN	0x07f
+#define SVM_EXIT_VMRUN		0x080
+#define SVM_EXIT_VMMCALL	0x081
+#define SVM_EXIT_VMLOAD		0x082
+#define SVM_EXIT_VMSAVE		0x083
+#define SVM_EXIT_STGI		0x084
+#define SVM_EXIT_CLGI		0x085
+#define SVM_EXIT_SKINIT		0x086
+#define SVM_EXIT_RDTSCP		0x087
+#define SVM_EXIT_ICEBP		0x088
+#define SVM_EXIT_WBINVD		0x089
+/* only included in documentation, maybe wrong */
+#define SVM_EXIT_MONITOR	0x08a
+#define SVM_EXIT_MWAIT		0x08b
+#define SVM_EXIT_NPF  		0x400
+
+#define SVM_EXIT_ERR		-1
+
+#define SVM_CR0_SELECTIVE_MASK (1 << 3 | 1) /* TS and MP */
+
+#define SVM_VMLOAD ".byte 0x0f, 0x01, 0xda"
+#define SVM_VMRUN  ".byte 0x0f, 0x01, 0xd8"
+#define SVM_VMSAVE ".byte 0x0f, 0x01, 0xdb"
+#define SVM_CLGI   ".byte 0x0f, 0x01, 0xdd"
+#define SVM_STGI   ".byte 0x0f, 0x01, 0xdc"
+#define SVM_INVLPGA ".byte 0x0f, 0x01, 0xdf"
+
+/* function references */
+
+void helper_stgi();
+void vmexit(uint64_t exit_code, uint64_t exit_info_1);
+int svm_check_intercept_param(uint32_t type, uint64_t param);
+static inline int svm_check_intercept(unsigned int type) {
+    return svm_check_intercept_param(type, 0);
+}
+
+
+#define INTERCEPTED(mask) (env->intercept & mask)
+#define INTERCEPTEDw(var, mask) (env->intercept ## var & mask)
+#define INTERCEPTEDl(var, mask) (env->intercept ## var & mask)
+
+#define SVM_LOAD_SEG(addr, seg_index, seg) \
+    cpu_x86_load_seg_cache(env, \
+                    R_##seg_index, \
+                    lduw_phys(addr + offsetof(struct vmcb, save.seg.selector)),\
+                    ldq_phys(addr + offsetof(struct vmcb, save.seg.base)),\
+                    ldl_phys(addr + offsetof(struct vmcb, save.seg.limit)),\
+                    vmcb2cpu_attrib(lduw_phys(addr + offsetof(struct vmcb, save.seg.attrib)), ldq_phys(addr + offsetof(struct vmcb, save.seg.base)), ldl_phys(addr + offsetof(struct vmcb, save.seg.limit))))
+
+#define SVM_LOAD_SEG2(addr, seg_qemu, seg_vmcb) \
+    env->seg_qemu.selector  = lduw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.selector)); \
+    env->seg_qemu.base      = ldq_phys(addr + offsetof(struct vmcb, save.seg_vmcb.base)); \
+    env->seg_qemu.limit     = ldl_phys(addr + offsetof(struct vmcb, save.seg_vmcb.limit)); \
+    env->seg_qemu.flags     = vmcb2cpu_attrib(lduw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.attrib)), env->seg_qemu.base, env->seg_qemu.limit)
+
+#define SVM_SAVE_SEG(addr, seg_qemu, seg_vmcb) \
+    stw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.selector), env->seg_qemu.selector); \
+    stq_phys(addr + offsetof(struct vmcb, save.seg_vmcb.base), env->seg_qemu.base); \
+    stl_phys(addr + offsetof(struct vmcb, save.seg_vmcb.limit), env->seg_qemu.limit); \
+    stw_phys(addr + offsetof(struct vmcb, save.seg_vmcb.attrib), cpu2vmcb_attrib(env->seg_qemu.flags))
+
+#endif
diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c
index cf8bd5a..d687643 100644
--- a/target-i386/translate-copy.c
+++ b/target-i386/translate-copy.c
@@ -1,6 +1,6 @@
 /*
  *  i386 on i386 translation
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -42,7 +42,7 @@
 enum {
     OT_BYTE = 0,
     OT_WORD,
-    OT_LONG, 
+    OT_LONG,
     OT_QUAD,
 };
 
@@ -63,7 +63,7 @@
     /* code output */
     uint8_t *gen_code_ptr;
     uint8_t *gen_code_start;
-    
+
     /* current block context */
     target_ulong cs_base; /* base of CS segment */
     int pe;     /* protected mode */
@@ -105,22 +105,22 @@
     gl(s, val - (long)(s->gen_code_ptr + 4));
 }
 
-static inline void gen_movl_addr_im(DisasContext *s, 
+static inline void gen_movl_addr_im(DisasContext *s,
                                     uint32_t addr, uint32_t val)
 {
     gb(s, CPU_SEG); /* seg movl im, addr */
-    gb(s, 0xc7); 
+    gb(s, 0xc7);
     gb(s, 0x05);
     gl(s, addr);
     gl(s, val);
 }
 
-static inline void gen_movw_addr_im(DisasContext *s, 
+static inline void gen_movw_addr_im(DisasContext *s,
                                     uint32_t addr, uint32_t val)
 {
     gb(s, CPU_SEG); /* seg movl im, addr */
-    gb(s, 0x66); 
-    gb(s, 0xc7); 
+    gb(s, 0x66);
+    gb(s, 0xc7);
     gb(s, 0x05);
     gl(s, addr);
     gw(s, val);
@@ -155,7 +155,7 @@
     gb(s, 0xe9); /* jmp */
     tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start;
     gl(s, 0);
-    
+
     tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
     gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
     gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
@@ -194,7 +194,7 @@
         base = rm;
         index = 0;
         scale = 0;
-        
+
         if (base == 4) {
             havesib = 1;
             code = ldub_code(s->pc++);
@@ -222,7 +222,7 @@
             s->pc += 4;
             break;
         }
-        
+
     } else {
         switch (mod) {
         case 0:
@@ -248,7 +248,7 @@
 static inline void parse_modrm(DisasContext *s, int modrm)
 {
     if ((modrm & 0xc0) != 0xc0)
-        gen_lea_modrm(s, modrm);        
+        gen_lea_modrm(s, modrm);
 }
 
 static inline uint32_t insn_get(DisasContext *s, int ot)
@@ -351,7 +351,7 @@
         /* extended op code */
         b = ldub_code(s->pc++) | 0x100;
         goto reswitch;
-        
+
         /**************************/
         /* arith & logic */
     case 0x00 ... 0x05:
@@ -370,7 +370,7 @@
                 ot = OT_BYTE;
             else
                 ot = dflag ? OT_LONG : OT_WORD;
-            
+
             switch(f) {
             case 0: /* OP Ev, Gv */
                 modrm = ldub_code(s->pc++);
@@ -396,7 +396,7 @@
                 ot = OT_BYTE;
             else
                 ot = dflag ? OT_LONG : OT_WORD;
-            
+
             modrm = ldub_code(s->pc++);
             parse_modrm(s, modrm);
 
@@ -475,8 +475,8 @@
             break;
         case 2: /* call Ev */
             /* XXX: optimize and handle MEM exceptions specifically
-               fs movl %eax, regs[0] 
-               movl Ev, %eax 
+               fs movl %eax, regs[0]
+               movl Ev, %eax
                pushl next_eip
                fs movl %eax, eip
             */
@@ -485,8 +485,8 @@
             goto unsupported_op;
         case 4: /* jmp Ev */
             /* XXX: optimize and handle MEM exceptions specifically
-               fs movl %eax, regs[0] 
-               movl Ev, %eax 
+               fs movl %eax, regs[0]
+               movl Ev, %eax
                fs movl %eax, eip
             */
             goto unsupported_op;
@@ -506,7 +506,7 @@
             ot = dflag ? OT_LONG : OT_WORD;
         insn_get(s, ot);
         break;
-        
+
     case 0x98: /* CWDE/CBW */
         break;
     case 0x99: /* CDQ/CWD */
@@ -526,8 +526,8 @@
         break;
 
     case 0x84: /* test Ev, Gv */
-    case 0x85: 
-        
+    case 0x85:
+
     case 0x1c0:
     case 0x1c1: /* xadd Ev, Gv */
 
@@ -583,7 +583,7 @@
             goto illegal_op;
         parse_modrm(s, modrm);
         break;
-        
+
         /**************************/
         /* push/pop */
     case 0x50 ... 0x57: /* push */
@@ -654,7 +654,7 @@
         goto unsupported_op;
         /************************/
         /* floats */
-    case 0xd8 ... 0xdf: 
+    case 0xd8 ... 0xdf:
 #if 1
         /* currently not stable enough */
         goto unsupported_op;
@@ -850,7 +850,7 @@
             goto illegal_op;
         parse_modrm(s, modrm);
         break;
-        
+
     case 0xa0: /* mov EAX, Ov */
     case 0xa1:
     case 0xa2: /* mov Ov, EAX */
@@ -888,14 +888,14 @@
         parse_modrm(s, modrm);
         ldub_code(s->pc++);
         break;
-        
+
         /************************/
         /* string ops */
 
     case 0xa4: /* movsS */
     case 0xa5:
         break;
-        
+
     case 0xaa: /* stosS */
     case 0xab:
         break;
@@ -955,7 +955,7 @@
 
     case 0xc3: /* ret */
         gb(s, CPU_SEG);
-        if (!s->dflag)  
+        if (!s->dflag)
             gb(s, 0x66); /* d16 */
         gb(s, 0x8f); /* pop addr */
         gb(s, 0x05);
@@ -1011,7 +1011,7 @@
         if (dflag) {
             val = insn_get(s, OT_LONG);
         } else {
-            val = (int16_t)insn_get(s, OT_WORD); 
+            val = (int16_t)insn_get(s, OT_WORD);
         }
     do_jcc:
         next_eip = s->pc - s->cs_base;
@@ -1071,7 +1071,7 @@
     case 0x90: /* nop */
         break;
     case 0x9b: /* fwait */
-        if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == 
+        if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
             (HF_MP_MASK | HF_TS_MASK)) {
             goto unsupported_op;
         }
@@ -1171,7 +1171,7 @@
 #define GEN_CODE_MAX_INSN_SIZE 512
 
 static inline int gen_intermediate_code_internal(CPUState *env,
-                                                 TranslationBlock *tb, 
+                                                 TranslationBlock *tb,
                                                  uint8_t *gen_code_ptr,
                                                  int *gen_code_size_ptr,
                                                  int search_pc,
@@ -1186,14 +1186,14 @@
         env->singlestep_enabled)
         return -1;
     flags = tb->flags;
-    if (flags & (HF_TF_MASK | HF_ADDSEG_MASK | 
+    if (flags & (HF_TF_MASK | HF_ADDSEG_MASK |
                  HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK))
         return -1;
     if (!(flags & HF_SS32_MASK))
         return -1;
     if (tb->cflags & CF_SINGLE_INSN)
         return -1;
-    gen_code_end = gen_code_ptr + 
+    gen_code_end = gen_code_ptr +
         GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE;
     dc->gen_code_ptr = gen_code_ptr;
     dc->gen_code_start = gen_code_ptr;
@@ -1244,11 +1244,11 @@
             break;
         }
     }
-    
+
 #ifdef DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
         fprintf(logfile, "----------------\n");
-        fprintf(logfile, "IN: COPY: %s fpu=%d\n", 
+        fprintf(logfile, "IN: COPY: %s fpu=%d\n",
                 lookup_symbol(pc_start),
                 tb->cflags & CF_TB_FP_USED ? 1 : 0);
 	target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32);
@@ -1279,14 +1279,14 @@
     tb->tb_jmp_offset[2] = 0xffff;
     tb->tb_jmp_offset[3] = 0xffff;
 #endif
-    return gen_intermediate_code_internal(env, tb, 
+    return gen_intermediate_code_internal(env, tb,
                                           tb->tc_ptr, gen_code_size_ptr,
                                           0, NULL);
 }
 
 static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE];
 
-int cpu_restore_state_copy(TranslationBlock *tb, 
+int cpu_restore_state_copy(TranslationBlock *tb,
                            CPUState *env, unsigned long searched_pc,
                            void *puc)
 {
@@ -1297,14 +1297,14 @@
     if (searched_pc < (unsigned long)tb->tc_ptr)
         return -1;
     searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf;
-    ret = gen_intermediate_code_internal(env, tb, 
+    ret = gen_intermediate_code_internal(env, tb,
                                          dummy_gen_code_buf, NULL,
                                          1, (uint8_t *)searched_pc);
     if (ret < 0)
         return ret;
     /* restore all the CPU state from the CPU context from the
        signal. The FPU context stays in the host CPU. */
-    
+
     env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX];
     env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX];
     env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX];
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 735acb0..cd95412 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -1,6 +1,6 @@
 /*
  *  i386 translation
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -95,7 +95,7 @@
     int singlestep_enabled; /* "hardware" single step enabled */
     int jmp_opt; /* use direct block chaining for direct jumps */
     int mem_index; /* select memory access functions */
-    int flags; /* all execution flags */
+    uint64_t flags; /* all execution flags */
     struct TranslationBlock *tb;
     int popl_esp_hack; /* for correct popl with esp base handling */
     int rip_offset; /* only used in x86_64, but left for simplicity */
@@ -109,24 +109,24 @@
 
 /* i386 arith/logic operations */
 enum {
-    OP_ADDL, 
-    OP_ORL, 
-    OP_ADCL, 
+    OP_ADDL,
+    OP_ORL,
+    OP_ADCL,
     OP_SBBL,
-    OP_ANDL, 
-    OP_SUBL, 
-    OP_XORL, 
+    OP_ANDL,
+    OP_SUBL,
+    OP_XORL,
     OP_CMPL,
 };
 
 /* i386 shift ops */
 enum {
-    OP_ROL, 
-    OP_ROR, 
-    OP_RCL, 
-    OP_RCR, 
-    OP_SHL, 
-    OP_SHR, 
+    OP_ROL,
+    OP_ROR,
+    OP_RCL,
+    OP_RCR,
+    OP_SHL,
+    OP_SHR,
     OP_SHL1, /* undocumented */
     OP_SAR = 7,
 };
@@ -144,7 +144,7 @@
 enum {
     OT_BYTE = 0,
     OT_WORD,
-    OT_LONG, 
+    OT_LONG,
     OT_QUAD,
 };
 
@@ -333,7 +333,7 @@
 #endif
 };
 
-static GenOpFunc *gen_op_mov_TN_reg[NB_OP_SIZES][2][CPU_NB_REGS] = 
+static GenOpFunc *gen_op_mov_TN_reg[NB_OP_SIZES][2][CPU_NB_REGS] =
 {
     [OT_BYTE] = {
         {
@@ -878,7 +878,7 @@
     gen_op_jnz_ecxl,
     X86_64_ONLY(gen_op_jnz_ecxq),
 };
-    
+
 static GenOpFunc1 *gen_op_jz_ecx[3] = {
     gen_op_jz_ecxw,
     gen_op_jz_ecxl,
@@ -966,7 +966,7 @@
     if (s->aflag == 2) {
         gen_op_addq_ESI_T0();
         gen_op_addq_EDI_T0();
-    } else 
+    } else
 #endif
     if (s->aflag) {
         gen_op_addl_ESI_T0();
@@ -1009,7 +1009,7 @@
 #ifdef TARGET_X86_64
     if (s->aflag == 2) {
         gen_op_addq_EDI_T0();
-    } else 
+    } else
 #endif
     if (s->aflag) {
         gen_op_addl_EDI_T0();
@@ -1027,7 +1027,7 @@
 #ifdef TARGET_X86_64
     if (s->aflag == 2) {
         gen_op_addq_ESI_T0();
-    } else 
+    } else
 #endif
     if (s->aflag) {
         gen_op_addl_ESI_T0();
@@ -1046,7 +1046,7 @@
 #ifdef TARGET_X86_64
     if (s->aflag == 2) {
         gen_op_addq_EDI_T0();
-    } else 
+    } else
 #endif
     if (s->aflag) {
         gen_op_addl_EDI_T0();
@@ -1067,7 +1067,7 @@
     if (s->aflag == 2) {
         gen_op_addq_ESI_T0();
         gen_op_addq_EDI_T0();
-    } else 
+    } else
 #endif
     if (s->aflag) {
         gen_op_addl_ESI_T0();
@@ -1089,7 +1089,7 @@
 #ifdef TARGET_X86_64
     if (s->aflag == 2) {
         gen_op_addq_EDI_T0();
-    } else 
+    } else
 #endif
     if (s->aflag) {
         gen_op_addl_EDI_T0();
@@ -1107,7 +1107,7 @@
 #ifdef TARGET_X86_64
     if (s->aflag == 2) {
         gen_op_addq_ESI_T0();
-    } else 
+    } else
 #endif
     if (s->aflag) {
         gen_op_addl_ESI_T0();
@@ -1318,7 +1318,7 @@
 static void gen_op(DisasContext *s1, int op, int ot, int d)
 {
     GenOpFunc *gen_update_cc;
-    
+
     if (d != OR_TMP0) {
         gen_op_mov_TN_reg[ot][0][d]();
     } else {
@@ -1408,7 +1408,7 @@
     /* for zero counts, flags are not updated, so must do it dynamically */
     if (s1->cc_op != CC_OP_DYNAMIC)
         gen_op_set_cc_op(s1->cc_op);
-    
+
     if (d != OR_TMP0)
         gen_op_shift_T0_T1_cc[ot][op]();
     else
@@ -1448,7 +1448,7 @@
         base = rm;
         index = 0;
         scale = 0;
-        
+
         if (base == 4) {
             havesib = 1;
             code = ldub_code(s->pc++);
@@ -1480,7 +1480,7 @@
             s->pc += 4;
             break;
         }
-        
+
         if (base >= 0) {
             /* for correct popl handling with esp */
             if (base == 4 && s->popl_esp_hack)
@@ -1494,7 +1494,7 @@
                     else
                         gen_op_addq_A0_im64(disp >> 32, disp);
                 }
-            } else 
+            } else
 #endif
             {
                 gen_op_movl_A0_reg[base]();
@@ -1508,7 +1508,7 @@
                     gen_op_movq_A0_im(disp);
                 else
                     gen_op_movq_A0_im64(disp >> 32, disp);
-            } else 
+            } else
 #endif
             {
                 gen_op_movl_A0_im(disp);
@@ -1519,7 +1519,7 @@
 #ifdef TARGET_X86_64
             if (s->aflag == 2) {
                 gen_op_addq_A0_reg_sN[scale][index]();
-            } else 
+            } else
 #endif
             {
                 gen_op_addl_A0_reg_sN[scale][index]();
@@ -1535,7 +1535,7 @@
 #ifdef TARGET_X86_64
             if (s->aflag == 2) {
                 gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base));
-            } else 
+            } else
 #endif
             {
                 gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
@@ -1627,12 +1627,12 @@
     if (s->aflag) {
 
         base = rm;
-        
+
         if (base == 4) {
             code = ldub_code(s->pc++);
             base = (code & 7);
         }
-        
+
         switch (mod) {
         case 0:
             if (base == 5) {
@@ -1681,7 +1681,7 @@
 #ifdef TARGET_X86_64
         if (CODE64(s)) {
             gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base));
-        } else 
+        } else
 #endif
         {
             gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
@@ -1776,7 +1776,7 @@
     }
 }
 
-static inline void gen_jcc(DisasContext *s, int b, 
+static inline void gen_jcc(DisasContext *s, int b,
                            target_ulong val, target_ulong next_eip)
 {
     TranslationBlock *tb;
@@ -1787,7 +1787,7 @@
 
     inv = b & 1;
     jcc_op = (b >> 1) & 7;
-    
+
     if (s->jmp_opt) {
         switch(s->cc_op) {
             /* we optimize the cmp/jcc case */
@@ -1797,7 +1797,7 @@
         case CC_OP_SUBQ:
             func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
             break;
-            
+
             /* some jumps are easy to compute */
         case CC_OP_ADDB:
         case CC_OP_ADDW:
@@ -1864,7 +1864,7 @@
             gen_setcc_slow[jcc_op]();
             func = gen_op_jnz_T0_label;
         }
-    
+
         if (inv) {
             tmp = val;
             val = next_eip;
@@ -1922,7 +1922,7 @@
         if (!func)
             goto slow_jcc;
         break;
-        
+
         /* some jumps are easy to compute */
     case CC_OP_ADDB:
     case CC_OP_ADDW:
@@ -1995,13 +1995,105 @@
     }
 }
 
+#ifdef TARGET_X86_64
+#define SVM_movq_T1_im(x) gen_op_movq_T1_im64((x) >> 32, x)
+#else
+#define SVM_movq_T1_im(x) gen_op_movl_T1_im(x)
+#endif
+
+static inline int
+gen_svm_check_io(DisasContext *s, target_ulong pc_start, uint64_t type)
+{
+#if !defined(CONFIG_USER_ONLY)
+    if(s->flags & (1ULL << INTERCEPT_IOIO_PROT)) {
+        if (s->cc_op != CC_OP_DYNAMIC)
+            gen_op_set_cc_op(s->cc_op);
+        SVM_movq_T1_im(s->pc - s->cs_base);
+        gen_jmp_im(pc_start - s->cs_base);
+        gen_op_geneflags();
+        gen_op_svm_check_intercept_io((uint32_t)(type >> 32), (uint32_t)type);
+        s->cc_op = CC_OP_DYNAMIC;
+        /* FIXME: maybe we could move the io intercept vector to the TB as well
+                  so we know if this is an EOB or not ... let's assume it's not
+                  for now. */
+    }
+#endif
+    return 0;
+}
+
+static inline int svm_is_rep(int prefixes)
+{
+    return ((prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) ? 8 : 0);
+}
+
+static inline int
+gen_svm_check_intercept_param(DisasContext *s, target_ulong pc_start,
+                              uint64_t type, uint64_t param)
+{
+    if(!(s->flags & (INTERCEPT_SVM_MASK)))
+	/* no SVM activated */
+        return 0;
+    switch(type) {
+        /* CRx and DRx reads/writes */
+        case SVM_EXIT_READ_CR0 ... SVM_EXIT_EXCP_BASE - 1:
+            if (s->cc_op != CC_OP_DYNAMIC) {
+                gen_op_set_cc_op(s->cc_op);
+                s->cc_op = CC_OP_DYNAMIC;
+            }
+            gen_jmp_im(pc_start - s->cs_base);
+            SVM_movq_T1_im(param);
+            gen_op_geneflags();
+            gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type);
+            /* this is a special case as we do not know if the interception occurs
+               so we assume there was none */
+            return 0;
+        case SVM_EXIT_MSR:
+            if(s->flags & (1ULL << INTERCEPT_MSR_PROT)) {
+                if (s->cc_op != CC_OP_DYNAMIC) {
+                    gen_op_set_cc_op(s->cc_op);
+                    s->cc_op = CC_OP_DYNAMIC;
+                }
+                gen_jmp_im(pc_start - s->cs_base);
+                SVM_movq_T1_im(param);
+                gen_op_geneflags();
+                gen_op_svm_check_intercept_param((uint32_t)(type >> 32), (uint32_t)type);
+                /* this is a special case as we do not know if the interception occurs
+                   so we assume there was none */
+                return 0;
+            }
+            break;
+        default:
+            if(s->flags & (1ULL << ((type - SVM_EXIT_INTR) + INTERCEPT_INTR))) {
+                if (s->cc_op != CC_OP_DYNAMIC) {
+                    gen_op_set_cc_op(s->cc_op);
+		    s->cc_op = CC_OP_EFLAGS;
+                }
+                gen_jmp_im(pc_start - s->cs_base);
+                SVM_movq_T1_im(param);
+                gen_op_geneflags();
+                gen_op_svm_vmexit(type >> 32, type);
+                /* we can optimize this one so TBs don't get longer
+                   than up to vmexit */
+                gen_eob(s);
+                return 1;
+            }
+    }
+    return 0;
+}
+
+static inline int
+gen_svm_check_intercept(DisasContext *s, target_ulong pc_start, uint64_t type)
+{
+    return gen_svm_check_intercept_param(s, pc_start, type, 0);
+}
+
 static inline void gen_stack_update(DisasContext *s, int addend)
 {
 #ifdef TARGET_X86_64
     if (CODE64(s)) {
         if (addend == 8)
             gen_op_addq_ESP_8();
-        else 
+        else
             gen_op_addq_ESP_im(addend);
     } else
 #endif
@@ -2010,7 +2102,7 @@
             gen_op_addl_ESP_2();
         else if (addend == 4)
             gen_op_addl_ESP_4();
-        else 
+        else
             gen_op_addl_ESP_im(addend);
     } else {
         if (addend == 2)
@@ -2036,7 +2128,7 @@
             gen_op_st_T0_A0[OT_WORD + s->mem_index]();
         }
         gen_op_movq_ESP_A0();
-    } else 
+    } else
 #endif
     {
         gen_op_movl_A0_reg[R_ESP]();
@@ -2077,7 +2169,7 @@
             gen_op_st_T0_A0[OT_WORD + s->mem_index]();
         }
         gen_op_movq_ESP_A0();
-    } else 
+    } else
 #endif
     {
         gen_op_movl_A0_reg[R_ESP]();
@@ -2094,7 +2186,7 @@
             gen_op_addl_A0_SS();
         }
         gen_op_st_T1_A0[s->dflag + 1 + s->mem_index]();
-        
+
         if (s->ss32 && !s->addseg)
             gen_op_movl_ESP_A0();
         else
@@ -2109,7 +2201,7 @@
     if (CODE64(s)) {
         gen_op_movq_A0_reg[R_ESP]();
         gen_op_ld_T0_A0[(s->dflag ? OT_QUAD : OT_WORD) + s->mem_index]();
-    } else 
+    } else
 #endif
     {
         gen_op_movl_A0_reg[R_ESP]();
@@ -2196,7 +2288,7 @@
     if (CODE64(s)) {
         ot = s->dflag ? OT_QUAD : OT_WORD;
         opsize = 1 << ot;
-        
+
         gen_op_movl_A0_ESP();
         gen_op_addq_A0_im(-opsize);
         gen_op_movl_T1_A0();
@@ -2210,12 +2302,12 @@
         gen_op_mov_reg_T1[ot][R_EBP]();
         gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
         gen_op_mov_reg_T1[OT_QUAD][R_ESP]();
-    } else 
+    } else
 #endif
     {
         ot = s->dflag + OT_WORD;
         opsize = 2 << s->dflag;
-        
+
         gen_op_movl_A0_ESP();
         gen_op_addl_A0_im(-opsize);
         if (!s->ss32)
@@ -2245,8 +2337,8 @@
 }
 
 /* an interrupt is different from an exception because of the
-   priviledge checks */
-static void gen_interrupt(DisasContext *s, int intno, 
+   privilege checks */
+static void gen_interrupt(DisasContext *s, int intno,
                           target_ulong cur_eip, target_ulong next_eip)
 {
     if (s->cc_op != CC_OP_DYNAMIC)
@@ -2277,7 +2369,7 @@
     if (s->singlestep_enabled) {
         gen_op_debug();
     } else if (s->tf) {
-        gen_op_raise_exception(EXCP01_SSTP);
+	gen_op_single_step();
     } else {
         gen_op_movl_T0_0();
         gen_op_exit_tb();
@@ -2309,7 +2401,7 @@
 
 static void gen_movtl_T0_im(target_ulong val)
 {
-#ifdef TARGET_X86_64    
+#ifdef TARGET_X86_64
     if ((int32_t)val == val) {
         gen_op_movl_T0_im(val);
     } else {
@@ -2322,7 +2414,7 @@
 
 static void gen_movtl_T1_im(target_ulong val)
 {
-#ifdef TARGET_X86_64    
+#ifdef TARGET_X86_64
     if ((int32_t)val == val) {
         gen_op_movl_T1_im(val);
     } else {
@@ -2410,7 +2502,7 @@
     [0x57] = { gen_op_pxor_xmm, gen_op_pxor_xmm }, /* xorps, xorpd */
     [0x58] = SSE_FOP(add),
     [0x59] = SSE_FOP(mul),
-    [0x5a] = { gen_op_cvtps2pd, gen_op_cvtpd2ps, 
+    [0x5a] = { gen_op_cvtps2pd, gen_op_cvtpd2ps,
                gen_op_cvtss2sd, gen_op_cvtsd2ss },
     [0x5b] = { gen_op_cvtdq2ps, gen_op_cvtps2dq, gen_op_cvttps2dq },
     [0x5c] = SSE_FOP(sub),
@@ -2438,9 +2530,9 @@
     [0x6d] = { NULL, gen_op_punpckhqdq_xmm },
     [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */
     [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */
-    [0x70] = { (GenOpFunc2 *)gen_op_pshufw_mmx, 
-               (GenOpFunc2 *)gen_op_pshufd_xmm, 
-               (GenOpFunc2 *)gen_op_pshufhw_xmm, 
+    [0x70] = { (GenOpFunc2 *)gen_op_pshufw_mmx,
+               (GenOpFunc2 *)gen_op_pshufd_xmm,
+               (GenOpFunc2 *)gen_op_pshufhw_xmm,
                (GenOpFunc2 *)gen_op_pshuflw_xmm },
     [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */
     [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */
@@ -2522,7 +2614,7 @@
     gen_op_cvtsi2sd,
     X86_64_ONLY(gen_op_cvtsq2ss),
     X86_64_ONLY(gen_op_cvtsq2sd),
-    
+
     gen_op_cvttss2si,
     gen_op_cvttsd2si,
     X86_64_ONLY(gen_op_cvttss2sq),
@@ -2533,7 +2625,7 @@
     X86_64_ONLY(gen_op_cvtss2sq),
     X86_64_ONLY(gen_op_cvtsd2sq),
 };
-    
+
 static GenOpFunc2 *sse_op_table4[8][4] = {
     SSE_FOP(cmpeq),
     SSE_FOP(cmplt),
@@ -2544,7 +2636,7 @@
     SSE_FOP(cmpnle),
     SSE_FOP(cmpord),
 };
-    
+
 static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
 {
     int b1, op1_offset, op2_offset, is_xmm, val, ot;
@@ -2553,16 +2645,16 @@
     GenOpFunc3 *sse_op3;
 
     b &= 0xff;
-    if (s->prefix & PREFIX_DATA) 
+    if (s->prefix & PREFIX_DATA)
         b1 = 1;
-    else if (s->prefix & PREFIX_REPZ) 
+    else if (s->prefix & PREFIX_REPZ)
         b1 = 2;
-    else if (s->prefix & PREFIX_REPNZ) 
+    else if (s->prefix & PREFIX_REPNZ)
         b1 = 3;
     else
         b1 = 0;
     sse_op2 = sse_op_table1[b][b1];
-    if (!sse_op2) 
+    if (!sse_op2)
         goto illegal_op;
     if (b <= 0x5f || b == 0xc6 || b == 0xc2) {
         is_xmm = 1;
@@ -2606,7 +2698,7 @@
         b |= (b1 << 8);
         switch(b) {
         case 0x0e7: /* movntq */
-            if (mod == 3) 
+            if (mod == 3)
                 goto illegal_op;
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
             gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx));
@@ -2625,7 +2717,7 @@
             if (s->dflag == 2) {
                 gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
                 gen_op_movq_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
-            } else 
+            } else
 #endif
             {
                 gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
@@ -2637,7 +2729,7 @@
             if (s->dflag == 2) {
                 gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
                 gen_op_movq_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg]));
-            } else 
+            } else
 #endif
             {
                 gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
@@ -2770,7 +2862,7 @@
             if (s->dflag == 2) {
                 gen_op_movq_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
                 gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
-            } else 
+            } else
 #endif
             {
                 gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
@@ -2782,7 +2874,7 @@
             if (s->dflag == 2) {
                 gen_op_movq_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg]));
                 gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
-            } else 
+            } else
 #endif
             {
                 gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg]));
@@ -2982,12 +3074,12 @@
                 rm = (modrm & 7) | REX_B(s);
                 op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
             }
-            sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 + 
+            sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 +
                           (b & 1) * 4](op2_offset);
             gen_op_mov_reg_T0[ot][reg]();
             break;
         case 0xc4: /* pinsrw */
-        case 0x1c4: 
+        case 0x1c4:
             s->rip_offset = 1;
             gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
             val = ldub_code(s->pc++);
@@ -3000,7 +3092,7 @@
             }
             break;
         case 0xc5: /* pextrw */
-        case 0x1c5: 
+        case 0x1c5:
             if (mod != 3)
                 goto illegal_op;
             val = ldub_code(s->pc++);
@@ -3062,12 +3154,12 @@
         switch(b) {
         case 0xf7:
             /* maskmov : we must prepare A0 */
-            if (mod != 3) 
+            if (mod != 3)
                 goto illegal_op;
 #ifdef TARGET_X86_64
             if (s->aflag == 2) {
                 gen_op_movq_A0_reg[R_EDI]();
-            } else 
+            } else
 #endif
             {
                 gen_op_movl_A0_reg[R_EDI]();
@@ -3164,7 +3256,7 @@
 #ifdef TARGET_X86_64
     s->rex_x = 0;
     s->rex_b = 0;
-    x86_64_hregs = 0; 
+    x86_64_hregs = 0;
 #endif
     s->rip_offset = 0; /* for relative ip address */
  next_byte:
@@ -3225,7 +3317,7 @@
         }
         if (!(prefixes & PREFIX_ADR))
             aflag = 2;
-    } else 
+    } else
 #endif
     {
         switch (b) {
@@ -3285,7 +3377,7 @@
         /* extended op code */
         b = ldub_code(s->pc++) | 0x100;
         goto reswitch;
-        
+
         /**************************/
         /* arith & logic */
     case 0x00 ... 0x05:
@@ -3305,7 +3397,7 @@
                 ot = OT_BYTE;
             else
                 ot = dflag + OT_WORD;
-            
+
             switch(f) {
             case 0: /* OP Ev, Gv */
                 modrm = ldub_code(s->pc++);
@@ -3364,12 +3456,12 @@
                 ot = OT_BYTE;
             else
                 ot = dflag + OT_WORD;
-            
+
             modrm = ldub_code(s->pc++);
             mod = (modrm >> 6) & 3;
             rm = (modrm & 7) | REX_B(s);
             op = (modrm >> 3) & 7;
-            
+
             if (mod != 3) {
                 if (b == 0x83)
                     s->rip_offset = 1;
@@ -3656,7 +3748,7 @@
         break;
 
     case 0x84: /* test Ev, Gv */
-    case 0x85: 
+    case 0x85:
         if ((b & 1) == 0)
             ot = OT_BYTE;
         else
@@ -3666,13 +3758,13 @@
         mod = (modrm >> 6) & 3;
         rm = (modrm & 7) | REX_B(s);
         reg = ((modrm >> 3) & 7) | rex_r;
-        
+
         gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
         gen_op_mov_TN_reg[ot][1][reg]();
         gen_op_testl_T0_T1_cc();
         s->cc_op = CC_OP_LOGICB + ot;
         break;
-        
+
     case 0xa8: /* test eAX, Iv */
     case 0xa9:
         if ((b & 1) == 0)
@@ -3686,7 +3778,7 @@
         gen_op_testl_T0_T1_cc();
         s->cc_op = CC_OP_LOGICB + ot;
         break;
-        
+
     case 0x98: /* CWDE/CBW */
 #ifdef TARGET_X86_64
         if (dflag == 2) {
@@ -3797,13 +3889,14 @@
         mod = (modrm >> 6) & 3;
         if (mod == 3)
             goto illegal_op;
+        gen_jmp_im(pc_start - s->cs_base);
         if (s->cc_op != CC_OP_DYNAMIC)
             gen_op_set_cc_op(s->cc_op);
         gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
         gen_op_cmpxchg8b();
         s->cc_op = CC_OP_EFLAGS;
         break;
-        
+
         /**************************/
         /* push/pop */
     case 0x50 ... 0x57: /* push */
@@ -3954,7 +4047,7 @@
             ot = dflag + OT_WORD;
         modrm = ldub_code(s->pc++);
         reg = ((modrm >> 3) & 7) | rex_r;
-        
+
         /* generate a generic store */
         gen_ldst_modrm(s, modrm, ot, reg, 1);
         break;
@@ -3985,7 +4078,7 @@
             ot = OT_WORD + dflag;
         modrm = ldub_code(s->pc++);
         reg = ((modrm >> 3) & 7) | rex_r;
-        
+
         gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
         gen_op_mov_reg_T0[ot][reg]();
         break;
@@ -4037,7 +4130,7 @@
             reg = ((modrm >> 3) & 7) | rex_r;
             mod = (modrm >> 6) & 3;
             rm = (modrm & 7) | REX_B(s);
-            
+
             if (mod == 3) {
                 gen_op_mov_TN_reg[ot][0][rm]();
                 switch(ot | (b & 8)) {
@@ -4083,7 +4176,7 @@
         s->addseg = val;
         gen_op_mov_reg_A0[ot - OT_WORD][reg]();
         break;
-        
+
     case 0xa0: /* mov EAX, Ov */
     case 0xa1:
     case 0xa2: /* mov Ov, EAX */
@@ -4103,7 +4196,7 @@
                     gen_op_movq_A0_im(offset_addr);
                 else
                     gen_op_movq_A0_im64(offset_addr >> 32, offset_addr);
-            } else 
+            } else
 #endif
             {
                 if (s->aflag) {
@@ -4128,7 +4221,7 @@
         if (s->aflag == 2) {
             gen_op_movq_A0_reg[R_EBX]();
             gen_op_addq_A0_AL();
-        } else 
+        } else
 #endif
         {
             gen_op_movl_A0_reg[R_EBX]();
@@ -4155,7 +4248,7 @@
             reg = (b & 7) | REX_B(s);
             gen_movtl_T0_im(tmp);
             gen_op_mov_reg_T0[OT_QUAD][reg]();
-        } else 
+        } else
 #endif
         {
             ot = dflag ? OT_LONG : OT_WORD;
@@ -4238,7 +4331,7 @@
             gen_eob(s);
         }
         break;
-        
+
         /************************/
         /* shifts */
     case 0xc0:
@@ -4251,11 +4344,11 @@
                 ot = OT_BYTE;
             else
                 ot = dflag + OT_WORD;
-            
+
             modrm = ldub_code(s->pc++);
             mod = (modrm >> 6) & 3;
             op = (modrm >> 3) & 7;
-            
+
             if (mod != 3) {
                 if (shift == 2) {
                     s->rip_offset = 1;
@@ -4309,7 +4402,7 @@
         mod = (modrm >> 6) & 3;
         rm = (modrm & 7) | REX_B(s);
         reg = ((modrm >> 3) & 7) | rex_r;
-        
+
         if (mod != 3) {
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
             gen_op_ld_T0_A0[ot + s->mem_index]();
@@ -4317,7 +4410,7 @@
             gen_op_mov_TN_reg[ot][0][rm]();
         }
         gen_op_mov_TN_reg[ot][1][reg]();
-        
+
         if (shift) {
             val = ldub_code(s->pc++);
             if (ot == OT_QUAD)
@@ -4350,7 +4443,7 @@
 
         /************************/
         /* floats */
-    case 0xd8 ... 0xdf: 
+    case 0xd8 ... 0xdf:
         if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
             /* if CR0.EM or CR0.TS are set, generate an FPU exception */
             /* XXX: what to do if illegal op ? */
@@ -4388,7 +4481,7 @@
                         gen_op_fild_FT0_A0();
                         break;
                     }
-                    
+
                     gen_op_fp_arith_ST0_FT0[op1]();
                     if (op1 == 3) {
                         /* fcomp needs pop */
@@ -4645,7 +4738,7 @@
             case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
                 {
                     int op1;
-                    
+
                     op1 = op & 7;
                     if (op >= 0x20) {
                         gen_op_fp_arith_STN_ST0[op1](opreg);
@@ -4715,7 +4808,7 @@
                 break;
             case 0x28: /* ffree sti */
                 gen_op_ffree_STN(opreg);
-                break; 
+                break;
             case 0x2a: /* fst sti */
                 gen_op_fmov_STN_ST0(opreg);
                 break;
@@ -4815,7 +4908,7 @@
             gen_movs(s, ot);
         }
         break;
-        
+
     case 0xaa: /* stosS */
     case 0xab:
         if ((b & 1) == 0)
@@ -4879,6 +4972,12 @@
         else
             ot = dflag ? OT_LONG : OT_WORD;
         gen_check_io(s, ot, 1, pc_start - s->cs_base);
+        gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
+        gen_op_andl_T0_ffff();
+        if (gen_svm_check_io(s, pc_start,
+                             SVM_IOIO_TYPE_MASK | (1 << (4+ot)) |
+                             svm_is_rep(prefixes) | 4 | (1 << (7+s->aflag))))
+            break;
         if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
             gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
         } else {
@@ -4892,6 +4991,12 @@
         else
             ot = dflag ? OT_LONG : OT_WORD;
         gen_check_io(s, ot, 1, pc_start - s->cs_base);
+        gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
+        gen_op_andl_T0_ffff();
+        if (gen_svm_check_io(s, pc_start,
+                             (1 << (4+ot)) | svm_is_rep(prefixes) |
+                             4 | (1 << (7+s->aflag))))
+            break;
         if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
             gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
         } else {
@@ -4901,6 +5006,7 @@
 
         /************************/
         /* port I/O */
+
     case 0xe4:
     case 0xe5:
         if ((b & 1) == 0)
@@ -4910,6 +5016,10 @@
         val = ldub_code(s->pc++);
         gen_op_movl_T0_im(val);
         gen_check_io(s, ot, 0, pc_start - s->cs_base);
+        if (gen_svm_check_io(s, pc_start,
+                             SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) |
+                             (1 << (4+ot))))
+            break;
         gen_op_in[ot]();
         gen_op_mov_reg_T1[ot][R_EAX]();
         break;
@@ -4922,6 +5032,9 @@
         val = ldub_code(s->pc++);
         gen_op_movl_T0_im(val);
         gen_check_io(s, ot, 0, pc_start - s->cs_base);
+        if (gen_svm_check_io(s, pc_start, svm_is_rep(prefixes) |
+                             (1 << (4+ot))))
+            break;
         gen_op_mov_TN_reg[ot][1][R_EAX]();
         gen_op_out[ot]();
         break;
@@ -4934,6 +5047,10 @@
         gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
         gen_op_andl_T0_ffff();
         gen_check_io(s, ot, 0, pc_start - s->cs_base);
+        if (gen_svm_check_io(s, pc_start,
+                             SVM_IOIO_TYPE_MASK | svm_is_rep(prefixes) |
+                             (1 << (4+ot))))
+            break;
         gen_op_in[ot]();
         gen_op_mov_reg_T1[ot][R_EAX]();
         break;
@@ -4946,6 +5063,9 @@
         gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
         gen_op_andl_T0_ffff();
         gen_check_io(s, ot, 0, pc_start - s->cs_base);
+        if (gen_svm_check_io(s, pc_start,
+                             svm_is_rep(prefixes) | (1 << (4+ot))))
+            break;
         gen_op_mov_TN_reg[ot][1][R_EAX]();
         gen_op_out[ot]();
         break;
@@ -5003,6 +5123,8 @@
         val = 0;
         goto do_lret;
     case 0xcf: /* iret */
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_IRET))
+            break;
         if (!s->pe) {
             /* real mode */
             gen_op_iret_real(s->dflag);
@@ -5041,13 +5163,13 @@
     case 0x9a: /* lcall im */
         {
             unsigned int selector, offset;
-            
+
             if (CODE64(s))
                 goto illegal_op;
             ot = dflag ? OT_LONG : OT_WORD;
             offset = insn_get(s, ot);
             selector = insn_get(s, OT_WORD);
-            
+
             gen_op_movl_T0_im(selector);
             gen_op_movl_T1_imu(offset);
         }
@@ -5071,7 +5193,7 @@
             ot = dflag ? OT_LONG : OT_WORD;
             offset = insn_get(s, ot);
             selector = insn_get(s, OT_WORD);
-            
+
             gen_op_movl_T0_im(selector);
             gen_op_movl_T1_imu(offset);
         }
@@ -5090,7 +5212,7 @@
         if (dflag) {
             tval = (int32_t)insn_get(s, OT_LONG);
         } else {
-            tval = (int16_t)insn_get(s, OT_WORD); 
+            tval = (int16_t)insn_get(s, OT_WORD);
         }
     do_jcc:
         next_eip = s->pc - s->cs_base;
@@ -5120,10 +5242,12 @@
         }
         gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg]();
         break;
-        
+
         /************************/
         /* flags */
     case 0x9c: /* pushf */
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_PUSHF))
+            break;
         if (s->vm86 && s->iopl != 3) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
@@ -5134,6 +5258,8 @@
         }
         break;
     case 0x9d: /* popf */
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_POPF))
+            break;
         if (s->vm86 && s->iopl != 3) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
@@ -5326,8 +5452,12 @@
         if (CODE64(s))
             goto illegal_op;
         val = ldub_code(s->pc++);
-        gen_op_aam(val);
-        s->cc_op = CC_OP_LOGICB;
+        if (val == 0) {
+            gen_exception(s, EXCP00_DIVZ, pc_start - s->cs_base);
+        } else {
+            gen_op_aam(val);
+            s->cc_op = CC_OP_LOGICB;
+        }
         break;
     case 0xd5: /* aad */
         if (CODE64(s))
@@ -5343,9 +5473,12 @@
         /* XXX: correct lock test for all insn */
         if (prefixes & PREFIX_LOCK)
             goto illegal_op;
+        if (prefixes & PREFIX_REPZ) {
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_PAUSE);
+        }
         break;
     case 0x9b: /* fwait */
-        if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) == 
+        if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
             (HF_MP_MASK | HF_TS_MASK)) {
             gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
         } else {
@@ -5356,12 +5489,16 @@
         }
         break;
     case 0xcc: /* int3 */
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT))
+            break;
         gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
         break;
     case 0xcd: /* int N */
         val = ldub_code(s->pc++);
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT))
+            break;
         if (s->vm86 && s->iopl != 3) {
-            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); 
+            gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
             gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
         }
@@ -5369,12 +5506,16 @@
     case 0xce: /* into */
         if (CODE64(s))
             goto illegal_op;
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SWINT))
+            break;
         if (s->cc_op != CC_OP_DYNAMIC)
             gen_op_set_cc_op(s->cc_op);
         gen_jmp_im(pc_start - s->cs_base);
         gen_op_into(s->pc - pc_start);
         break;
     case 0xf1: /* icebp (undocumented, exits to external debugger) */
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_ICEBP))
+            break;
 #if 1
         gen_debug(s, pc_start - s->cs_base);
 #else
@@ -5446,7 +5587,7 @@
             gen_op_mov_TN_reg[OT_QUAD][0][reg]();
             gen_op_bswapq_T0();
             gen_op_mov_reg_T0[OT_QUAD][reg]();
-        } else 
+        } else
 #endif
         {
             gen_op_mov_TN_reg[OT_LONG][0][reg]();
@@ -5476,7 +5617,7 @@
             tval += next_eip;
             if (s->dflag == 0)
                 tval &= 0xffff;
-            
+
             l1 = gen_new_label();
             l2 = gen_new_label();
             b &= 3;
@@ -5502,13 +5643,21 @@
         if (s->cpl != 0) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
-            if (b & 2)
+            int retval = 0;
+            if (b & 2) {
+                retval = gen_svm_check_intercept_param(s, pc_start, SVM_EXIT_MSR, 0);
                 gen_op_rdmsr();
-            else
+            } else {
+                retval = gen_svm_check_intercept_param(s, pc_start, SVM_EXIT_MSR, 1);
                 gen_op_wrmsr();
+            }
+            if(retval)
+                gen_eob(s);
         }
         break;
     case 0x131: /* rdtsc */
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_RDTSC))
+            break;
         gen_jmp_im(pc_start - s->cs_base);
         gen_op_rdtsc();
         break;
@@ -5571,12 +5720,16 @@
         break;
 #endif
     case 0x1a2: /* cpuid */
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_CPUID))
+            break;
         gen_op_cpuid();
         break;
     case 0xf4: /* hlt */
         if (s->cpl != 0) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
+            if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_HLT))
+                break;
             if (s->cc_op != CC_OP_DYNAMIC)
                 gen_op_set_cc_op(s->cc_op);
             gen_jmp_im(s->pc - s->cs_base);
@@ -5592,6 +5745,8 @@
         case 0: /* sldt */
             if (!s->pe || s->vm86)
                 goto illegal_op;
+            if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_READ))
+                break;
             gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
             ot = OT_WORD;
             if (mod == 3)
@@ -5604,6 +5759,8 @@
             if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             } else {
+                if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_LDTR_WRITE))
+                    break;
                 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
                 gen_jmp_im(pc_start - s->cs_base);
                 gen_op_lldt_T0();
@@ -5612,6 +5769,8 @@
         case 1: /* str */
             if (!s->pe || s->vm86)
                 goto illegal_op;
+            if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_READ))
+                break;
             gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
             ot = OT_WORD;
             if (mod == 3)
@@ -5624,6 +5783,8 @@
             if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             } else {
+                if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_TR_WRITE))
+                    break;
                 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
                 gen_jmp_im(pc_start - s->cs_base);
                 gen_op_ltr_T0();
@@ -5655,6 +5816,8 @@
         case 0: /* sgdt */
             if (mod == 3)
                 goto illegal_op;
+            if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_GDTR_READ))
+                break;
             gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
             gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit));
             gen_op_st_T0_A0[OT_WORD + s->mem_index]();
@@ -5671,12 +5834,14 @@
                     if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
                         s->cpl != 0)
                         goto illegal_op;
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_MONITOR))
+                        break;
                     gen_jmp_im(pc_start - s->cs_base);
 #ifdef TARGET_X86_64
                     if (s->aflag == 2) {
                         gen_op_movq_A0_reg[R_EBX]();
                         gen_op_addq_A0_AL();
-                    } else 
+                    } else
 #endif
                     {
                         gen_op_movl_A0_reg[R_EBX]();
@@ -5695,6 +5860,8 @@
                         gen_op_set_cc_op(s->cc_op);
                         s->cc_op = CC_OP_DYNAMIC;
                     }
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_MWAIT))
+                        break;
                     gen_jmp_im(s->pc - s->cs_base);
                     gen_op_mwait();
                     gen_eob(s);
@@ -5703,6 +5870,8 @@
                     goto illegal_op;
                 }
             } else { /* sidt */
+                if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_IDTR_READ))
+                    break;
                 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
                 gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit));
                 gen_op_st_T0_A0[OT_WORD + s->mem_index]();
@@ -5715,11 +5884,63 @@
             break;
         case 2: /* lgdt */
         case 3: /* lidt */
-            if (mod == 3)
-                goto illegal_op;
-            if (s->cpl != 0) {
+            if (mod == 3) {
+                switch(rm) {
+                case 0: /* VMRUN */
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMRUN))
+                        break;
+                    if (s->cc_op != CC_OP_DYNAMIC)
+                        gen_op_set_cc_op(s->cc_op);
+                    gen_jmp_im(s->pc - s->cs_base);
+                    gen_op_vmrun();
+                    s->cc_op = CC_OP_EFLAGS;
+                    gen_eob(s);
+                    break;
+                case 1: /* VMMCALL */
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMMCALL))
+                         break;
+                    /* FIXME: cause #UD if hflags & SVM */
+                    gen_op_vmmcall();
+                    break;
+                case 2: /* VMLOAD */
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMLOAD))
+                         break;
+                    gen_op_vmload();
+                    break;
+                case 3: /* VMSAVE */
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_VMSAVE))
+                         break;
+                    gen_op_vmsave();
+                    break;
+                case 4: /* STGI */
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_STGI))
+                         break;
+                    gen_op_stgi();
+                    break;
+                case 5: /* CLGI */
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_CLGI))
+                         break;
+                    gen_op_clgi();
+                    break;
+                case 6: /* SKINIT */
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_SKINIT))
+                         break;
+                    gen_op_skinit();
+                    break;
+                case 7: /* INVLPGA */
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVLPGA))
+                         break;
+                    gen_op_invlpga();
+                    break;
+                default:
+                    goto illegal_op;
+                }
+            } else if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             } else {
+                if (gen_svm_check_intercept(s, pc_start,
+                                            op==2 ? SVM_EXIT_GDTR_WRITE : SVM_EXIT_IDTR_WRITE))
+                    break;
                 gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
                 gen_op_ld_T1_A0[OT_WORD + s->mem_index]();
                 gen_add_A0_im(s, 2);
@@ -5736,6 +5957,8 @@
             }
             break;
         case 4: /* smsw */
+            if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0))
+                break;
             gen_op_movl_T0_env(offsetof(CPUX86State,cr[0]));
             gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1);
             break;
@@ -5743,6 +5966,8 @@
             if (s->cpl != 0) {
                 gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
             } else {
+                if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0))
+                    break;
                 gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
                 gen_op_lmsw_T0();
                 gen_jmp_im(s->pc - s->cs_base);
@@ -5761,12 +5986,14 @@
                         gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase));
                         gen_op_movtl_env_T1(offsetof(CPUX86State,segs[R_GS].base));
                         gen_op_movtl_env_T0(offsetof(CPUX86State,kernelgsbase));
-                    } else 
+                    } else
 #endif
                     {
                         goto illegal_op;
                     }
                 } else {
+                    if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVLPG))
+                        break;
                     gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
                     gen_op_invlpg_A0();
                     gen_jmp_im(s->pc - s->cs_base);
@@ -5783,6 +6010,8 @@
         if (s->cpl != 0) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
+            if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_INVD))
+                break;
             /* nothing to do */
         }
         break;
@@ -5797,7 +6026,7 @@
             reg = ((modrm >> 3) & 7) | rex_r;
             mod = (modrm >> 6) & 3;
             rm = (modrm & 7) | REX_B(s);
-            
+
             if (mod == 3) {
                 gen_op_mov_TN_reg[OT_LONG][0][rm]();
                 /* sign extend */
@@ -5813,7 +6042,7 @@
                 }
                 gen_op_mov_reg_T0[d_ot][reg]();
             }
-        } else 
+        } else
 #endif
         {
             if (!s->pe || s->vm86)
@@ -5903,12 +6132,14 @@
             case 4:
             case 8:
                 if (b & 2) {
+                    gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0 + reg);
                     gen_op_mov_TN_reg[ot][0][rm]();
                     gen_op_movl_crN_T0(reg);
                     gen_jmp_im(s->pc - s->cs_base);
                     gen_eob(s);
                 } else {
-#if !defined(CONFIG_USER_ONLY) 
+                    gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_CR0 + reg);
+#if !defined(CONFIG_USER_ONLY)
                     if (reg == 8)
                         gen_op_movtl_T0_cr8();
                     else
@@ -5940,11 +6171,13 @@
             if (reg == 4 || reg == 5 || reg >= 8)
                 goto illegal_op;
             if (b & 2) {
+                gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_DR0 + reg);
                 gen_op_mov_TN_reg[ot][0][rm]();
                 gen_op_movl_drN_T0(reg);
                 gen_jmp_im(s->pc - s->cs_base);
                 gen_eob(s);
             } else {
+                gen_svm_check_intercept(s, pc_start, SVM_EXIT_READ_DR0 + reg);
                 gen_op_movtl_T0_env(offsetof(CPUX86State,dr[reg]));
                 gen_op_mov_reg_T0[ot][rm]();
             }
@@ -5954,6 +6187,7 @@
         if (s->cpl != 0) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
         } else {
+            gen_svm_check_intercept(s, pc_start, SVM_EXIT_WRITE_CR0);
             gen_op_clts();
             /* abort block because static cpu state changed */
             gen_jmp_im(s->pc - s->cs_base);
@@ -5979,7 +6213,7 @@
         op = (modrm >> 3) & 7;
         switch(op) {
         case 0: /* fxsave */
-            if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || 
+            if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
                 (s->flags & HF_EM_MASK))
                 goto illegal_op;
             if (s->flags & HF_TS_MASK) {
@@ -5990,7 +6224,7 @@
             gen_op_fxsave_A0((s->dflag == 2));
             break;
         case 1: /* fxrstor */
-            if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) || 
+            if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
                 (s->flags & HF_EM_MASK))
                 goto illegal_op;
             if (s->flags & HF_TS_MASK) {
@@ -6045,6 +6279,8 @@
         /* ignore for now */
         break;
     case 0x1aa: /* rsm */
+        if (gen_svm_check_intercept(s, pc_start, SVM_EXIT_RSM))
+            break;
         if (!(s->flags & HF_SMM_MASK))
             goto illegal_op;
         if (s->cc_op != CC_OP_DYNAMIC) {
@@ -6083,14 +6319,14 @@
 #define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P)
 
 /* flags read by an operation */
-static uint16_t opc_read_flags[NB_OPS] = { 
+static uint16_t opc_read_flags[NB_OPS] = {
     [INDEX_op_aas] = CC_A,
     [INDEX_op_aaa] = CC_A,
     [INDEX_op_das] = CC_A | CC_C,
     [INDEX_op_daa] = CC_A | CC_C,
 
     /* subtle: due to the incl/decl implementation, C is used */
-    [INDEX_op_update_inc_cc] = CC_C, 
+    [INDEX_op_update_inc_cc] = CC_C,
 
     [INDEX_op_into] = CC_O,
 
@@ -6216,13 +6452,13 @@
 };
 
 /* flags written by an operation */
-static uint16_t opc_write_flags[NB_OPS] = { 
+static uint16_t opc_write_flags[NB_OPS] = {
     [INDEX_op_update2_cc] = CC_OSZAPC,
     [INDEX_op_update1_cc] = CC_OSZAPC,
     [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
     [INDEX_op_update_neg_cc] = CC_OSZAPC,
     /* subtle: due to the incl/decl implementation, C is used */
-    [INDEX_op_update_inc_cc] = CC_OSZAPC, 
+    [INDEX_op_update_inc_cc] = CC_OSZAPC,
     [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
 
     [INDEX_op_mulb_AL_T0] = CC_OSZAPC,
@@ -6367,7 +6603,7 @@
 };
 
 /* simpler form of an operation if no flags need to be generated */
-static uint16_t opc_simpler[NB_OPS] = { 
+static uint16_t opc_simpler[NB_OPS] = {
     [INDEX_op_update2_cc] = INDEX_op_nop,
     [INDEX_op_update1_cc] = INDEX_op_nop,
     [INDEX_op_update_neg_cc] = INDEX_op_nop,
@@ -6430,7 +6666,7 @@
 
     opc_ptr = opc_buf + opc_buf_len;
     /* live_flags contains the flags needed by the next instructions
-       in the code. At the end of the bloc, we consider that all the
+       in the code. At the end of the block, we consider that all the
        flags are live. */
     live_flags = CC_OSZAPC;
     while (opc_ptr > opc_buf) {
@@ -6451,16 +6687,17 @@
    basic block 'tb'. If search_pc is TRUE, also generate PC
    information for each intermediate instruction. */
 static inline int gen_intermediate_code_internal(CPUState *env,
-                                                 TranslationBlock *tb, 
+                                                 TranslationBlock *tb,
                                                  int search_pc)
 {
     DisasContext dc1, *dc = &dc1;
     target_ulong pc_ptr;
     uint16_t *gen_opc_end;
-    int flags, j, lj, cflags;
+    int j, lj, cflags;
+    uint64_t flags;
     target_ulong pc_start;
     target_ulong cs_base;
-    
+
     /* generate intermediate code */
     pc_start = tb->pc;
     cs_base = tb->cs_base;
@@ -6546,7 +6783,7 @@
         /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
            the flag and abort the translation to give the irqs a
            change to be happen */
-        if (dc->tf || dc->singlestep_enabled || 
+        if (dc->tf || dc->singlestep_enabled ||
             (flags & HF_INHIBIT_IRQ_MASK) ||
             (cflags & CF_SINGLE_INSN)) {
             gen_jmp_im(pc_ptr - dc->cs_base);
@@ -6569,7 +6806,7 @@
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
     }
-        
+
 #ifdef DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_CPU) {
         cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index de37baf..a34c137 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -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,12 +50,19 @@
 #define EXCP_UNSUPPORTED    61
 #define EXCP_ICE            13
 
+#define EXCP_RTE            0x100
+#define EXCP_HALT_INSN      0x101
+
 typedef struct CPUM68KState {
     uint32_t dregs[8];
     uint32_t aregs[8];
     uint32_t pc;
     uint32_t sr;
 
+    /* SSP and USP.  The current_sp is stored in aregs[7], the other here.  */
+    int current_sp;
+    uint32_t sp[2];
+
     /* Condition flags.  */
     uint32_t cc_op;
     uint32_t cc_dest;
@@ -68,14 +75,31 @@
     uint32_t fpsr;
     float_status fp_status;
 
+    uint64_t mactmp;
+    /* EMAC Hardware deals with 48-bit values composed of one 32-bit and
+       two 8-bit parts.  We store a single 64-bit value and
+       rearrange/extend this when changing modes.  */
+    uint64_t macc[4];
+    uint32_t macsr;
+    uint32_t mac_mask;
+
     /* Temporary storage for DIV helpers.  */
     uint32_t div1;
     uint32_t div2;
-    
+
     /* MMU status.  */
     struct {
         uint32_t ar;
     } mmu;
+
+    /* Control registers.  */
+    uint32_t vbr;
+    uint32_t mbar;
+    uint32_t rambar0;
+    uint32_t cacr;
+
+    uint32_t features;
+
     /* ??? remove this.  */
     uint32_t t1;
 
@@ -84,7 +108,10 @@
     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];
 
@@ -94,10 +121,11 @@
 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.  */
-int cpu_m68k_signal_handler(int host_signum, void *pinfo, 
+int cpu_m68k_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 void cpu_m68k_flush_flags(CPUM68KState *, int);
 
@@ -120,22 +148,81 @@
 #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
+
+#define M68K_SSP    0
+#define M68K_USP    1
+
+/* CACR fields are implementation defined, but some bits are common.  */
+#define M68K_CACR_EUSP  0x10
+
+#define MACSR_PAV0  0x100
+#define MACSR_OMC   0x080
+#define MACSR_SU    0x040
+#define MACSR_FI    0x020
+#define MACSR_RT    0x010
+#define MACSR_N     0x008
+#define MACSR_Z     0x004
+#define MACSR_V     0x002
+#define MACSR_EV    0x001
 
 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);
+void m68k_set_macsr(CPUM68KState *env, uint32_t val);
+void m68k_switch_sp(CPUM68KState *env);
 
 #define M68K_FPCR_PREC (1 << 6)
 
+void do_m68k_semihosting(CPUM68KState *env, int nr);
+
+/* There are 4 ColdFire core ISA revisions: A, A+, B and C.
+   Each feature covers the subset of instructions common to the
+   ISA revisions mentioned.  */
+
+enum m68k_features {
+    M68K_FEATURE_CF_ISA_A,
+    M68K_FEATURE_CF_ISA_B, /* (ISA B or C).  */
+    M68K_FEATURE_CF_ISA_APLUSC, /* BIT/BITREV, FF1, STRLDSR (ISA A+ or C).  */
+    M68K_FEATURE_BRAL, /* Long unconditional branch.  (ISA A+ or B).  */
+    M68K_FEATURE_CF_FPU,
+    M68K_FEATURE_CF_MAC,
+    M68K_FEATURE_CF_EMAC,
+    M68K_FEATURE_CF_EMAC_B, /* Revision B EMAC (dual accumulate).  */
+    M68K_FEATURE_USP, /* User Stack Pointer.  (ISA A+, B or C).  */
+    M68K_FEATURE_EXT_FULL, /* 68020+ full extension word.  */
+    M68K_FEATURE_WORD_INDEX /* word sized address index registers.  */
+};
+
+static inline int m68k_feature(CPUM68KState *env, int feature)
+{
+    return (env->features & (1u << feature)) != 0;
+}
+
+void register_m68k_insns (CPUM68KState *env);
+
 #ifdef CONFIG_USER_ONLY
 /* Linux uses 8k pages.  */
 #define TARGET_PAGE_BITS 13
 #else
-/* Smallest TLB entry size is 1k.  */ 
+/* Smallest TLB entry size is 1k.  */
 #define TARGET_PAGE_BITS 10
 #endif
+
+#define CPUState CPUM68KState
+#define cpu_init cpu_m68k_init
+#define cpu_exec cpu_m68k_exec
+#define cpu_gen_code cpu_m68k_gen_code
+#define cpu_signal_handler cpu_m68k_signal_handler
+
 #include "cpu-all.h"
 
 #endif
diff --git a/target-m68k/exec.h b/target-m68k/exec.h
index ef4adeb..dc5bf5e 100644
--- a/target-m68k/exec.h
+++ b/target-m68k/exec.h
@@ -1,6 +1,6 @@
 /*
  *  m68k execution defines
- * 
+ *
  *  Copyright (c) 2005-2006 CodeSourcery
  *  Written by Paul Brook
  *
@@ -40,8 +40,22 @@
 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);
+
+static inline int cpu_halted(CPUState *env) {
+    if (!env->halted)
+        return 0;
+    if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
diff --git a/target-m68k/helper.c b/target-m68k/helper.c
index 6b8f18d..423a0e0 100644
--- a/target-m68k/helper.c
+++ b/target-m68k/helper.c
@@ -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
@@ -20,11 +20,88 @@
  */
 
 #include <stdio.h>
+#include <string.h>
 
 #include "config.h"
 #include "cpu.h"
 #include "exec-all.h"
 
+enum m68k_cpuid {
+    M68K_CPUID_M5206,
+    M68K_CPUID_M5208,
+    M68K_CPUID_CFV4E,
+    M68K_CPUID_ANY,
+};
+
+struct m68k_def_t {
+    const char * name;
+    enum m68k_cpuid id;
+};
+
+static m68k_def_t m68k_cpu_defs[] = {
+    {"m5206", M68K_CPUID_M5206},
+    {"m5208", M68K_CPUID_M5208},
+    {"cfv4e", M68K_CPUID_CFV4E},
+    {"any", M68K_CPUID_ANY},
+    {NULL, 0},
+};
+
+static void m68k_set_feature(CPUM68KState *env, int feature)
+{
+    env->features |= (1u << feature);
+}
+
+int cpu_m68k_set_model(CPUM68KState *env, const char * name)
+{
+    m68k_def_t *def;
+
+    for (def = m68k_cpu_defs; def->name; def++) {
+        if (strcmp(def->name, name) == 0)
+            break;
+    }
+    if (!def->name)
+        return 1;
+
+    switch (def->id) {
+    case M68K_CPUID_M5206:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        break;
+    case M68K_CPUID_M5208:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
+        m68k_set_feature(env, M68K_FEATURE_BRAL);
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_USP);
+        break;
+    case M68K_CPUID_CFV4E:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
+        m68k_set_feature(env, M68K_FEATURE_BRAL);
+        m68k_set_feature(env, M68K_FEATURE_CF_FPU);
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_USP);
+        break;
+    case M68K_CPUID_ANY:
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_A);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_B);
+        m68k_set_feature(env, M68K_FEATURE_CF_ISA_APLUSC);
+        m68k_set_feature(env, M68K_FEATURE_BRAL);
+        m68k_set_feature(env, M68K_FEATURE_CF_FPU);
+        /* MAC and EMAC are mututally exclusive, so pick EMAC.
+           It's mostly backwards compatible.  */
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC);
+        m68k_set_feature(env, M68K_FEATURE_CF_EMAC_B);
+        m68k_set_feature(env, M68K_FEATURE_USP);
+        m68k_set_feature(env, M68K_FEATURE_EXT_FULL);
+        m68k_set_feature(env, M68K_FEATURE_WORD_INDEX);
+        break;
+    }
+
+    register_m68k_insns(env);
+
+    return 0;
+}
+
 void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op)
 {
     int flags;
@@ -147,3 +224,114 @@
     }
     return res;
 }
+
+void helper_movec(CPUM68KState *env, int reg, uint32_t val)
+{
+    switch (reg) {
+    case 0x02: /* CACR */
+        env->cacr = val;
+        m68k_switch_sp(env);
+        break;
+    case 0x04: case 0x05: case 0x06: case 0x07: /* ACR[0-3] */
+        /* TODO: Implement Access Control Registers.  */
+        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);
+    }
+}
+
+void m68k_set_macsr(CPUM68KState *env, uint32_t val)
+{
+    uint32_t acc;
+    int8_t exthigh;
+    uint8_t extlow;
+    uint64_t regval;
+    int i;
+    if ((env->macsr ^ val) & (MACSR_FI | MACSR_SU)) {
+        for (i = 0; i < 4; i++) {
+            regval = env->macc[i];
+            exthigh = regval >> 40;
+            if (env->macsr & MACSR_FI) {
+                acc = regval >> 8;
+                extlow = regval;
+            } else {
+                acc = regval;
+                extlow = regval >> 32;
+            }
+            if (env->macsr & MACSR_FI) {
+                regval = (((uint64_t)acc) << 8) | extlow;
+                regval |= ((int64_t)exthigh) << 40;
+            } else if (env->macsr & MACSR_SU) {
+                regval = acc | (((int64_t)extlow) << 32);
+                regval |= ((int64_t)exthigh) << 40;
+            } else {
+                regval = acc | (((uint64_t)extlow) << 32);
+                regval |= ((uint64_t)(uint8_t)exthigh) << 40;
+            }
+            env->macc[i] = regval;
+        }
+    }
+    env->macsr = val;
+}
+
+void m68k_switch_sp(CPUM68KState *env)
+{
+    int new_sp;
+
+    env->sp[env->current_sp] = env->aregs[7];
+    new_sp = (env->sr & SR_S && env->cacr & M68K_CACR_EUSP)
+             ? M68K_SSP : M68K_USP;
+    env->aregs[7] = env->sp[new_sp];
+    env->current_sp = new_sp;
+}
+
+/* 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
diff --git a/target-m68k/op-hacks.h b/target-m68k/op-hacks.h
index c786563..7bf345c 100644
--- a/target-m68k/op-hacks.h
+++ b/target-m68k/op-hacks.h
@@ -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);
@@ -81,3 +103,28 @@
         gen_op_goto_tb1(TBPARAM(tb));
     }
 }
+
+static inline void gen_op_jmp_z32(int val, int label)
+{
+    gen_op_set_T0_z32(val);
+    gen_op_jmp_T0(label);
+}
+
+static inline void gen_op_jmp_nz32(int val, int label)
+{
+    gen_op_set_T0_nz32(val);
+    gen_op_jmp_T0(label);
+}
+
+static inline void gen_op_jmp_s32(int val, int label)
+{
+    gen_op_set_T0_s32(val);
+    gen_op_jmp_T0(label);
+}
+
+static inline void gen_op_jmp_ns32(int val, int label)
+{
+    gen_op_set_T0_ns32(val);
+    gen_op_jmp_T0(label);
+}
+
diff --git a/target-m68k/op.c b/target-m68k/op.c
index 8ea7589..8600f43 100644
--- a/target-m68k/op.c
+++ b/target-m68k/op.c
@@ -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) {
-        return T0;
-    } else if (qreg < TARGET_NUM_QREGS) {
-        return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
-    } else {
+    if (qreg >= TARGET_NUM_QREGS) {
         return env->qregs[qreg - TARGET_NUM_QREGS];
+    } else if (qreg == QREG_T0) {
+        return T0;
+    } else {
+        return *(uint32_t *)(((long)env) + qreg_offsets[qreg]);
     }
 }
 
 void set_op(int qreg, uint32_t val)
 {
-    if (qreg == QREG_T0) {
-        T0 = val;
-    } else if (qreg < TARGET_NUM_QREGS) {
-        *(uint32_t *)(((long)env) + qreg_offsets[qreg]) = val;
-    } else {
+    if (qreg >= TARGET_NUM_QREGS) {
         env->qregs[qreg - TARGET_NUM_QREGS] = val;
+    } else if (qreg == QREG_T0) {
+        T0 = val;
+    } else {
+        *(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,17 @@
     FORCE_RET();
 }
 
-OP(addx_cc)
+OP(ff1)
+{
+    uint32_t arg = get_op(PARAM2);
+    int n;
+    for (n = 32; arg; n--)
+        arg >>= 1;
+    set_op(PARAM1, n);
+    FORCE_RET();
+}
+
+OP(subx_cc)
 {
     uint32_t op1 = get_op(PARAM1);
     uint32_t op2 = get_op(PARAM2);
@@ -188,7 +198,7 @@
     FORCE_RET();
 }
 
-OP(subx_cc)
+OP(addx_cc)
 {
     uint32_t op1 = get_op(PARAM1);
     uint32_t op2 = get_op(PARAM2);
@@ -275,6 +285,16 @@
     FORCE_RET();
 }
 
+OP(sar32)
+{
+    int32_t op2 = get_op(PARAM2);
+    uint32_t op3 = get_op(PARAM3);
+    uint32_t result;
+    result = op2 >> op3;
+    set_op(PARAM1, result);
+    FORCE_RET();
+}
+
 OP(sar_cc)
 {
     int32_t op1 = get_op(PARAM1);
@@ -316,83 +336,9 @@
     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;
-    if (cc_op == CC_OP_DYNAMIC)
-        cc_op = env->cc_op;
-    cpu_m68k_flush_flags(env, cc_op);
+    cpu_m68k_flush_flags(env, env->cc_op);
     FORCE_RET();
 }
 
@@ -403,7 +349,7 @@
     uint32_t quot;
     uint32_t rem;
     uint32_t flags;
-    
+
     num = env->div1;
     den = env->div2;
     /* ??? This needs to make sure the throwing location is accurate.  */
@@ -434,7 +380,7 @@
     int32_t quot;
     int32_t rem;
     int32_t flags;
-    
+
     num = env->div1;
     den = env->div2;
     if (den == 0)
@@ -454,6 +400,20 @@
     FORCE_RET();
 }
 
+/* Halt is special because it may be a semihosting call.  */
+OP(halt)
+{
+    RAISE_EXCEPTION(EXCP_HALT_INSN);
+    FORCE_RET();
+}
+
+OP(stop)
+{
+    env->halted = 1;
+    RAISE_EXCEPTION(EXCP_HLT);
+    FORCE_RET();
+}
+
 OP(raise_exception)
 {
     RAISE_EXCEPTION(PARAM1);
@@ -515,42 +475,50 @@
     FORCE_RET();
 }
 
+OP(set_sr)
+{
+    env->sr = get_op(PARAM1) & 0xffff;
+    m68k_switch_sp(env);
+    FORCE_RET();
+}
+
 OP(jmp)
 {
     GOTO_LABEL_PARAM(1);
 }
 
-/* These ops involve a function call, which probably requires a stack frame
-   and breaks things on some hosts.  */
-OP(jmp_z32)
+OP(set_T0_z32)
 {
     uint32_t arg = get_op(PARAM1);
-    if (arg == 0)
-        GOTO_LABEL_PARAM(2);
+    T0 = (arg == 0);
     FORCE_RET();
 }
 
-OP(jmp_nz32)
+OP(set_T0_nz32)
 {
     uint32_t arg = get_op(PARAM1);
-    if (arg != 0)
-        GOTO_LABEL_PARAM(2);
+    T0 = (arg != 0);
     FORCE_RET();
 }
 
-OP(jmp_s32)
+OP(set_T0_s32)
 {
     int32_t arg = get_op(PARAM1);
-    if (arg < 0)
-        GOTO_LABEL_PARAM(2);
+    T0 = (arg > 0);
     FORCE_RET();
 }
 
-OP(jmp_ns32)
+OP(set_T0_ns32)
 {
     int32_t arg = get_op(PARAM1);
-    if (arg >= 0)
-        GOTO_LABEL_PARAM(2);
+    T0 = (arg >= 0);
+    FORCE_RET();
+}
+
+OP(jmp_T0)
+{
+    if (T0)
+        GOTO_LABEL_PARAM(1);
     FORCE_RET();
 }
 
@@ -679,3 +647,429 @@
     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
+
+/* MAC unit.  */
+/* TODO: The MAC instructions use 64-bit arithmetic fairly extensively.
+   This results in fairly large ops (and sometimes other issues) on 32-bit
+   hosts.  Maybe move most of them into helpers.  */
+OP(macmuls)
+{
+    uint32_t op1 = get_op(PARAM1);
+    uint32_t op2 = get_op(PARAM2);
+    int64_t product;
+    int64_t res;
+
+    product = (uint64_t)op1 * op2;
+    res = (product << 24) >> 24;
+    if (res != product) {
+        env->macsr |= MACSR_V;
+        if (env->macsr & MACSR_OMC) {
+            /* Make sure the accumulate operation overflows.  */
+            if (product < 0)
+                res = ~(1ll << 50);
+            else
+                res = 1ll << 50;
+        }
+    }
+    env->mactmp = res;
+    FORCE_RET();
+}
+
+OP(macmulu)
+{
+    uint32_t op1 = get_op(PARAM1);
+    uint32_t op2 = get_op(PARAM2);
+    uint64_t product;
+
+    product = (uint64_t)op1 * op2;
+    if (product & (0xffffffull << 40)) {
+        env->macsr |= MACSR_V;
+        if (env->macsr & MACSR_OMC) {
+            /* Make sure the accumulate operation overflows.  */
+            product = 1ll << 50;
+        } else {
+            product &= ((1ull << 40) - 1);
+        }
+    }
+    env->mactmp = product;
+    FORCE_RET();
+}
+
+OP(macmulf)
+{
+    int32_t op1 = get_op(PARAM1);
+    int32_t op2 = get_op(PARAM2);
+    uint64_t product;
+    uint32_t remainder;
+
+    product = (uint64_t)op1 * op2;
+    if (env->macsr & MACSR_RT) {
+        remainder = product & 0xffffff;
+        product >>= 24;
+        if (remainder > 0x800000)
+            product++;
+        else if (remainder == 0x800000)
+            product += (product & 1);
+    } else {
+        product >>= 24;
+    }
+    env->mactmp = product;
+    FORCE_RET();
+}
+
+OP(macshl)
+{
+    env->mactmp <<= 1;
+}
+
+OP(macshr)
+{
+    env->mactmp >>= 1;
+}
+
+OP(macadd)
+{
+    int acc = PARAM1;
+    env->macc[acc] += env->mactmp;
+    FORCE_RET();
+}
+
+OP(macsub)
+{
+    int acc = PARAM1;
+    env->macc[acc] -= env->mactmp;
+    FORCE_RET();
+}
+
+OP(macsats)
+{
+    int acc = PARAM1;
+    int64_t sum;
+    int64_t result;
+
+    sum = env->macc[acc];
+    result = (sum << 16) >> 16;
+    if (result != sum) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            /* The result is saturated to 32 bits, despite overflow occuring
+               at 48 bits.  Seems weird, but that's what the hardware docs
+               say.  */
+            result = (result >> 63) ^ 0x7fffffff;
+        }
+    }
+    env->macc[acc] = result;
+    FORCE_RET();
+}
+
+OP(macsatu)
+{
+    int acc = PARAM1;
+    uint64_t sum;
+
+    sum = env->macc[acc];
+    if (sum & (0xffffull << 48)) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            if (sum > (1ull << 53))
+                sum = 0;
+            else
+                sum = (1ull << 48) - 1;
+        } else {
+            sum &= ((1ull << 48) - 1);
+        }
+    }
+    FORCE_RET();
+}
+
+OP(macsatf)
+{
+    int acc = PARAM1;
+    int64_t sum;
+    int64_t result;
+
+    sum = env->macc[acc];
+    result = (sum << 16) >> 16;
+    if (result != sum) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_V) {
+        env->macsr |= MACSR_PAV0 << acc;
+        if (env->macsr & MACSR_OMC) {
+            result = (result >> 63) ^ 0x7fffffffffffll;
+        }
+    }
+    env->macc[acc] = result;
+    FORCE_RET();
+}
+
+OP(mac_clear_flags)
+{
+    env->macsr &= ~(MACSR_V | MACSR_Z | MACSR_N | MACSR_EV);
+}
+
+OP(mac_set_flags)
+{
+    int acc = PARAM1;
+    uint64_t val;
+    val = env->macc[acc];
+    if (val == 0)
+        env->macsr |= MACSR_Z;
+    else if (val & (1ull << 47));
+        env->macsr |= MACSR_N;
+    if (env->macsr & (MACSR_PAV0 << acc)) {
+        env->macsr |= MACSR_V;
+    }
+    if (env->macsr & MACSR_FI) {
+        val = ((int64_t)val) >> 40;
+        if (val != 0 && val != -1)
+            env->macsr |= MACSR_EV;
+    } else if (env->macsr & MACSR_SU) {
+        val = ((int64_t)val) >> 32;
+        if (val != 0 && val != -1)
+            env->macsr |= MACSR_EV;
+    } else {
+        if ((val >> 32) != 0)
+            env->macsr |= MACSR_EV;
+    }
+    FORCE_RET();
+}
+
+OP(get_macf)
+{
+    int acc = PARAM2;
+    int64_t val;
+    int rem;
+    uint32_t result;
+
+    val = env->macc[acc];
+    if (env->macsr & MACSR_SU) {
+        /* 16-bit rounding.  */
+        rem = val & 0xffffff;
+        val = (val >> 24) & 0xffffu;
+        if (rem > 0x800000)
+            val++;
+        else if (rem == 0x800000)
+            val += (val & 1);
+    } else if (env->macsr & MACSR_RT) {
+        /* 32-bit rounding.  */
+        rem = val & 0xff;
+        val >>= 8;
+        if (rem > 0x80)
+            val++;
+        else if (rem == 0x80)
+            val += (val & 1);
+    } else {
+        /* No rounding.  */
+        val >>= 8;
+    }
+    if (env->macsr & MACSR_OMC) {
+        /* Saturate.  */
+        if (env->macsr & MACSR_SU) {
+            if (val != (uint16_t) val) {
+                result = ((val >> 63) ^ 0x7fff) & 0xffff;
+            } else {
+                result = val & 0xffff;
+            }
+        } else {
+            if (val != (uint32_t)val) {
+                result = ((uint32_t)(val >> 63) & 0x7fffffff);
+            } else {
+                result = (uint32_t)val;
+            }
+        }
+    } else {
+        /* No saturation.  */
+        if (env->macsr & MACSR_SU) {
+            result = val & 0xffff;
+        } else {
+            result = (uint32_t)val;
+        }
+    }
+    set_op(PARAM1, result);
+    FORCE_RET();
+}
+
+OP(get_maci)
+{
+    int acc = PARAM2;
+    set_op(PARAM1, (uint32_t)env->macc[acc]);
+    FORCE_RET();
+}
+
+OP(get_macs)
+{
+    int acc = PARAM2;
+    int64_t val = env->macc[acc];
+    uint32_t result;
+    if (val == (int32_t)val) {
+        result = (int32_t)val;
+    } else {
+        result = (val >> 61) ^ 0x7fffffff;
+    }
+    set_op(PARAM1, result);
+    FORCE_RET();
+}
+
+OP(get_macu)
+{
+    int acc = PARAM2;
+    uint64_t val = env->macc[acc];
+    uint32_t result;
+    if ((val >> 32) == 0) {
+        result = (uint32_t)val;
+    } else {
+        result = 0xffffffffu;
+    }
+    set_op(PARAM1, result);
+    FORCE_RET();
+}
+
+OP(clear_mac)
+{
+    int acc = PARAM1;
+
+    env->macc[acc] = 0;
+    env->macsr &= ~(MACSR_PAV0 << acc);
+    FORCE_RET();
+}
+
+OP(move_mac)
+{
+    int dest = PARAM1;
+    int src = PARAM2;
+    uint32_t mask;
+    env->macc[dest] = env->macc[src];
+    mask = MACSR_PAV0 << dest;
+    if (env->macsr & (MACSR_PAV0 << src))
+        env->macsr |= mask;
+    else
+        env->macsr &= ~mask;
+    FORCE_RET();
+}
+
+OP(get_mac_extf)
+{
+    uint32_t val;
+    int acc = PARAM2;
+    val = env->macc[acc] & 0x00ff;
+    val = (env->macc[acc] >> 32) & 0xff00;
+    val |= (env->macc[acc + 1] << 16) & 0x00ff0000;
+    val |= (env->macc[acc + 1] >> 16) & 0xff000000;
+    set_op(PARAM1, val);
+    FORCE_RET();
+}
+
+OP(get_mac_exti)
+{
+    uint32_t val;
+    int acc = PARAM2;
+    val = (env->macc[acc] >> 32) & 0xffff;
+    val |= (env->macc[acc + 1] >> 16) & 0xffff0000;
+    set_op(PARAM1, val);
+    FORCE_RET();
+}
+
+OP(set_macf)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    env->macc[acc] = ((int64_t)val) << 8;
+    env->macsr &= ~(MACSR_PAV0 << acc);
+    FORCE_RET();
+}
+
+OP(set_macs)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    env->macc[acc] = val;
+    env->macsr &= ~(MACSR_PAV0 << acc);
+    FORCE_RET();
+}
+
+OP(set_macu)
+{
+    int acc = PARAM2;
+    uint32_t val = get_op(PARAM1);
+    env->macc[acc] = val;
+    env->macsr &= ~(MACSR_PAV0 << acc);
+    FORCE_RET();
+}
+
+OP(set_mac_extf)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    int64_t res;
+    int32_t tmp;
+    res = env->macc[acc] & 0xffffffff00ull;
+    tmp = (int16_t)(val & 0xff00);
+    res |= ((int64_t)tmp) << 32;
+    res |= val & 0xff;
+    env->macc[acc] = res;
+    res = env->macc[acc + 1] & 0xffffffff00ull;
+    tmp = (val & 0xff000000);
+    res |= ((int64_t)tmp) << 16;
+    res |= (val >> 16) & 0xff;
+    env->macc[acc + 1] = res;
+}
+
+OP(set_mac_exts)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    int64_t res;
+    int32_t tmp;
+    res = (uint32_t)env->macc[acc];
+    tmp = (int16_t)val;
+    res |= ((int64_t)tmp) << 32;
+    env->macc[acc] = res;
+    res = (uint32_t)env->macc[acc + 1];
+    tmp = val & 0xffff0000;
+    res |= (int64_t)tmp << 16;
+    env->macc[acc + 1] = res;
+}
+
+OP(set_mac_extu)
+{
+    int acc = PARAM2;
+    int32_t val = get_op(PARAM1);
+    uint64_t res;
+    res = (uint32_t)env->macc[acc];
+    res |= ((uint64_t)(val & 0xffff)) << 32;
+    env->macc[acc] = res;
+    res = (uint32_t)env->macc[acc + 1];
+    res |= (uint64_t)(val & 0xffff0000) << 16;
+    env->macc[acc + 1] = res;
+}
+
+OP(set_macsr)
+{
+    m68k_set_macsr(env, get_op(PARAM1));
+}
diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c
new file mode 100644
index 0000000..70b7aec
--- /dev/null
+++ b/target-m68k/op_helper.c
@@ -0,0 +1,159 @@
+/*
+ *  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
+
+extern int semihosting_enabled;
+
+#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;
+    m68k_switch_sp(env);
+    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;
+        case EXCP_HALT_INSN:
+            if (semihosting_enabled
+                    && (env->sr & SR_S) != 0
+                    && (env->pc & 3) == 0
+                    && lduw_code(env->pc - 4) == 0x4e71
+                    && ldl_code(env->pc) == 0x4e7bf000) {
+                env->pc += 4;
+                do_m68k_semihosting(env, env->dregs[0]);
+                return;
+            }
+            env->halted = 1;
+            env->exception_index = EXCP_HLT;
+            cpu_loop_exit();
+            return;
+        }
+        if (env->exception_index >= EXCP_TRAP0
+            && env->exception_index <= EXCP_TRAP15) {
+            /* Move the PC after the trap instruction.  */
+            retaddr += 2;
+        }
+    }
+
+    vector = env->exception_index << 2;
+
+    sp = env->aregs[7];
+
+    fmt |= 0x40000000;
+    fmt |= (sp & 3) << 28;
+    fmt |= vector << 16;
+    fmt |= env->sr;
+
+    env->sr |= SR_S;
+    if (is_hw) {
+        env->sr = (env->sr & ~SR_I) | (env->pending_level << SR_I_SHIFT);
+        env->sr &= ~SR_M;
+    }
+    m68k_switch_sp(env);
+
+    /* ??? This could cause MMU faults.  */
+    sp &= ~3;
+    sp -= 4;
+    stl_kernel(sp, retaddr);
+    sp -= 4;
+    stl_kernel(sp, fmt);
+    env->aregs[7] = sp;
+    /* Jump to vector.  */
+    env->pc = ldl_kernel(env->vbr + vector);
+}
+
+#endif
diff --git a/target-m68k/op_mem.h b/target-m68k/op_mem.h
new file mode 100644
index 0000000..556829f
--- /dev/null
+++ b/target-m68k/op_mem.h
@@ -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
diff --git a/target-m68k/qregs.def b/target-m68k/qregs.def
index d8c1944..bf568a5 100644
--- a/target-m68k/qregs.def
+++ b/target-m68k/qregs.def
@@ -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)
@@ -32,3 +33,5 @@
 DEFO32(DIV1, div1)
 DEFO32(DIV2, div2)
 DEFO32(EXCEPTION, exception_index)
+DEFO32(MACSR, macsr)
+DEFO32(MAC_MASK, mac_mask)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 9c34c62..f6b4fad 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -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) {
@@ -40,16 +42,26 @@
 
 /* internal defines */
 typedef struct DisasContext {
+    CPUM68KState *env;
+    target_ulong insn_pc; /* Start of the current instruction.  */
     target_ulong pc;
     int is_jmp;
     int cc_op;
+    int user;
     uint32_t fpcr;
     struct TranslationBlock *tb;
     int singlestep_enabled;
+    int is_mem;
 } DisasContext;
 
 #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 +80,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
@@ -80,61 +111,52 @@
 #define AREG(insn, pos) (((insn >> pos) & 7) + QREG_A0)
 #define FREG(insn, pos) (((insn >> pos) & 7) + QREG_F0)
 
-#define M68K_INSN_CF_A    (1 << 0)
-#define M68K_INSN_CF_B    (1 << 1)
-#define M68K_INSN_CF_C    (1 << 2)
-#define M68K_INSN_CF_MAC  (1 << 3)
-#define M68K_INSN_CF_EMAC (1 << 4)
-#define M68K_INSN_CF_FPU  (1 << 5)
-
-struct m68k_def_t {
-    const char * name;
-    uint32_t insns;
-};
-
-static m68k_def_t m68k_cpu_defs[] = {
-    {"m5206", M68K_INSN_CF_A},
-    {"cfv4e", M68K_INSN_CF_A | M68K_INSN_CF_B | M68K_INSN_CF_C
-            | M68K_INSN_CF_MAC | M68K_INSN_CF_EMAC | M68K_INSN_CF_FPU},
-    {NULL, 0}, 
-};
-
 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;
+    s->is_mem = 1;
     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 +166,24 @@
 }
 
 /* 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)
 {
+    s->is_mem = 1;
     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,59 +193,148 @@
 
 /* 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);
     }
 }
 
-/* Handle a base + index + displacement effective addresss.  A base of
-   -1 means pc-relative.  */
-static int gen_lea_indexed(DisasContext *s, int opsize, int base)
-{
-    int scale;
-    uint32_t offset;
-    uint16_t ext;
-    int add;
-    int tmp;
-
-    offset = s->pc;
-    ext = lduw(s->pc);
-    s->pc += 2;
-    tmp = ((ext >> 12) & 7) + ((ext & 0x8000) ? QREG_A0 : QREG_D0);
-    /* ??? Check W/L bit.  */
-    scale = (ext >> 9) & 3;
-    if (scale == 0) {
-        add = tmp;
-    } else {
-        add = gen_new_qreg(QMODE_I32);
-        gen_op_shl32(add, tmp, gen_im32(scale));
-    }
-    tmp = gen_new_qreg(QMODE_I32);
-    if (base != -1) {
-        gen_op_add32(tmp, base, gen_im32((int8_t)ext));
-        gen_op_add32(tmp, tmp, add);
-    } else {
-        gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext));
-    }
-    return tmp;
-}
-
 /* Read a 32-bit immediate constant.  */
 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;
 }
 
+/* Calculate and address index.  */
+static int gen_addr_index(uint16_t ext, int tmp)
+{
+    int add;
+    int scale;
+
+    add = (ext & 0x8000) ? AREG(ext, 12) : DREG(ext, 12);
+    if ((ext & 0x800) == 0) {
+        gen_op_ext16s32(tmp, add);
+        add = tmp;
+    }
+    scale = (ext >> 9) & 3;
+    if (scale != 0) {
+        gen_op_shl32(tmp, add, gen_im32(scale));
+        add = tmp;
+    }
+    return add;
+}
+
+/* Handle a base + index + displacement effective addresss.  A base of
+   -1 means pc-relative.  */
+static int gen_lea_indexed(DisasContext *s, int opsize, int base)
+{
+    uint32_t offset;
+    uint16_t ext;
+    int add;
+    int tmp;
+    uint32_t bd, od;
+
+    offset = s->pc;
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX))
+        return -1;
+
+    if (ext & 0x100) {
+        /* full extension word format */
+        if (!m68k_feature(s->env, M68K_FEATURE_EXT_FULL))
+            return -1;
+
+        if ((ext & 0x30) > 0x10) {
+            /* base displacement */
+            if ((ext & 0x30) == 0x20) {
+                bd = (int16_t)lduw_code(s->pc);
+                s->pc += 2;
+            } else {
+                bd = read_im32(s);
+            }
+        } else {
+            bd = 0;
+        }
+        tmp = gen_new_qreg(QMODE_I32);
+        if ((ext & 0x44) == 0) {
+            /* pre-index */
+            add = gen_addr_index(ext, tmp);
+        } else {
+            add = QREG_NULL;
+        }
+        if ((ext & 0x80) == 0) {
+            /* base not suppressed */
+            if (base == -1) {
+                base = gen_im32(offset + bd);
+                bd = 0;
+            }
+            if (add) {
+                gen_op_add32(tmp, add, base);
+                add = tmp;
+            } else {
+                add = base;
+            }
+        }
+        if (add) {
+            if (bd != 0) {
+                gen_op_add32(tmp, add, gen_im32(bd));
+                add = tmp;
+            }
+        } else {
+            add = gen_im32(bd);
+        }
+        if ((ext & 3) != 0) {
+            /* memory indirect */
+            base = gen_load(s, OS_LONG, add, 0);
+            if ((ext & 0x44) == 4) {
+                add = gen_addr_index(ext, tmp);
+                gen_op_add32(tmp, add, base);
+                add = tmp;
+            } else {
+                add = base;
+            }
+            if ((ext & 3) > 1) {
+                /* outer displacement */
+                if ((ext & 3) == 2) {
+                    od = (int16_t)lduw_code(s->pc);
+                    s->pc += 2;
+                } else {
+                    od = read_im32(s);
+                }
+            } else {
+                od = 0;
+            }
+            if (od != 0) {
+                gen_op_add32(tmp, add, gen_im32(od));
+                add = tmp;
+            }
+        }
+    } else {
+        /* brief extension word format */
+        tmp = gen_new_qreg(QMODE_I32);
+        add = gen_addr_index(ext, tmp);
+        if (base != -1) {
+            gen_op_add32(tmp, add, base);
+            if ((int8_t)ext)
+                gen_op_add32(tmp, tmp, gen_im32((int8_t)ext));
+        } else {
+            gen_op_add32(tmp, add, gen_im32(offset + (int8_t)ext));
+        }
+        add = tmp;
+    }
+    return add;
+}
 
 /* Update the CPU env CC_OP state.  */
 static inline void gen_flush_cc_op(DisasContext *s)
@@ -236,7 +348,8 @@
 {
     if (s->cc_op == CC_OP_FLAGS)
         return;
-    gen_op_flush_flags(s->cc_op);
+    gen_flush_cc_op(s);
+    gen_op_flush_flags();
     s->cc_op = CC_OP_FLAGS;
 }
 
@@ -329,8 +442,7 @@
     switch ((insn >> 3) & 7) {
     case 0: /* Data register direct.  */
     case 1: /* Address register direct.  */
-        /* ??? generate bad addressing mode fault.  */
-        qemu_assert(0, "invalid addressing mode");
+        return -1;
     case 2: /* Indirect register */
     case 3: /* Indirect postincrement.  */
         reg += QREG_A0;
@@ -343,7 +455,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 +465,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,15 +474,14 @@
         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.  */
             return gen_lea_indexed(s, opsize, -1);
         case 4: /* Immediate.  */
         default:
-            /* ??? generate bad addressing mode fault.  */
-            qemu_assert(0, "invalid addressing mode");
+            return -1;
         }
     }
     /* Should never happen.  */
@@ -388,10 +499,12 @@
         tmp = *addrp;
     } else {
         tmp = gen_lea(s, insn, opsize);
+        if (tmp == -1)
+            return -1;
         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 +537,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)
@@ -440,10 +553,12 @@
                 tmp = *addrp;
             } else {
                 tmp = gen_lea(s, insn, opsize);
+                if (tmp == -1)
+                    return -1;
                 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 +582,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:
@@ -487,7 +602,7 @@
             }
             return gen_im32(offset);
         default:
-            qemu_assert(0, "invalid addressing mode");
+            return -1;
         }
     }
     /* Should never happen.  */
@@ -622,6 +737,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)
 {
@@ -637,6 +760,27 @@
     gen_op_raise_exception(nr);
 }
 
+static inline void gen_addr_fault(DisasContext *s)
+{
+    gen_exception(s, s->insn_pc, EXCP_ADDRESS);
+}
+
+#define SRC_EA(result, opsize, val, addrp) do { \
+    result = gen_ea(s, insn, opsize, val, addrp); \
+    if (result == -1) { \
+        gen_addr_fault(s); \
+        return; \
+    } \
+    } while (0)
+
+#define DEST_EA(insn, opsize, val, addrp) do { \
+    int ea_result = gen_ea(s, insn, opsize, val, addrp); \
+    if (ea_result == -1) { \
+        gen_addr_fault(s); \
+        return; \
+    } \
+    } while (0)
+
 /* Generate a jump to an immediate address.  */
 static void gen_jmp_tb(DisasContext *s, int n, uint32_t dest)
 {
@@ -690,7 +834,7 @@
         gen_op_ext16s32(tmp, reg);
     else
         gen_op_ext16u32(tmp, reg);
-    src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL);
+    SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL);
     gen_op_mul32(tmp, tmp, src);
     gen_op_mov32(reg, tmp);
     /* Unlike m68k, coldfire always clears the overflow bit.  */
@@ -711,7 +855,7 @@
     } else {
         gen_op_ext16u32(QREG_DIV1, reg);
     }
-    src = gen_ea(s, insn, OS_WORD, sign ? -1 : 0, NULL);
+    SRC_EA(src, OS_WORD, sign ? -1 : 0, NULL);
     gen_op_mov32(QREG_DIV2, src);
     if (sign) {
         gen_op_divs(1);
@@ -735,7 +879,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);
@@ -744,7 +888,7 @@
     num = DREG(ext, 12);
     reg = DREG(ext, 0);
     gen_op_mov32(QREG_DIV1, num);
-    den = gen_ea(s, insn, OS_LONG, 0, NULL);
+    SRC_EA(den, OS_LONG, 0, NULL);
     gen_op_mov32(QREG_DIV2, den);
     if (ext & 0x0800) {
         gen_op_divs(2);
@@ -775,11 +919,11 @@
     reg = DREG(insn, 9);
     dest = gen_new_qreg(QMODE_I32);
     if (insn & 0x100) {
-        tmp = gen_ea(s, insn, OS_LONG, 0, &addr);
+        SRC_EA(tmp, OS_LONG, 0, &addr);
         src = reg;
     } else {
         tmp = reg;
-        src = gen_ea(s, insn, OS_LONG, 0, NULL);
+        SRC_EA(src, OS_LONG, 0, NULL);
     }
     if (add) {
         gen_op_add32(dest, tmp, src);
@@ -792,7 +936,7 @@
     }
     gen_op_update_cc_add(dest, src);
     if (insn & 0x100) {
-        gen_ea(s, insn, OS_LONG, dest, &addr);
+        DEST_EA(insn, OS_LONG, dest, &addr);
     } else {
         gen_op_mov32(reg, dest);
     }
@@ -850,7 +994,7 @@
     else
         opsize = OS_LONG;
     op = (insn >> 6) & 3;
-    src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL);
+    SRC_EA(src1, opsize, 0, op ? &addr: NULL);
     src2 = DREG(insn, 9);
     dest = gen_new_qreg(QMODE_I32);
 
@@ -880,7 +1024,7 @@
         break;
     }
     if (op)
-        gen_ea(s, insn, opsize, dest, &addr);
+        DEST_EA(insn, opsize, dest, &addr);
 }
 
 DISAS_INSN(sats)
@@ -903,13 +1047,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,9 +1066,13 @@
     int tmp;
     int is_load;
 
-    mask = lduw(s->pc);
+    mask = lduw_code(s->pc);
     s->pc += 2;
     tmp = gen_lea(s, insn, OS_LONG);
+    if (tmp == -1) {
+        gen_addr_fault(s);
+        return;
+    }
     addr = gen_new_qreg(QMODE_I32);
     gen_op_mov32(addr, tmp);
     is_load = ((insn & 0x0400) != 0);
@@ -935,10 +1083,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,14 +1111,14 @@
         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);
         return;
     }
 
-    src1 = gen_ea(s, insn, opsize, 0, op ? &addr: NULL);
+    SRC_EA(src1, opsize, 0, op ? &addr: NULL);
 
     gen_flush_flags(s);
     tmp = gen_new_qreg(QMODE_I32);
@@ -1000,7 +1148,7 @@
         break;
     }
     if (op)
-        gen_ea(s, insn, opsize, dest, &addr);
+        DEST_EA(insn, opsize, dest, &addr);
 }
 
 DISAS_INSN(arith_im)
@@ -1012,7 +1160,7 @@
     int addr;
 
     op = (insn >> 9) & 7;
-    src1 = gen_ea(s, insn, OS_LONG, 0, (op == 6) ? NULL : &addr);
+    SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr);
     src2 = gen_im32(read_im32(s));
     dest = gen_new_qreg(QMODE_I32);
     switch (op) {
@@ -1052,7 +1200,7 @@
         abort();
     }
     if (op != 6) {
-        gen_ea(s, insn, OS_LONG, dest, &addr);
+        DEST_EA(insn, OS_LONG, dest, &addr);
     }
 }
 
@@ -1084,7 +1232,7 @@
     default:
         abort();
     }
-    src = gen_ea(s, insn, opsize, -1, NULL);
+    SRC_EA(src, opsize, -1, NULL);
     op = (insn >> 6) & 7;
     if (op == 1) {
         /* movea */
@@ -1095,7 +1243,7 @@
         /* normal move */
         uint16_t dest_ea;
         dest_ea = ((insn >> 9) & 7) | (op << 3);
-        gen_ea(s, dest_ea, opsize, src, NULL);
+        DEST_EA(dest_ea, opsize, src, NULL);
         /* This will be correct because loads sign extend.  */
         gen_logic_cc(s, src);
     }
@@ -1131,6 +1279,10 @@
 
     reg = AREG(insn, 9);
     tmp = gen_lea(s, insn, OS_LONG);
+    if (tmp == -1) {
+        gen_addr_fault(s);
+        return;
+    }
     gen_op_mov32(reg, tmp);
 }
 
@@ -1151,13 +1303,12 @@
     default:
         abort();
     }
-    gen_ea (s, insn, opsize, gen_im32(0), NULL);
+    DEST_EA(insn, opsize, gen_im32(0), NULL);
     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 +1316,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,7 +1344,16 @@
     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_set_sr(gen_im32(val & 0xff00));
+    }
+}
+
+static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only)
 {
     int src1;
     int reg;
@@ -1199,19 +1368,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_set_sr(reg);
+        }
       }
-    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 +1420,11 @@
     int tmp;
 
     tmp = gen_lea(s, insn, OS_LONG);
-    gen_push(tmp);
+    if (tmp == -1) {
+        gen_addr_fault(s);
+        return;
+    }
+    gen_push(s, tmp);
 }
 
 DISAS_INSN(ext)
@@ -1285,7 +1465,7 @@
     default:
         abort();
     }
-    tmp = gen_ea(s, insn, opsize, -1, NULL);
+    SRC_EA(tmp, opsize, -1, NULL);
     gen_logic_cc(s, tmp);
 }
 
@@ -1307,10 +1487,10 @@
     int addr;
 
     dest = gen_new_qreg(QMODE_I32);
-    src1 = gen_ea(s, insn, OS_BYTE, -1, &addr);
+    SRC_EA(src1, OS_BYTE, -1, &addr);
     gen_logic_cc(s, src1);
     gen_op_or32(dest, src1, gen_im32(0x80));
-    gen_ea(s, insn, OS_BYTE, dest, &addr);
+    DEST_EA(insn, OS_BYTE, dest, &addr);
 }
 
 DISAS_INSN(mull)
@@ -1322,14 +1502,14 @@
 
     /* 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);
         return;
     }
     reg = DREG(ext, 12);
-    src1 = gen_ea(s, insn, OS_LONG, 0, NULL);
+    SRC_EA(src1, OS_LONG, 0, NULL);
     dest = gen_new_qreg(QMODE_I32);
     gen_op_mul32(dest, src1, reg);
     gen_op_mov32(reg, dest);
@@ -1343,12 +1523,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 +1543,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 +1556,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);
 }
@@ -1388,9 +1568,13 @@
     /* Load the target address first to ensure correct exception
        behavior.  */
     tmp = gen_lea(s, insn, OS_LONG);
+    if (tmp == -1) {
+        gen_addr_fault(s);
+        return;
+    }
     if ((insn & 0x40) == 0) {
         /* jsr */
-        gen_push(gen_im32(s->pc));
+        gen_push(s, gen_im32(s->pc));
     }
     gen_jmp(s, tmp);
 }
@@ -1403,7 +1587,7 @@
     int val;
     int addr;
 
-    src1 = gen_ea(s, insn, OS_LONG, 0, &addr);
+    SRC_EA(src1, OS_LONG, 0, &addr);
     val = (insn >> 9) & 7;
     if (val == 0)
         val = 8;
@@ -1430,7 +1614,7 @@
         }
         gen_op_update_cc_add(dest, src2);
     }
-    gen_ea(s, insn, OS_LONG, dest, &addr);
+    DEST_EA(insn, OS_LONG, dest, &addr);
 }
 
 DISAS_INSN(tpf)
@@ -1455,19 +1639,19 @@
     uint32_t base;
     int op;
     int l1;
-    
+
     base = s->pc;
     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) {
@@ -1502,7 +1686,7 @@
         opsize = OS_WORD;
     else
         opsize = OS_BYTE;
-    src = gen_ea(s, insn, opsize, (insn & 0x80) ? 0 : -1, NULL);
+    SRC_EA(src, opsize, (insn & 0x80) ? 0 : -1, NULL);
     reg = DREG(insn, 9);
     gen_op_mov32(reg, src);
     gen_logic_cc(s, src);
@@ -1518,11 +1702,11 @@
     reg = DREG(insn, 9);
     dest = gen_new_qreg(QMODE_I32);
     if (insn & 0x100) {
-        src = gen_ea(s, insn, OS_LONG, 0, &addr);
+        SRC_EA(src, OS_LONG, 0, &addr);
         gen_op_or32(dest, src, reg);
-        gen_ea(s, insn, OS_LONG, dest, &addr);
+        DEST_EA(insn, OS_LONG, dest, &addr);
     } else {
-        src = gen_ea(s, insn, OS_LONG, 0, NULL);
+        SRC_EA(src, OS_LONG, 0, NULL);
         gen_op_or32(dest, src, reg);
         gen_op_mov32(reg, dest);
     }
@@ -1534,7 +1718,7 @@
     int src;
     int reg;
 
-    src = gen_ea(s, insn, OS_LONG, 0, NULL);
+    SRC_EA(src, OS_LONG, 0, NULL);
     reg = AREG(insn, 9);
     gen_op_sub32(reg, reg, src);
 }
@@ -1574,7 +1758,7 @@
         val = -1;
     src = gen_im32(val);
     gen_logic_cc(s, src);
-    gen_ea(s, insn, OS_LONG, src, NULL);
+    DEST_EA(insn, OS_LONG, src, NULL);
 }
 
 DISAS_INSN(cmp)
@@ -1602,7 +1786,7 @@
     default:
         abort();
     }
-    src = gen_ea(s, insn, opsize, -1, NULL);
+    SRC_EA(src, opsize, -1, NULL);
     reg = DREG(insn, 9);
     dest = gen_new_qreg(QMODE_I32);
     gen_op_sub32(dest, reg, src);
@@ -1621,7 +1805,7 @@
     } else {
         opsize = OS_WORD;
     }
-    src = gen_ea(s, insn, opsize, -1, NULL);
+    SRC_EA(src, opsize, -1, NULL);
     reg = AREG(insn, 9);
     dest = gen_new_qreg(QMODE_I32);
     gen_op_sub32(dest, reg, src);
@@ -1636,12 +1820,12 @@
     int dest;
     int addr;
 
-    src = gen_ea(s, insn, OS_LONG, 0, &addr);
+    SRC_EA(src, OS_LONG, 0, &addr);
     reg = DREG(insn, 9);
     dest = gen_new_qreg(QMODE_I32);
     gen_op_xor32(dest, src, reg);
     gen_logic_cc(s, dest);
-    gen_ea(s, insn, OS_LONG, dest, &addr);
+    DEST_EA(insn, OS_LONG, dest, &addr);
 }
 
 DISAS_INSN(and)
@@ -1654,11 +1838,11 @@
     reg = DREG(insn, 9);
     dest = gen_new_qreg(QMODE_I32);
     if (insn & 0x100) {
-        src = gen_ea(s, insn, OS_LONG, 0, &addr);
+        SRC_EA(src, OS_LONG, 0, &addr);
         gen_op_and32(dest, src, reg);
-        gen_ea(s, insn, OS_LONG, dest, &addr);
+        DEST_EA(insn, OS_LONG, dest, &addr);
     } else {
-        src = gen_ea(s, insn, OS_LONG, 0, NULL);
+        SRC_EA(src, OS_LONG, 0, NULL);
         gen_op_and32(dest, src, reg);
         gen_op_mov32(reg, dest);
     }
@@ -1670,7 +1854,7 @@
     int src;
     int reg;
 
-    src = gen_ea(s, insn, OS_LONG, 0, NULL);
+    SRC_EA(src, OS_LONG, 0, NULL);
     reg = AREG(insn, 9);
     gen_op_add32(reg, reg, src);
 }
@@ -1749,7 +1933,22 @@
 
 DISAS_INSN(ff1)
 {
-    cpu_abort(NULL, "Unimplemented insn: ff1");
+    int reg;
+    reg = DREG(insn, 0);
+    gen_logic_cc(s, reg);
+    gen_op_ff1(reg, reg);
+}
+
+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)
@@ -1758,62 +1957,136 @@
     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_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);
+    gen_jmp(s, gen_im32(s->pc));
+    gen_op_stop();
 }
 
 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 +2096,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 +2121,7 @@
     int round;
     int opsize;
 
-    ext = lduw(s->pc);
+    ext = lduw_code(s->pc);
     s->pc += 2;
     opmode = ext & 0x7f;
     switch ((ext >> 13) & 7) {
@@ -1883,7 +2161,7 @@
         default:
             goto undef;
         }
-        gen_ea(s, insn, opsize, res, NULL);
+        DEST_EA(insn, opsize, res, NULL);
         return;
     case 4: /* fmove to control register.  */
         switch ((ext >> 10) & 7) {
@@ -1910,9 +2188,9 @@
                       (ext >> 10) & 7);
             goto undef;
         }
-        gen_ea(s, insn, OS_LONG, res, NULL);
+        DEST_EA(insn, OS_LONG, res, NULL);
         break;
-    case 6: /* fmovem */ 
+    case 6: /* fmovem */
     case 7:
         {
         int addr;
@@ -1920,18 +2198,23 @@
         if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0)
             goto undef;
         src = gen_lea(s, insn, OS_LONG);
+        if (src == -1) {
+            gen_addr_fault(s);
+            return;
+        }
         addr = gen_new_qreg(QMODE_I32);
         gen_op_mov32(addr, src);
         mask = 0x80;
         dest = QREG_F0;
         while (mask) {
             if (ext & mask) {
+                s->is_mem = 1;
                 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));
@@ -1955,7 +2238,7 @@
         default:
             goto undef;
         }
-        tmp = gen_ea(s, insn, opsize, -1, NULL);
+        SRC_EA(tmp, opsize, -1, NULL);
         if (opsize == OS_DOUBLE) {
             src = tmp;
         } else {
@@ -2040,7 +2323,7 @@
         tmp = gen_new_qreg(QMODE_F32);
         gen_op_f64_to_f32(tmp, res);
         gen_op_f32_to_f64(res, tmp);
-    } 
+    }
     gen_op_fp_result(res);
     if (dest) {
         gen_op_movf64(dest, res);
@@ -2060,10 +2343,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 +2426,295 @@
     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 inline int gen_mac_extract_word(DisasContext *s, int val, int upper)
+{
+    int tmp = gen_new_qreg(QMODE_I32);
+    if (s->env->macsr & MACSR_FI) {
+        if (upper)
+            gen_op_and32(tmp, val, gen_im32(0xffff0000));
+        else
+            gen_op_shl32(tmp, val, gen_im32(16));
+    } else if (s->env->macsr & MACSR_SU) {
+        if (upper)
+            gen_op_sar32(tmp, val, gen_im32(16));
+        else
+            gen_op_ext16s32(tmp, val);
+    } else {
+        if (upper)
+            gen_op_shr32(tmp, val, gen_im32(16));
+        else
+            gen_op_ext16u32(tmp, val);
+    }
+    return tmp;
+}
+
+DISAS_INSN(mac)
+{
+    int rx;
+    int ry;
+    uint16_t ext;
+    int acc;
+    int l1;
+    int tmp;
+    int addr;
+    int loadval;
+    int dual;
+    int saved_flags = -1;
+
+    ext = lduw_code(s->pc);
+    s->pc += 2;
+
+    acc = ((insn >> 7) & 1) | ((ext >> 3) & 2);
+    dual = ((insn & 0x30) != 0 && (ext & 3) != 0);
+    if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) {
+        disas_undef(s, insn);
+        return;
+    }
+    if (insn & 0x30) {
+        /* MAC with load.  */
+        tmp = gen_lea(s, insn, OS_LONG);
+        addr = gen_new_qreg(QMODE_I32);
+        gen_op_and32(addr, tmp, QREG_MAC_MASK);
+        /* Load the value now to ensure correct exception behavior.
+           Perform writeback after reading the MAC inputs.  */
+        loadval = gen_load(s, OS_LONG, addr, 0);
+
+        acc ^= 1;
+        rx = (ext & 0x8000) ? AREG(ext, 12) : DREG(insn, 12);
+        ry = (ext & 8) ? AREG(ext, 0) : DREG(ext, 0);
+    } else {
+        loadval = addr = -1;
+        rx = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
+        ry = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    }
+
+    gen_op_mac_clear_flags();
+    l1 = -1;
+    if ((s->env->macsr & MACSR_OMC) != 0 && !dual) {
+        /* Skip the multiply if we know we will ignore it.  */
+        l1 = gen_new_label();
+        tmp = gen_new_qreg(QMODE_I32);
+        gen_op_and32(tmp, QREG_MACSR, gen_im32(1 << (acc + 8)));
+        gen_op_jmp_nz32(tmp, l1);
+    }
+
+    if ((ext & 0x0800) == 0) {
+        /* Word.  */
+        rx = gen_mac_extract_word(s, rx, (ext & 0x80) != 0);
+        ry = gen_mac_extract_word(s, ry, (ext & 0x40) != 0);
+    }
+    if (s->env->macsr & MACSR_FI) {
+        gen_op_macmulf(rx, ry);
+    } else {
+        if (s->env->macsr & MACSR_SU)
+            gen_op_macmuls(rx, ry);
+        else
+            gen_op_macmulu(rx, ry);
+        switch ((ext >> 9) & 3) {
+        case 1:
+            gen_op_macshl();
+            break;
+        case 3:
+            gen_op_macshr();
+            break;
+        }
+    }
+
+    if (dual) {
+        /* Save the overflow flag from the multiply.  */
+        saved_flags = gen_new_qreg(QMODE_I32);
+        gen_op_mov32(saved_flags, QREG_MACSR);
+    }
+
+    if ((s->env->macsr & MACSR_OMC) != 0 && dual) {
+        /* Skip the accumulate if the value is already saturated.  */
+        l1 = gen_new_label();
+        tmp = gen_new_qreg(QMODE_I32);
+        gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+        gen_op_jmp_nz32(tmp, l1);
+    }
+
+    if (insn & 0x100)
+        gen_op_macsub(acc);
+    else
+        gen_op_macadd(acc);
+
+    if (s->env->macsr & MACSR_FI)
+        gen_op_macsatf(acc);
+    else if (s->env->macsr & MACSR_SU)
+        gen_op_macsats(acc);
+    else
+        gen_op_macsatu(acc);
+
+    if (l1 != -1)
+        gen_set_label(l1);
+
+    if (dual) {
+        /* Dual accumulate variant.  */
+        acc = (ext >> 2) & 3;
+        /* Restore the overflow flag from the multiplier.  */
+        gen_op_mov32(QREG_MACSR, saved_flags);
+        if ((s->env->macsr & MACSR_OMC) != 0) {
+            /* Skip the accumulate if the value is already saturated.  */
+            l1 = gen_new_label();
+            tmp = gen_new_qreg(QMODE_I32);
+            gen_op_and32(tmp, QREG_MACSR, gen_im32(MACSR_PAV0 << acc));
+            gen_op_jmp_nz32(tmp, l1);
+        }
+        if (ext & 2)
+            gen_op_macsub(acc);
+        else
+            gen_op_macadd(acc);
+        if (s->env->macsr & MACSR_FI)
+            gen_op_macsatf(acc);
+        else if (s->env->macsr & MACSR_SU)
+            gen_op_macsats(acc);
+        else
+            gen_op_macsatu(acc);
+        if (l1 != -1)
+            gen_set_label(l1);
+    }
+    gen_op_mac_set_flags(acc);
+
+    if (insn & 0x30) {
+        int rw;
+        rw = (insn & 0x40) ? AREG(insn, 9) : DREG(insn, 9);
+        gen_op_mov32(rw, loadval);
+        /* FIXME: Should address writeback happen with the masked or
+           unmasked value?  */
+        switch ((insn >> 3) & 7) {
+        case 3: /* Post-increment.  */
+            gen_op_add32(AREG(insn, 0), addr, gen_im32(4));
+            break;
+        case 4: /* Pre-decrement.  */
+            gen_op_mov32(AREG(insn, 0), addr);
+        }
+    }
+}
+
+DISAS_INSN(from_mac)
+{
+    int rx;
+    int acc;
+
+    rx = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    acc = (insn >> 9) & 3;
+    if (s->env->macsr & MACSR_FI) {
+        gen_op_get_macf(rx, acc);
+    } else if ((s->env->macsr & MACSR_OMC) == 0) {
+        gen_op_get_maci(rx, acc);
+    } else if (s->env->macsr & MACSR_SU) {
+        gen_op_get_macs(rx, acc);
+    } else {
+        gen_op_get_macu(rx, acc);
+    }
+    if (insn & 0x40)
+        gen_op_clear_mac(acc);
+}
+
+DISAS_INSN(move_mac)
+{
+    int src;
+    int dest;
+    src = insn & 3;
+    dest = (insn >> 9) & 3;
+    gen_op_move_mac(dest, src);
+    gen_op_mac_clear_flags();
+    gen_op_mac_set_flags(dest);
+}
+
+DISAS_INSN(from_macsr)
+{
+    int reg;
+
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    gen_op_mov32(reg, QREG_MACSR);
+}
+
+DISAS_INSN(from_mask)
+{
+    int reg;
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    gen_op_mov32(reg, QREG_MAC_MASK);
+}
+
+DISAS_INSN(from_mext)
+{
+    int reg;
+    int acc;
+    reg = (insn & 8) ? AREG(insn, 0) : DREG(insn, 0);
+    acc = (insn & 0x400) ? 2 : 0;
+    if (s->env->macsr & MACSR_FI)
+        gen_op_get_mac_extf(reg, acc);
+    else
+        gen_op_get_mac_exti(reg, acc);
+}
+
+DISAS_INSN(macsr_to_ccr)
+{
+    gen_op_mov32(QREG_CC_X, gen_im32(0));
+    gen_op_and32(QREG_CC_DEST, QREG_MACSR, gen_im32(0xf));
+    s->cc_op = CC_OP_FLAGS;
+}
+
+DISAS_INSN(to_mac)
+{
+    int acc;
+    int val;
+    acc = (insn >>9) & 3;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    if (s->env->macsr & MACSR_FI) {
+        gen_op_set_macf(val, acc);
+    } else if (s->env->macsr & MACSR_SU) {
+        gen_op_set_macs(val, acc);
+    } else {
+        gen_op_set_macu(val, acc);
+    }
+    gen_op_mac_clear_flags();
+    gen_op_mac_set_flags(acc);
+}
+
+DISAS_INSN(to_macsr)
+{
+    int val;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    gen_op_set_macsr(val);
+    gen_lookup_tb(s);
+}
+
+DISAS_INSN(to_mask)
+{
+    int val;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    gen_op_or32(QREG_MAC_MASK, val, gen_im32(0xffff0000));
+}
+
+DISAS_INSN(to_mext)
+{
+    int val;
+    int acc;
+    SRC_EA(val, OS_LONG, 0, NULL);
+    acc = (insn & 0x400) ? 2 : 0;
+    if (s->env->macsr & MACSR_FI)
+        gen_op_set_mac_extf(val, acc);
+    else if (s->env->macsr & MACSR_SU)
+        gen_op_set_mac_exts(val, acc);
+    else
+        gen_op_set_mac_extu(val, acc);
+}
+
 static disas_proc opcode_table[65536];
 
 static void
@@ -2153,8 +2725,12 @@
   int to;
 
   /* Sanity check.  All set bits must be included in the mask.  */
-  if (opcode & ~mask)
+  if (opcode & ~mask) {
+      fprintf(stderr,
+              "qemu internal error: bogus opcode definition %04x/%04x\n",
+              opcode, mask);
       abort();
+  }
   /* This could probably be cleverer.  For now just optimize the case where
      the top bits are known.  */
   /* Find the first zero bit in the mask.  */
@@ -2168,116 +2744,135 @@
       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.
    Later insn override earlier ones.  */
-static void
-register_m68k_insns (m68k_def_t *def)
+void register_m68k_insns (CPUM68KState *env)
 {
-    uint32_t iflags;
+#define INSN(name, opcode, mask, feature) do { \
+    if (m68k_feature(env, M68K_FEATURE_##feature)) \
+        register_opcode(disas_##name, 0x##opcode, 0x##mask); \
+    } while(0)
+    INSN(undef,     0000, 0000, CF_ISA_A);
+    INSN(arith_im,  0080, fff8, CF_ISA_A);
+    INSN(bitrev,    00c0, fff8, CF_ISA_APLUSC);
+    INSN(bitop_reg, 0100, f1c0, CF_ISA_A);
+    INSN(bitop_reg, 0140, f1c0, CF_ISA_A);
+    INSN(bitop_reg, 0180, f1c0, CF_ISA_A);
+    INSN(bitop_reg, 01c0, f1c0, CF_ISA_A);
+    INSN(arith_im,  0280, fff8, CF_ISA_A);
+    INSN(byterev,   02c0, fff8, CF_ISA_APLUSC);
+    INSN(arith_im,  0480, fff8, CF_ISA_A);
+    INSN(ff1,       04c0, fff8, CF_ISA_APLUSC);
+    INSN(arith_im,  0680, fff8, CF_ISA_A);
+    INSN(bitop_im,  0800, ffc0, CF_ISA_A);
+    INSN(bitop_im,  0840, ffc0, CF_ISA_A);
+    INSN(bitop_im,  0880, ffc0, CF_ISA_A);
+    INSN(bitop_im,  08c0, ffc0, CF_ISA_A);
+    INSN(arith_im,  0a80, fff8, CF_ISA_A);
+    INSN(arith_im,  0c00, ff38, CF_ISA_A);
+    INSN(move,      1000, f000, CF_ISA_A);
+    INSN(move,      2000, f000, CF_ISA_A);
+    INSN(move,      3000, f000, CF_ISA_A);
+    INSN(strldsr,   40e7, ffff, CF_ISA_APLUSC);
+    INSN(negx,      4080, fff8, CF_ISA_A);
+    INSN(move_from_sr, 40c0, fff8, CF_ISA_A);
+    INSN(lea,       41c0, f1c0, CF_ISA_A);
+    INSN(clr,       4200, ff00, CF_ISA_A);
+    INSN(undef,     42c0, ffc0, CF_ISA_A);
+    INSN(move_from_ccr, 42c0, fff8, CF_ISA_A);
+    INSN(neg,       4480, fff8, CF_ISA_A);
+    INSN(move_to_ccr, 44c0, ffc0, CF_ISA_A);
+    INSN(not,       4680, fff8, CF_ISA_A);
+    INSN(move_to_sr, 46c0, ffc0, CF_ISA_A);
+    INSN(pea,       4840, ffc0, CF_ISA_A);
+    INSN(swap,      4840, fff8, CF_ISA_A);
+    INSN(movem,     48c0, fbc0, CF_ISA_A);
+    INSN(ext,       4880, fff8, CF_ISA_A);
+    INSN(ext,       48c0, fff8, CF_ISA_A);
+    INSN(ext,       49c0, fff8, CF_ISA_A);
+    INSN(tst,       4a00, ff00, CF_ISA_A);
+    INSN(tas,       4ac0, ffc0, CF_ISA_B);
+    INSN(halt,      4ac8, ffff, CF_ISA_A);
+    INSN(pulse,     4acc, ffff, CF_ISA_A);
+    INSN(illegal,   4afc, ffff, CF_ISA_A);
+    INSN(mull,      4c00, ffc0, CF_ISA_A);
+    INSN(divl,      4c40, ffc0, CF_ISA_A);
+    INSN(sats,      4c80, fff8, CF_ISA_B);
+    INSN(trap,      4e40, fff0, CF_ISA_A);
+    INSN(link,      4e50, fff8, CF_ISA_A);
+    INSN(unlk,      4e58, fff8, CF_ISA_A);
+    INSN(move_to_usp, 4e60, fff8, USP);
+    INSN(move_from_usp, 4e68, fff8, USP);
+    INSN(nop,       4e71, ffff, CF_ISA_A);
+    INSN(stop,      4e72, ffff, CF_ISA_A);
+    INSN(rte,       4e73, ffff, CF_ISA_A);
+    INSN(rts,       4e75, ffff, CF_ISA_A);
+    INSN(movec,     4e7b, ffff, CF_ISA_A);
+    INSN(jump,      4e80, ffc0, CF_ISA_A);
+    INSN(jump,      4ec0, ffc0, CF_ISA_A);
+    INSN(addsubq,   5180, f1c0, CF_ISA_A);
+    INSN(scc,       50c0, f0f8, CF_ISA_A);
+    INSN(addsubq,   5080, f1c0, CF_ISA_A);
+    INSN(tpf,       51f8, fff8, CF_ISA_A);
 
-    iflags = def->insns;
-#define INSN(name, opcode, mask, isa) \
-    if (iflags & M68K_INSN_##isa) \
-        register_opcode(disas_##name, 0x##opcode, 0x##mask)
-    INSN(undef,     0000, 0000, CF_A);
-    INSN(arith_im,  0080, fff8, CF_A);
-    INSN(bitrev,    00c0, fff8, CF_C);
-    INSN(bitop_reg, 0100, f1c0, CF_A);
-    INSN(bitop_reg, 0140, f1c0, CF_A);
-    INSN(bitop_reg, 0180, f1c0, CF_A);
-    INSN(bitop_reg, 01c0, f1c0, CF_A);
-    INSN(arith_im,  0280, fff8, CF_A);
-    INSN(byterev,   02c0, fff8, CF_A);
-    INSN(arith_im,  0480, fff8, CF_A);
-    INSN(ff1,       04c0, fff8, CF_C);
-    INSN(arith_im,  0680, fff8, CF_A);
-    INSN(bitop_im,  0800, ffc0, CF_A);
-    INSN(bitop_im,  0840, ffc0, CF_A);
-    INSN(bitop_im,  0880, ffc0, CF_A);
-    INSN(bitop_im,  08c0, ffc0, CF_A);
-    INSN(arith_im,  0a80, fff8, CF_A);
-    INSN(arith_im,  0c00, ff38, CF_A);
-    INSN(move,      1000, f000, CF_A);
-    INSN(move,      2000, f000, CF_A);
-    INSN(move,      3000, f000, CF_A);
-    INSN(strldsr,   40e7, ffff, CF_A);
-    INSN(negx,      4080, fff8, CF_A);
-    INSN(move_from_sr, 40c0, fff8, CF_A);
-    INSN(lea,       41c0, f1c0, CF_A);
-    INSN(clr,       4200, ff00, CF_A);
-    INSN(undef,     42c0, ffc0, CF_A);
-    INSN(move_from_ccr, 42c0, fff8, CF_A);
-    INSN(neg,       4480, fff8, CF_A);
-    INSN(move_to_ccr, 44c0, ffc0, CF_A);
-    INSN(not,       4680, fff8, CF_A);
-    INSN(move_to_sr, 46c0, ffc0, CF_A);
-    INSN(pea,       4840, ffc0, CF_A);
-    INSN(swap,      4840, fff8, CF_A);
-    INSN(movem,     48c0, fbc0, CF_A);
-    INSN(ext,       4880, fff8, CF_A);
-    INSN(ext,       48c0, fff8, CF_A);
-    INSN(ext,       49c0, fff8, CF_A);
-    INSN(tst,       4a00, ff00, CF_A);
-    INSN(tas,       4ac0, ffc0, CF_B);
-    INSN(halt,      4ac8, ffff, CF_A);
-    INSN(pulse,     4acc, ffff, CF_A);
-    INSN(illegal,   4afc, ffff, CF_A);
-    INSN(mull,      4c00, ffc0, CF_A);
-    INSN(divl,      4c40, ffc0, CF_A);
-    INSN(sats,      4c80, fff8, CF_B);
-    INSN(trap,      4e40, fff0, CF_A);
-    INSN(link,      4e50, fff8, CF_A);
-    INSN(unlk,      4e58, fff8, CF_A);
-    INSN(move_to_usp, 4e60, fff8, CF_B);
-    INSN(move_from_usp, 4e68, fff8, CF_B);
-    INSN(nop,       4e71, ffff, CF_A);
-    INSN(stop,      4e72, ffff, CF_A);
-    INSN(rte,       4e73, ffff, CF_A);
-    INSN(rts,       4e75, ffff, CF_A);
-    INSN(movec,     4e7b, ffff, CF_A);
-    INSN(jump,      4e80, ffc0, CF_A);
-    INSN(jump,      4ec0, ffc0, CF_A);
-    INSN(addsubq,   5180, f1c0, CF_A);
-    INSN(scc,       50c0, f0f8, CF_A);
-    INSN(addsubq,   5080, f1c0, CF_A);
-    INSN(tpf,       51f8, fff8, CF_A);
-    INSN(branch,    6000, f000, CF_A);
-    INSN(moveq,     7000, f100, CF_A);
-    INSN(mvzs,      7100, f100, CF_B);
-    INSN(or,        8000, f000, CF_A);
-    INSN(divw,      80c0, f0c0, CF_A);
-    INSN(addsub,    9000, f000, CF_A);
-    INSN(subx,      9180, f1f8, CF_A);
-    INSN(suba,      91c0, f1c0, CF_A);
-    INSN(undef_mac, a000, f000, CF_A);
-    INSN(mov3q,     a140, f1c0, CF_B);
-    INSN(cmp,       b000, f1c0, CF_B); /* cmp.b */
-    INSN(cmp,       b040, f1c0, CF_B); /* cmp.w */
-    INSN(cmpa,      b0c0, f1c0, CF_B); /* cmpa.w */
-    INSN(cmp,       b080, f1c0, CF_A);
-    INSN(cmpa,      b1c0, f1c0, CF_A);
-    INSN(eor,       b180, f1c0, CF_A);
-    INSN(and,       c000, f000, CF_A);
-    INSN(mulw,      c0c0, f0c0, CF_A);
-    INSN(addsub,    d000, f000, CF_A);
-    INSN(addx,      d180, f1f8, CF_A);
-    INSN(adda,      d1c0, f1c0, CF_A);
-    INSN(shift_im,  e080, f0f0, CF_A);
-    INSN(shift_reg, e0a0, f0f0, CF_A);
-    INSN(undef_fpu, f000, f000, CF_A);
+    /* Branch instructions.  */
+    INSN(branch,    6000, f000, CF_ISA_A);
+    /* Disable long branch instructions, then add back the ones we want.  */
+    INSN(undef,     60ff, f0ff, CF_ISA_A); /* All long branches.  */
+    INSN(branch,    60ff, f0ff, CF_ISA_B);
+    INSN(undef,     60ff, ffff, CF_ISA_B); /* bra.l */
+    INSN(branch,    60ff, ffff, BRAL);
+
+    INSN(moveq,     7000, f100, CF_ISA_A);
+    INSN(mvzs,      7100, f100, CF_ISA_B);
+    INSN(or,        8000, f000, CF_ISA_A);
+    INSN(divw,      80c0, f0c0, CF_ISA_A);
+    INSN(addsub,    9000, f000, CF_ISA_A);
+    INSN(subx,      9180, f1f8, CF_ISA_A);
+    INSN(suba,      91c0, f1c0, CF_ISA_A);
+
+    INSN(undef_mac, a000, f000, CF_ISA_A);
+    INSN(mac,       a000, f100, CF_EMAC);
+    INSN(from_mac,  a180, f9b0, CF_EMAC);
+    INSN(move_mac,  a110, f9fc, CF_EMAC);
+    INSN(from_macsr,a980, f9f0, CF_EMAC);
+    INSN(from_mask, ad80, fff0, CF_EMAC);
+    INSN(from_mext, ab80, fbf0, CF_EMAC);
+    INSN(macsr_to_ccr, a9c0, ffff, CF_EMAC);
+    INSN(to_mac,    a100, f9c0, CF_EMAC);
+    INSN(to_macsr,  a900, ffc0, CF_EMAC);
+    INSN(to_mext,   ab00, fbc0, CF_EMAC);
+    INSN(to_mask,   ad00, ffc0, CF_EMAC);
+
+    INSN(mov3q,     a140, f1c0, CF_ISA_B);
+    INSN(cmp,       b000, f1c0, CF_ISA_B); /* cmp.b */
+    INSN(cmp,       b040, f1c0, CF_ISA_B); /* cmp.w */
+    INSN(cmpa,      b0c0, f1c0, CF_ISA_B); /* cmpa.w */
+    INSN(cmp,       b080, f1c0, CF_ISA_A);
+    INSN(cmpa,      b1c0, f1c0, CF_ISA_A);
+    INSN(eor,       b180, f1c0, CF_ISA_A);
+    INSN(and,       c000, f000, CF_ISA_A);
+    INSN(mulw,      c0c0, f0c0, CF_ISA_A);
+    INSN(addsub,    d000, f000, CF_ISA_A);
+    INSN(addx,      d180, f1f8, CF_ISA_A);
+    INSN(adda,      d1c0, f1c0, CF_ISA_A);
+    INSN(shift_im,  e080, f0f0, CF_ISA_A);
+    INSN(shift_reg, e0a0, f0f0, CF_ISA_A);
+    INSN(undef_fpu, f000, f000, CF_ISA_A);
     INSN(fpu,       f200, ffc0, CF_FPU);
     INSN(fbcc,      f280, ffc0, CF_FPU);
-    INSN(intouch,   f340, ffc0, CF_A);
-    INSN(cpushl,    f428, ff38, CF_A);
-    INSN(wddata,    fb00, ff00, CF_A);
-    INSN(wdebug,    fbc0, ffc0, CF_A);
+    INSN(frestore,  f340, ffc0, CF_FPU);
+    INSN(fsave,     f340, ffc0, CF_FPU);
+    INSN(intouch,   f340, ffc0, CF_ISA_A);
+    INSN(cpushl,    f428, ff38, CF_ISA_A);
+    INSN(wddata,    fb00, ff00, CF_ISA_A);
+    INSN(wdebug,    fbc0, ffc0, CF_ISA_A);
 #undef INSN
 }
 
@@ -2287,7 +2882,7 @@
 {
     uint16_t insn;
 
-    insn = lduw(s->pc);
+    insn = lduw_code(s->pc);
     s->pc += 2;
 
     opcode_table[insn](s, insn);
@@ -2470,7 +3065,7 @@
     int arg0 = qop->args[0];
     int arg1 = qop->args[1];
     int l1, l2;
-    
+
     gen_op_add32 (arg0, arg0, arg1);
     l1 = gen_new_label();
     l2 = gen_new_label();
@@ -2551,8 +3146,9 @@
 #endif
 
 /* generate intermediate code for basic block 'tb'.  */
-int gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
-                                   int search_pc)
+static inline int
+gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
+                               int search_pc)
 {
     DisasContext dc1, *dc = &dc1;
     uint16_t *gen_opc_end;
@@ -2563,18 +3159,21 @@
 
     /* generate intermediate code */
     pc_start = tb->pc;
-       
+
     dc->tb = tb;
 
     gen_opc_ptr = gen_opc_buf;
     gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
     gen_opparam_ptr = gen_opparam_buf;
 
+    dc->env = env;
     dc->is_jmp = DISAS_NEXT;
     dc->pc = pc_start;
     dc->cc_op = CC_OP_DYNAMIC;
     dc->singlestep_enabled = env->singlestep_enabled;
     dc->fpcr = env->fpcr;
+    dc->user = (env->sr & SR_S) == 0;
+    dc->is_mem = 0;
     nb_gen_labels = 0;
     lj = -1;
     do {
@@ -2603,7 +3202,14 @@
             gen_opc_instr_start[lj] = 1;
         }
         last_cc_op = dc->cc_op;
+        dc->insn_pc = dc->pc;
 	disas_m68k_insn(env, dc);
+
+        /* Terminate the TB on memory ops if watchpoints are present.  */
+        /* FIXME: This should be replacd by the deterministic execution
+         * IRQ raising bits.  */
+        if (dc->is_mem && env->nb_watchpoints)
+            break;
     } while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
              !env->singlestep_enabled &&
              (pc_offset) < (TARGET_PAGE_SIZE - 32));
@@ -2654,7 +3260,6 @@
         lj++;
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
-        tb->size = 0;
     } else {
         tb->size = dc->pc - pc_start;
     }
@@ -2674,6 +3279,20 @@
     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
+    m68k_switch_sp(env);
+    /* ??? 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;
@@ -2683,10 +3302,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;
 }
 
@@ -2695,26 +3311,7 @@
     free(env);
 }
 
-m68k_def_t *m68k_find_by_name(const char *name)
-{
-    m68k_def_t *def;
-
-    def = m68k_cpu_defs;
-    while (def->name)
-      {
-        if (strcmp(def->name, name) == 0)
-            return def;
-        def++;
-      }
-    return NULL;
-}
-
-void cpu_m68k_register(CPUM68KState *env, m68k_def_t *def)
-{
-    register_m68k_insns(def);
-}
-
-void cpu_dump_state(CPUState *env, FILE *f, 
+void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
 {
@@ -2736,24 +3333,3 @@
     cpu_fprintf (f, "FPRESULT = %12g\n", env->fp_result);
 }
 
-/* ??? */
-target_ulong 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
diff --git a/target-mips/TODO b/target-mips/TODO
index bd8d26d..2d207cf 100644
--- a/target-mips/TODO
+++ b/target-mips/TODO
@@ -4,23 +4,21 @@
 General
 -------
 - [ls][dw][lr] report broken (aligned) BadVAddr
-- Missing per-CPU instruction decoding, currently all implemented
-  instructions are regarded as valid
-- pcnet32 does not work for little endian emulation on big endian host
-  (probably not mips specific, but observable for mips-malta)
 
 MIPS64
 ------
-- No 64bit TLB support
-- no 64bit wide registers for FPU
-- 64bit mul/div handling broken
+- Userland emulation (both n32 and n64) not functional.
 
 "Generic" 4Kc system emulation
 ------------------------------
 - Doesn't correspond to any real hardware.
 
+PICA 61 system emulation
+------------------------
+- No framebuffer support yet.
+
 MALTA system emulation
 ----------------------
 - We fake firmware support instead of doing the real thing
 - Real firmware falls over when trying to init RAM, presumably due
-  to lacking I2C emulation.
+  to lacking system controller emulation.
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index fb5a3fe..569f932 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -12,37 +12,15 @@
 
 // uint_fast8_t and uint_fast16_t not in <sys/int_types.h>
 // XXX: move that elsewhere
-#if defined(HOST_SOLARIS) && SOLARISREV < 10
+#if defined(HOST_SOLARIS) && HOST_SOLARIS < 10
 typedef unsigned char           uint_fast8_t;
 typedef unsigned int            uint_fast16_t;
 #endif
 
-/* target_ulong size spec */
-#ifdef MIPS_HAS_MIPS64
-#define TLSZ "%016llx"
-#else
-#define TLSZ "%08x"
-#endif
+struct CPUMIPSState;
 
-typedef union fpr_t fpr_t;
-union fpr_t {
-    float64  fd;   /* ieee double precision */
-    float32  fs[2];/* ieee single precision */
-    uint64_t d;    /* binary single fixed-point */
-    uint32_t w[2]; /* binary single fixed-point */
-};
-/* define FP_ENDIAN_IDX to access the same location
- * in the fpr_t union regardless of the host endianess
- */
-#if defined(WORDS_BIGENDIAN)
-#  define FP_ENDIAN_IDX 1
-#else
-#  define FP_ENDIAN_IDX 0
-#endif
-
-#if defined(MIPS_USES_R4K_TLB)
-typedef struct tlb_t tlb_t;
-struct tlb_t {
+typedef struct r4k_tlb_t r4k_tlb_t;
+struct r4k_tlb_t {
     target_ulong VPN;
     uint32_t PageMask;
     uint_fast8_t ASID;
@@ -55,69 +33,233 @@
     uint_fast16_t D1:1;
     target_ulong PFN[2];
 };
+
+typedef struct CPUMIPSTLBContext CPUMIPSTLBContext;
+struct CPUMIPSTLBContext {
+    uint32_t nb_tlb;
+    uint32_t tlb_in_use;
+    int (*map_address) (struct CPUMIPSState *env, target_ulong *physical, int *prot, target_ulong address, int rw, int access_type);
+    void (*do_tlbwi) (void);
+    void (*do_tlbwr) (void);
+    void (*do_tlbp) (void);
+    void (*do_tlbr) (void);
+    union {
+        struct {
+            r4k_tlb_t tlb[MIPS_TLB_MAX];
+        } r4k;
+    } mmu;
+};
+
+typedef union fpr_t fpr_t;
+union fpr_t {
+    float64  fd;   /* ieee double precision */
+    float32  fs[2];/* ieee single precision */
+    uint64_t d;    /* binary double fixed-point */
+    uint32_t w[2]; /* binary single fixed-point */
+};
+/* define FP_ENDIAN_IDX to access the same location
+ * in the fpr_t union regardless of the host endianess
+ */
+#if defined(WORDS_BIGENDIAN)
+#  define FP_ENDIAN_IDX 1
+#else
+#  define FP_ENDIAN_IDX 0
 #endif
 
-typedef struct CPUMIPSState CPUMIPSState;
-struct CPUMIPSState {
-    /* General integer registers */
-    target_ulong gpr[32];
-    /* Special registers */
-    target_ulong PC;
-#if TARGET_LONG_BITS > HOST_LONG_BITS
-    target_ulong t0;
-    target_ulong t1;
-    target_ulong t2;
-#endif
-    target_ulong HI, LO;
-    uint32_t DCR; /* ? */
-#if defined(MIPS_USES_FPU)
+typedef struct CPUMIPSFPUContext CPUMIPSFPUContext;
+struct CPUMIPSFPUContext {
     /* Floating point registers */
-    fpr_t fpr[16];
-#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2])
-#define FPR_FD(cpu, n) (FPR(cpu, n)->fd)
-#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX])
-#define FPR_D(cpu, n)  (FPR(cpu, n)->d)
-#define FPR_W(cpu, n)  (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX])
-
+    fpr_t fpr[32];
 #ifndef USE_HOST_FLOAT_REGS
     fpr_t ft0;
     fpr_t ft1;
     fpr_t ft2;
 #endif
     float_status fp_status;
-    /* fpu implementation/revision register */
+    /* fpu implementation/revision register (fir) */
     uint32_t fcr0;
+#define FCR0_F64 22
+#define FCR0_L 21
+#define FCR0_W 20
+#define FCR0_3D 19
+#define FCR0_PS 18
+#define FCR0_D 17
+#define FCR0_S 16
+#define FCR0_PRID 8
+#define FCR0_REV 0
     /* fcsr */
     uint32_t fcr31;
-#define SET_FP_COND(reg)     do { (reg) |= (1<<23); } while(0)
-#define CLEAR_FP_COND(reg)   do { (reg) &= ~(1<<23); } while(0)
-#define IS_FP_COND_SET(reg)  (((reg) & (1<<23)) != 0)
-#define GET_FP_CAUSE(reg)    (((reg) >> 12) & 0x3f)
-#define GET_FP_ENABLE(reg)   (((reg) >>  7) & 0x1f)
-#define GET_FP_FLAGS(reg)    (((reg) >>  2) & 0x1f)
-#define SET_FP_CAUSE(reg,v)  do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 12); } while(0)
-#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f <<  7)) | ((v) << 7); } while(0)
-#define SET_FP_FLAGS(reg,v)  do { (reg) = ((reg) & ~(0x1f <<  2)) | ((v) << 2); } while(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)
+#define SET_FP_CAUSE(reg,v)      do { (reg) = ((reg) & ~(0x3f << 12)) | ((v & 0x3f) << 12); } while(0)
+#define SET_FP_ENABLE(reg,v)     do { (reg) = ((reg) & ~(0x1f <<  7)) | ((v & 0x1f) << 7); } while(0)
+#define SET_FP_FLAGS(reg,v)      do { (reg) = ((reg) & ~(0x1f <<  2)) | ((v & 0x1f) << 2); } while(0)
+#define UPDATE_FP_FLAGS(reg,v)   do { (reg) |= ((v & 0x1f) << 2); } while(0)
 #define FP_INEXACT        1
 #define FP_UNDERFLOW      2
 #define FP_OVERFLOW       4
 #define FP_DIV0           8
 #define FP_INVALID        16
 #define FP_UNIMPLEMENTED  32
-		
+};
+
+typedef struct CPUMIPSMVPContext CPUMIPSMVPContext;
+struct CPUMIPSMVPContext {
+    int32_t CP0_MVPControl;
+#define CP0MVPCo_CPA	3
+#define CP0MVPCo_STLB	2
+#define CP0MVPCo_VPC	1
+#define CP0MVPCo_EVP	0
+    int32_t CP0_MVPConf0;
+#define CP0MVPC0_M	31
+#define CP0MVPC0_TLBS	29
+#define CP0MVPC0_GS	28
+#define CP0MVPC0_PCP	27
+#define CP0MVPC0_PTLBE	16
+#define CP0MVPC0_TCA	15
+#define CP0MVPC0_PVPE	10
+#define CP0MVPC0_PTC	0
+    int32_t CP0_MVPConf1;
+#define CP0MVPC1_CIM	31
+#define CP0MVPC1_CIF	30
+#define CP0MVPC1_PCX	20
+#define CP0MVPC1_PCP2	10
+#define CP0MVPC1_PCP1	0
+};
+
+typedef struct mips_def_t mips_def_t;
+
+#define MIPS_SHADOW_SET_MAX 16
+#define MIPS_TC_MAX 5
+#define MIPS_DSP_ACC 4
+
+typedef struct CPUMIPSState CPUMIPSState;
+struct CPUMIPSState {
+    /* General integer registers */
+    target_ulong gpr[32][MIPS_SHADOW_SET_MAX];
+    /* Special registers */
+    target_ulong PC[MIPS_TC_MAX];
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+    target_ulong t0;
+    target_ulong t1;
+    target_ulong t2;
 #endif
-#if defined(MIPS_USES_R4K_TLB)
-    tlb_t tlb[MIPS_TLB_MAX];
-    uint32_t tlb_in_use;
-#endif
+    target_ulong HI[MIPS_DSP_ACC][MIPS_TC_MAX];
+    target_ulong LO[MIPS_DSP_ACC][MIPS_TC_MAX];
+    target_ulong ACX[MIPS_DSP_ACC][MIPS_TC_MAX];
+    target_ulong DSPControl[MIPS_TC_MAX];
+
+    CPUMIPSMVPContext *mvp;
+    CPUMIPSTLBContext *tlb;
+    CPUMIPSFPUContext *fpu;
+    uint32_t current_tc;
+
+    uint32_t SEGBITS;
+    target_ulong SEGMask;
+
     int32_t CP0_Index;
+    /* CP0_MVP* are per MVP registers. */
     int32_t CP0_Random;
+    int32_t CP0_VPEControl;
+#define CP0VPECo_YSI	21
+#define CP0VPECo_GSI	20
+#define CP0VPECo_EXCPT	16
+#define CP0VPECo_TE	15
+#define CP0VPECo_TargTC	0
+    int32_t CP0_VPEConf0;
+#define CP0VPEC0_M	31
+#define CP0VPEC0_XTC	21
+#define CP0VPEC0_TCS	19
+#define CP0VPEC0_SCS	18
+#define CP0VPEC0_DSC	17
+#define CP0VPEC0_ICS	16
+#define CP0VPEC0_MVP	1
+#define CP0VPEC0_VPA	0
+    int32_t CP0_VPEConf1;
+#define CP0VPEC1_NCX	20
+#define CP0VPEC1_NCP2	10
+#define CP0VPEC1_NCP1	0
+    target_ulong CP0_YQMask;
+    target_ulong CP0_VPESchedule;
+    target_ulong CP0_VPEScheFBack;
+    int32_t CP0_VPEOpt;
+#define CP0VPEOpt_IWX7	15
+#define CP0VPEOpt_IWX6	14
+#define CP0VPEOpt_IWX5	13
+#define CP0VPEOpt_IWX4	12
+#define CP0VPEOpt_IWX3	11
+#define CP0VPEOpt_IWX2	10
+#define CP0VPEOpt_IWX1	9
+#define CP0VPEOpt_IWX0	8
+#define CP0VPEOpt_DWX7	7
+#define CP0VPEOpt_DWX6	6
+#define CP0VPEOpt_DWX5	5
+#define CP0VPEOpt_DWX4	4
+#define CP0VPEOpt_DWX3	3
+#define CP0VPEOpt_DWX2	2
+#define CP0VPEOpt_DWX1	1
+#define CP0VPEOpt_DWX0	0
     target_ulong CP0_EntryLo0;
+    int32_t CP0_TCStatus[MIPS_TC_MAX];
+#define CP0TCSt_TCU3	31
+#define CP0TCSt_TCU2	30
+#define CP0TCSt_TCU1	29
+#define CP0TCSt_TCU0	28
+#define CP0TCSt_TMX	27
+#define CP0TCSt_RNST	23
+#define CP0TCSt_TDS	21
+#define CP0TCSt_DT	20
+#define CP0TCSt_DA	15
+#define CP0TCSt_A	13
+#define CP0TCSt_TKSU	11
+#define CP0TCSt_IXMT	10
+#define CP0TCSt_TASID	0
+    int32_t CP0_TCBind[MIPS_TC_MAX];
+#define CP0TCBd_CurTC	21
+#define CP0TCBd_TBE	17
+#define CP0TCBd_CurVPE	0
+    target_ulong CP0_TCHalt[MIPS_TC_MAX];
+    target_ulong CP0_TCContext[MIPS_TC_MAX];
+    target_ulong CP0_TCSchedule[MIPS_TC_MAX];
+    target_ulong CP0_TCScheFBack[MIPS_TC_MAX];
     target_ulong CP0_EntryLo1;
     target_ulong CP0_Context;
     int32_t CP0_PageMask;
     int32_t CP0_PageGrain;
     int32_t CP0_Wired;
+    int32_t CP0_SRSConf0_rw_bitmask;
+    int32_t CP0_SRSConf0;
+#define CP0SRSC0_M	31
+#define CP0SRSC0_SRS3	20
+#define CP0SRSC0_SRS2	10
+#define CP0SRSC0_SRS1	0
+    int32_t CP0_SRSConf1_rw_bitmask;
+    int32_t CP0_SRSConf1;
+#define CP0SRSC1_M	31
+#define CP0SRSC1_SRS6	20
+#define CP0SRSC1_SRS5	10
+#define CP0SRSC1_SRS4	0
+    int32_t CP0_SRSConf2_rw_bitmask;
+    int32_t CP0_SRSConf2;
+#define CP0SRSC2_M	31
+#define CP0SRSC2_SRS9	20
+#define CP0SRSC2_SRS8	10
+#define CP0SRSC2_SRS7	0
+    int32_t CP0_SRSConf3_rw_bitmask;
+    int32_t CP0_SRSConf3;
+#define CP0SRSC3_M	31
+#define CP0SRSC3_SRS12	20
+#define CP0SRSC3_SRS11	10
+#define CP0SRSC3_SRS10	0
+    int32_t CP0_SRSConf4_rw_bitmask;
+    int32_t CP0_SRSConf4;
+#define CP0SRSC4_SRS15	20
+#define CP0SRSC4_SRS14	10
+#define CP0SRSC4_SRS13	0
     int32_t CP0_HWREna;
     target_ulong CP0_BadVAddr;
     int32_t CP0_Count;
@@ -147,8 +289,24 @@
 #define CP0St_EXL   1
 #define CP0St_IE    0
     int32_t CP0_IntCtl;
+#define CP0IntCtl_IPTI 29
+#define CP0IntCtl_IPPC1 26
+#define CP0IntCtl_VS 5
     int32_t CP0_SRSCtl;
+#define CP0SRSCtl_HSS 26
+#define CP0SRSCtl_EICSS 18
+#define CP0SRSCtl_ESS 12
+#define CP0SRSCtl_PSS 6
+#define CP0SRSCtl_CSS 0
     int32_t CP0_SRSMap;
+#define CP0SRSMap_SSV7 28
+#define CP0SRSMap_SSV6 24
+#define CP0SRSMap_SSV5 20
+#define CP0SRSMap_SSV4 16
+#define CP0SRSMap_SSV3 12
+#define CP0SRSMap_SSV2 8
+#define CP0SRSMap_SSV1 4
+#define CP0SRSMap_SSV0 0
     int32_t CP0_Cause;
 #define CP0Ca_BD   31
 #define CP0Ca_TI   30
@@ -212,13 +370,16 @@
 #define CP0C3_MT   2
 #define CP0C3_SM   1
 #define CP0C3_TL   0
+    int32_t CP0_Config6;
+    int32_t CP0_Config7;
+    /* XXX: Maybe make LLAddr per-TC? */
     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;
-#define CPDB_DBD   31
+#define CP0DB_DBD  31
 #define CP0DB_DM   30
 #define CP0DB_LSNM 28
 #define CP0DB_Doze 27
@@ -236,6 +397,7 @@
 #define CP0DB_DDBL 2
 #define CP0DB_DBp  1
 #define CP0DB_DSS  0
+    int32_t CP0_Debug_tcstatus[MIPS_TC_MAX];
     target_ulong CP0_DEPC;
     int32_t CP0_Performance0;
     int32_t CP0_TagLo;
@@ -252,23 +414,25 @@
     int user_mode_only; /* user mode only simulation */
     uint32_t hflags;    /* CPU State */
     /* TMASK defines different execution modes */
-#define MIPS_HFLAG_TMASK  0x007F
-#define MIPS_HFLAG_MODE   0x001F /* execution modes                    */
+#define MIPS_HFLAG_TMASK  0x00FF
+#define MIPS_HFLAG_MODE   0x0007 /* execution modes                    */
 #define MIPS_HFLAG_UM     0x0001 /* user mode                          */
-#define MIPS_HFLAG_ERL    0x0002 /* Error mode                         */
-#define MIPS_HFLAG_EXL    0x0004 /* Exception mode                     */
-#define MIPS_HFLAG_DM     0x0008 /* Debug mode                         */
-#define MIPS_HFLAG_SM     0x0010 /* Supervisor mode                    */
-#define MIPS_HFLAG_RE     0x0040 /* Reversed endianness                */
+#define MIPS_HFLAG_DM     0x0002 /* Debug mode                         */
+#define MIPS_HFLAG_SM     0x0004 /* Supervisor mode                    */
+#define MIPS_HFLAG_64     0x0008 /* 64-bit instructions enabled        */
+#define MIPS_HFLAG_CP0    0x0010 /* CP0 enabled                        */
+#define MIPS_HFLAG_FPU    0x0020 /* FPU enabled                        */
+#define MIPS_HFLAG_F64    0x0040 /* 64-bit FPU enabled                 */
+#define MIPS_HFLAG_RE     0x0080 /* Reversed endianness                */
     /* If translation is interrupted between the branch instruction and
      * the delay slot, record what type of branch it is so that we can
      * resume translation properly.  It might be possible to reduce
      * this from three bits to two.  */
-#define MIPS_HFLAG_BMASK  0x0380
-#define MIPS_HFLAG_B      0x0080 /* Unconditional branch               */
-#define MIPS_HFLAG_BC     0x0100 /* Conditional branch                 */
-#define MIPS_HFLAG_BL     0x0180 /* Likely branch                      */
-#define MIPS_HFLAG_BR     0x0200 /* branch to register (can't link TB) */
+#define MIPS_HFLAG_BMASK  0x0700
+#define MIPS_HFLAG_B      0x0100 /* Unconditional branch               */
+#define MIPS_HFLAG_BC     0x0200 /* Conditional branch                 */
+#define MIPS_HFLAG_BL     0x0300 /* Likely branch                      */
+#define MIPS_HFLAG_BR     0x0400 /* branch to register (can't link TB) */
     target_ulong btarget;        /* Jump / branch target               */
     int bcond;                   /* Branch condition (if needed)       */
 
@@ -276,6 +440,13 @@
 
     int SYNCI_Step; /* Address step size for SYNCI */
     int CCRes; /* Cycle count resolution/divisor */
+    uint32_t CP0_Status_rw_bitmask; /* Read/write bits in CP0_Status */
+    uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */
+    int insn_flags; /* Supported instruction set */
+
+#ifdef CONFIG_USER_ONLY
+    target_ulong tls_value;
+#endif
 
     CPU_COMMON
 
@@ -284,9 +455,34 @@
     const char *kernel_cmdline;
     const char *initrd_filename;
 
+    mips_def_t *cpu_model;
+#ifndef CONFIG_USER_ONLY
+    void *irq[8];
+#endif
+
     struct QEMUTimer *timer; /* Internal timer */
 };
 
+int no_mmu_map_address (CPUMIPSState *env, target_ulong *physical, int *prot,
+                        target_ulong address, int rw, int access_type);
+int fixed_mmu_map_address (CPUMIPSState *env, target_ulong *physical, int *prot,
+                           target_ulong address, int rw, int access_type);
+int r4k_map_address (CPUMIPSState *env, target_ulong *physical, int *prot,
+                     target_ulong address, int rw, int access_type);
+void r4k_do_tlbwi (void);
+void r4k_do_tlbwr (void);
+void r4k_do_tlbp (void);
+void r4k_do_tlbr (void);
+int mips_find_by_name (const unsigned char *name, mips_def_t **def);
+void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+int cpu_mips_register (CPUMIPSState *env, mips_def_t *def);
+
+#define CPUState CPUMIPSState
+#define cpu_init cpu_mips_init
+#define cpu_exec cpu_mips_exec
+#define cpu_gen_code cpu_mips_gen_code
+#define cpu_signal_handler cpu_mips_signal_handler
+
 #include "cpu-all.h"
 
 /* Memory access type :
@@ -328,15 +524,17 @@
     EXCP_RI,
     EXCP_OVERFLOW,
     EXCP_TRAP,
+    EXCP_FPE,
     EXCP_DDBS,
     EXCP_DWATCH,
-    EXCP_LAE,
-    EXCP_SAE, /* 24 */
+    EXCP_LAE, /* 24 */
+    EXCP_SAE,
     EXCP_LTLBL,
     EXCP_TLBL,
     EXCP_TLBS,
     EXCP_DBE,
     EXCP_DDBL,
+    EXCP_THREAD,
     EXCP_MTCP0         = 0x104, /* mtmsr instruction:               */
                                 /* may change privilege level       */
     EXCP_BRANCH        = 0x108, /* branch instruction               */
@@ -348,5 +546,6 @@
 int cpu_mips_exec(CPUMIPSState *s);
 CPUMIPSState *cpu_mips_init(void);
 uint32_t cpu_mips_get_clock (void);
+int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
 
 #endif /* !defined (__MIPS_CPU_H__) */
diff --git a/target-mips/exec.h b/target-mips/exec.h
index 1e9fa8e..8e90978 100644
--- a/target-mips/exec.h
+++ b/target-mips/exec.h
@@ -6,52 +6,41 @@
 #include "config.h"
 #include "mips-defs.h"
 #include "dyngen-exec.h"
+#include "cpu-defs.h"
 
-#if defined(__sparc__)
-struct CPUMIPSState *env;
-#else
 register struct CPUMIPSState *env asm(AREG0);
-#endif
 
-#if defined (USE_64BITS_REGS)
-typedef int64_t host_int_t;
-typedef uint64_t host_uint_t;
-#else
-typedef int32_t host_int_t;
-typedef uint32_t host_uint_t;
-#endif
-
-#if defined(__sparc__)
-host_uint_t T0;
-host_uint_t T1;
-host_uint_t T2;
-#else
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 #define T0 (env->t0)
 #define T1 (env->t1)
 #define T2 (env->t2)
 #else
-register host_uint_t T0 asm(AREG1);
-register host_uint_t T1 asm(AREG2);
-register host_uint_t T2 asm(AREG3);
-#endif
+register target_ulong T0 asm(AREG1);
+register target_ulong T1 asm(AREG2);
+register target_ulong T2 asm(AREG3);
 #endif
 
 #if defined (USE_HOST_FLOAT_REGS)
 #error "implement me."
 #else
-#define FDT0 (env->ft0.fd)
-#define FDT1 (env->ft1.fd)
-#define FDT2 (env->ft2.fd)
-#define FST0 (env->ft0.fs[FP_ENDIAN_IDX])
-#define FST1 (env->ft1.fs[FP_ENDIAN_IDX])
-#define FST2 (env->ft2.fs[FP_ENDIAN_IDX])
-#define DT0 (env->ft0.d)
-#define DT1 (env->ft1.d)
-#define DT2 (env->ft2.d)
-#define WT0 (env->ft0.w[FP_ENDIAN_IDX])
-#define WT1 (env->ft1.w[FP_ENDIAN_IDX])
-#define WT2 (env->ft2.w[FP_ENDIAN_IDX])
+#define FDT0 (env->fpu->ft0.fd)
+#define FDT1 (env->fpu->ft1.fd)
+#define FDT2 (env->fpu->ft2.fd)
+#define FST0 (env->fpu->ft0.fs[FP_ENDIAN_IDX])
+#define FST1 (env->fpu->ft1.fs[FP_ENDIAN_IDX])
+#define FST2 (env->fpu->ft2.fs[FP_ENDIAN_IDX])
+#define FSTH0 (env->fpu->ft0.fs[!FP_ENDIAN_IDX])
+#define FSTH1 (env->fpu->ft1.fs[!FP_ENDIAN_IDX])
+#define FSTH2 (env->fpu->ft2.fs[!FP_ENDIAN_IDX])
+#define DT0 (env->fpu->ft0.d)
+#define DT1 (env->fpu->ft1.d)
+#define DT2 (env->fpu->ft2.d)
+#define WT0 (env->fpu->ft0.w[FP_ENDIAN_IDX])
+#define WT1 (env->fpu->ft1.w[FP_ENDIAN_IDX])
+#define WT2 (env->fpu->ft2.w[FP_ENDIAN_IDX])
+#define WTH0 (env->fpu->ft0.w[!FP_ENDIAN_IDX])
+#define WTH1 (env->fpu->ft1.w[!FP_ENDIAN_IDX])
+#define WTH2 (env->fpu->ft2.w[!FP_ENDIAN_IDX])
 #endif
 
 #if defined (DEBUG_OP)
@@ -67,15 +56,7 @@
 #include "softmmu_exec.h"
 #endif /* !defined(CONFIG_USER_ONLY) */
 
-static inline void env_to_regs(void)
-{
-}
-
-static inline void regs_to_env(void)
-{
-}
-
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 void do_dsll (void);
 void do_dsll32 (void);
@@ -92,6 +73,9 @@
 #endif
 #endif
 
+#if HOST_LONG_BITS < 64
+void do_div (void);
+#endif
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 void do_mult (void);
 void do_multu (void);
@@ -99,34 +83,28 @@
 void do_maddu (void);
 void do_msub (void);
 void do_msubu (void);
+#endif
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 void do_ddiv (void);
+#if TARGET_LONG_BITS > HOST_LONG_BITS
 void do_ddivu (void);
 #endif
-#ifdef MIPS_HAS_MIPS64
-void do_dmult (void);
-void do_dmultu (void);
 #endif
 void do_mfc0_random(void);
 void do_mfc0_count(void);
 void do_mtc0_entryhi(uint32_t in);
 void do_mtc0_status_debug(uint32_t old, uint32_t val);
 void do_mtc0_status_irqraise_debug(void);
-void do_tlbwi (void);
-void do_tlbwr (void);
-void do_tlbp (void);
-void do_tlbr (void);
-#ifdef MIPS_USES_FPU
 void dump_fpu(CPUState *env);
-void fpu_dump_state(CPUState *env, FILE *f, 
+void fpu_dump_state(CPUState *env, FILE *f,
                     int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags);
-#endif
 void dump_sc (void);
 void do_lwl_raw (uint32_t);
 void do_lwr_raw (uint32_t);
 uint32_t do_swl_raw (uint32_t);
 uint32_t do_swr_raw (uint32_t);
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 void do_ldl_raw (uint64_t);
 void do_ldr_raw (uint64_t);
 uint64_t do_sdl_raw (uint64_t);
@@ -141,7 +119,7 @@
 uint32_t do_swl_kernel (uint32_t);
 uint32_t do_swr_user (uint32_t);
 uint32_t do_swr_kernel (uint32_t);
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 void do_ldl_user (uint64_t);
 void do_ldl_kernel (uint64_t);
 void do_ldr_user (uint64_t);
@@ -159,14 +137,15 @@
 int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                                int is_user, int is_softmmu);
 void do_interrupt (CPUState *env);
-void invalidate_tlb (CPUState *env, int idx, int use_extra);
+void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
 
 void cpu_loop_exit(void);
 void do_raise_exception_err (uint32_t exception, int error_code);
 void do_raise_exception (uint32_t exception);
+void do_raise_exception_direct_err (uint32_t exception, int error_code);
 void do_raise_exception_direct (uint32_t exception);
 
-void cpu_dump_state(CPUState *env, FILE *f, 
+void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags);
 void cpu_mips_irqctrl_init (void);
@@ -174,8 +153,134 @@
 uint32_t cpu_mips_get_count (CPUState *env);
 void cpu_mips_store_count (CPUState *env, uint32_t value);
 void cpu_mips_store_compare (CPUState *env, uint32_t value);
-void cpu_mips_update_irq(CPUState *env);
+void cpu_mips_start_count(CPUState *env);
+void cpu_mips_stop_count(CPUState *env);
+void cpu_mips_update_irq (CPUState *env);
 void cpu_mips_clock_init (CPUState *env);
 void cpu_mips_tlb_flush (CPUState *env, int flush_global);
 
+void do_cfc1 (int reg);
+void do_ctc1 (int reg);
+
+#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
+
+static inline void env_to_regs(void)
+{
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+static inline int cpu_halted(CPUState *env)
+{
+    if (!env->halted)
+        return 0;
+    if (env->interrupt_request &
+        (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
+static inline void compute_hflags(CPUState *env)
+{
+    env->hflags &= ~(MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | MIPS_HFLAG_F64 |
+                     MIPS_HFLAG_FPU | MIPS_HFLAG_UM);
+    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+        !(env->CP0_Status & (1 << CP0St_ERL)) &&
+        !(env->hflags & MIPS_HFLAG_DM)) {
+        if (env->CP0_Status & (1 << CP0St_UM))
+            env->hflags |= MIPS_HFLAG_UM;
+        if (env->CP0_Status & (1 << CP0St_R0))
+            env->hflags |= MIPS_HFLAG_SM;
+    }
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    if (!(env->hflags & MIPS_HFLAG_UM) ||
+        (env->CP0_Status & (1 << CP0St_PX)) ||
+        (env->CP0_Status & (1 << CP0St_UX)))
+        env->hflags |= MIPS_HFLAG_64;
+#endif
+    if ((env->CP0_Status & (1 << CP0St_CU0)) ||
+        (!(env->hflags & MIPS_HFLAG_UM) &&
+         !(env->hflags & MIPS_HFLAG_SM)))
+        env->hflags |= MIPS_HFLAG_CP0;
+    if (env->CP0_Status & (1 << CP0St_CU1))
+        env->hflags |= MIPS_HFLAG_FPU;
+    if (env->CP0_Status & (1 << CP0St_FR))
+        env->hflags |= MIPS_HFLAG_F64;
+}
+
 #endif /* !defined(__QEMU_MIPS_EXEC_H__) */
diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c
index 4ebb46b..25b2ca7 100644
--- a/target-mips/fop_template.c
+++ b/target-mips/fop_template.c
@@ -1,7 +1,7 @@
 /*
- * MIPS emulation micro-operations templates for floating point reg 
+ * MIPS emulation micro-operations templates for floating point reg
  * load & store for qemu.
- * 
+ *
  * Copyright (c) 2006 Marius Groeger
  *
  * This library is free software; you can redistribute it and/or
@@ -19,75 +19,103 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#if defined(SFREG)
+#if defined(FREG)
 
-#define OP_WLOAD_FREG(treg, tregname, SFREG)      \
-    void glue(glue(op_load_fpr_,tregname), SFREG) (void) \
-    {                                                   \
-        treg = FPR_W(env, SFREG);     \
-        RETURN();                                       \
+#define OP_WLOAD_FREG(treg, tregname, FREG)              \
+    void glue(glue(op_load_fpr_,tregname), FREG) (void)  \
+    {                                                    \
+        treg = env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX];    \
+        RETURN();                                        \
     }
 
-#define OP_WSTORE_FREG(treg, tregname, SFREG)            \
-    void glue(glue(op_store_fpr_,tregname), SFREG) (void)\
-    {                                                   \
-        FPR_W(env, SFREG) = treg;     \
-        RETURN();                                       \
+#define OP_WSTORE_FREG(treg, tregname, FREG)             \
+    void glue(glue(op_store_fpr_,tregname), FREG) (void) \
+    {                                                    \
+        env->fpu->fpr[FREG].fs[FP_ENDIAN_IDX] = treg;    \
+        RETURN();                                        \
     }
 
-/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */
-OP_WLOAD_FREG(WT0, WT0_fpr, SFREG)
-/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */
-OP_WSTORE_FREG(WT0, WT0_fpr, SFREG)
+/* WT0 = FREG.w: op_load_fpr_WT0_fprFREG */
+OP_WLOAD_FREG(WT0, WT0_fpr, FREG)
+/* FREG.w = WT0: op_store_fpr_WT0_fprFREG */
+OP_WSTORE_FREG(WT0, WT0_fpr, FREG)
 
-OP_WLOAD_FREG(WT1, WT1_fpr, SFREG)
-OP_WSTORE_FREG(WT1, WT1_fpr, SFREG)
+OP_WLOAD_FREG(WT1, WT1_fpr, FREG)
+OP_WSTORE_FREG(WT1, WT1_fpr, FREG)
 
-OP_WLOAD_FREG(WT2, WT2_fpr, SFREG)
-OP_WSTORE_FREG(WT2, WT2_fpr, SFREG)
+OP_WLOAD_FREG(WT2, WT2_fpr, FREG)
+OP_WSTORE_FREG(WT2, WT2_fpr, FREG)
 
-#endif
-
-#if defined(DFREG)
-
-#define OP_DLOAD_FREG(treg, tregname, DFREG)      \
-    void glue(glue(op_load_fpr_,tregname), DFREG) (void) \
-    {                                                   \
-        treg = FPR_D(env, DFREG);                    \
-        RETURN();                                       \
+#define OP_DLOAD_FREG(treg, tregname, FREG)              \
+    void glue(glue(op_load_fpr_,tregname), FREG) (void)  \
+    {                                                    \
+        if (env->hflags & MIPS_HFLAG_F64)                \
+            treg = env->fpu->fpr[FREG].fd;               \
+        else                                             \
+            treg = (uint64_t)(env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \
+                   env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \
+        RETURN();                                        \
     }
 
-#define OP_DSTORE_FREG(treg, tregname, DFREG)            \
-    void glue(glue(op_store_fpr_,tregname), DFREG) (void)\
-    {                                                   \
-        FPR_D(env, DFREG) = treg;                    \
-        RETURN();                                       \
+#define OP_DSTORE_FREG(treg, tregname, FREG)             \
+    void glue(glue(op_store_fpr_,tregname), FREG) (void) \
+    {                                                    \
+        if (env->hflags & MIPS_HFLAG_F64)                \
+            env->fpu->fpr[FREG].fd = treg;               \
+        else {                                           \
+            env->fpu->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \
+            env->fpu->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg;      \
+        }                                                \
+        RETURN();                                        \
     }
 
-OP_DLOAD_FREG(DT0, DT0_fpr, DFREG)
-OP_DSTORE_FREG(DT0, DT0_fpr, DFREG)
+OP_DLOAD_FREG(DT0, DT0_fpr, FREG)
+OP_DSTORE_FREG(DT0, DT0_fpr, FREG)
 
-OP_DLOAD_FREG(DT1, DT1_fpr, DFREG)
-OP_DSTORE_FREG(DT1, DT1_fpr, DFREG)
+OP_DLOAD_FREG(DT1, DT1_fpr, FREG)
+OP_DSTORE_FREG(DT1, DT1_fpr, FREG)
 
-OP_DLOAD_FREG(DT2, DT2_fpr, DFREG)
-OP_DSTORE_FREG(DT2, DT2_fpr, DFREG)
+OP_DLOAD_FREG(DT2, DT2_fpr, FREG)
+OP_DSTORE_FREG(DT2, DT2_fpr, FREG)
+
+#define OP_PSLOAD_FREG(treg, tregname, FREG)             \
+    void glue(glue(op_load_fpr_,tregname), FREG) (void)  \
+    {                                                    \
+        treg = env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX];   \
+        RETURN();                                        \
+    }
+
+#define OP_PSSTORE_FREG(treg, tregname, FREG)            \
+    void glue(glue(op_store_fpr_,tregname), FREG) (void) \
+    {                                                    \
+        env->fpu->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg;   \
+        RETURN();                                        \
+    }
+
+OP_PSLOAD_FREG(WTH0, WTH0_fpr, FREG)
+OP_PSSTORE_FREG(WTH0, WTH0_fpr, FREG)
+
+OP_PSLOAD_FREG(WTH1, WTH1_fpr, FREG)
+OP_PSSTORE_FREG(WTH1, WTH1_fpr, FREG)
+
+OP_PSLOAD_FREG(WTH2, WTH2_fpr, FREG)
+OP_PSSTORE_FREG(WTH2, WTH2_fpr, FREG)
 
 #endif
 
 #if defined (FTN)
 
-#define SET_RESET(treg, tregname)    \
+#define SET_RESET(treg, tregname)        \
     void glue(op_set, tregname)(void)    \
-    {                                \
-        treg = PARAM1;               \
-        RETURN();                    \
-    }                                \
+    {                                    \
+        treg = PARAM1;                   \
+        RETURN();                        \
+    }                                    \
     void glue(op_reset, tregname)(void)  \
-    {                                \
-        treg = 0;                    \
-        RETURN();                    \
-    }                                \
+    {                                    \
+        treg = 0;                        \
+        RETURN();                        \
+    }
 
 SET_RESET(WT0, _WT0)
 SET_RESET(WT1, _WT1)
@@ -95,6 +123,9 @@
 SET_RESET(DT0, _DT0)
 SET_RESET(DT1, _DT1)
 SET_RESET(DT2, _DT2)
+SET_RESET(WTH0, _WTH0)
+SET_RESET(WTH1, _WTH1)
+SET_RESET(WTH2, _WTH2)
 
 #undef SET_RESET
 #endif
diff --git a/target-mips/helper.c b/target-mips/helper.c
index d2d7a9f..9c72481 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -1,6 +1,6 @@
 /*
  *  MIPS emulation helpers for qemu.
- * 
+ *
  *  Copyright (c) 2004-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
@@ -36,30 +36,58 @@
     TLBRET_MATCH = 0
 };
 
-/* MIPS32 4K MMU emulation */
-#ifdef MIPS_USES_R4K_TLB
-static int map_address (CPUState *env, target_ulong *physical, int *prot,
+/* no MMU emulation */
+int no_mmu_map_address (CPUState *env, target_ulong *physical, int *prot,
                         target_ulong address, int rw, int access_type)
 {
+    *physical = address;
+    *prot = PAGE_READ | PAGE_WRITE;
+    return TLBRET_MATCH;
+}
+
+/* fixed mapping MMU emulation */
+int fixed_mmu_map_address (CPUState *env, target_ulong *physical, int *prot,
+                           target_ulong address, int rw, int access_type)
+{
+    if (address <= (int32_t)0x7FFFFFFFUL) {
+        if (!(env->CP0_Status & (1 << CP0St_ERL)))
+            *physical = address + 0x40000000UL;
+        else
+            *physical = address;
+    } else if (address <= (int32_t)0xBFFFFFFFUL)
+        *physical = address & 0x1FFFFFFF;
+    else
+        *physical = address;
+
+    *prot = PAGE_READ | PAGE_WRITE;
+    return TLBRET_MATCH;
+}
+
+/* MIPS32/MIPS64 R4000-style MMU emulation */
+int r4k_map_address (CPUState *env, target_ulong *physical, int *prot,
+                     target_ulong address, int rw, int access_type)
+{
+    uint8_t ASID = env->CP0_EntryHi & 0xFF;
     int i;
 
-    for (i = 0; i < env->tlb_in_use; i++) {
-        tlb_t *tlb = &env->tlb[i];
+    for (i = 0; i < env->tlb->tlb_in_use; i++) {
+        r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
         /* 1k pages are not supported. */
-        uint8_t ASID = env->CP0_EntryHi & 0xFF;
-        target_ulong mask = tlb->PageMask | 0x1FFF;
+        target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
         target_ulong tag = address & ~mask;
-        int n;
+        target_ulong VPN = tlb->VPN & ~mask;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+        tag &= env->SEGMask;
+#endif
 
         /* Check ASID, virtual page number & size */
-        if ((tlb->G == 1 || tlb->ASID == ASID) &&
-            tlb->VPN == tag) {
+        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
             /* TLB match */
-            n = !!(address & mask & ~(mask >> 1));
+            int n = !!(address & mask & ~(mask >> 1));
             /* Check access rights */
-           if (!(n ? tlb->V1 : tlb->V0))
+            if (!(n ? tlb->V1 : tlb->V0))
                 return TLBRET_INVALID;
-           if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
+            if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
                 *physical = tlb->PFN[n] | (address & (mask >> 1));
                 *prot = PAGE_READ;
                 if (n ? tlb->D1 : tlb->D0)
@@ -71,14 +99,20 @@
     }
     return TLBRET_NOMATCH;
 }
-#endif
 
 static int get_physical_address (CPUState *env, target_ulong *physical,
                                 int *prot, target_ulong address,
                                 int rw, int access_type)
 {
-    /* User mode can only access useg */
+    /* User mode can only access useg/xuseg */
     int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
+    int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
+    int kernel_mode = !user_mode && !supervisor_mode;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+    int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+    int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+#endif
     int ret = TLBRET_MATCH;
 
 #if 0
@@ -87,52 +121,88 @@
                 user_mode, env->hflags);
     }
 #endif
-    if (user_mode && address > 0x7FFFFFFFUL)
-        return TLBRET_BADADDR;
-    if (address < (int32_t)0x80000000UL) {
-        if (!(env->hflags & MIPS_HFLAG_ERL)) {
-#ifdef MIPS_USES_R4K_TLB
-            ret = map_address(env, physical, prot, address, rw, access_type);
-#else
-            *physical = address + 0x40000000UL;
+
+    if (address <= (int32_t)0x7FFFFFFFUL) {
+        /* useg */
+        if (env->CP0_Status & (1 << CP0St_ERL)) {
+            *physical = address & 0xFFFFFFFF;
             *prot = PAGE_READ | PAGE_WRITE;
-#endif
         } else {
-            *physical = address;
-            *prot = PAGE_READ | PAGE_WRITE;
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
         }
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+/*
+   XXX: Assuming :
+   - PABITS = 36 (correct for MIPS64R1)
+*/
+    } else if (address < 0x3FFFFFFFFFFFFFFFULL) {
+        /* xuseg */
+	if (UX && address < (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+	} else {
+	    ret = TLBRET_BADADDR;
+        }
+    } else if (address < 0x7FFFFFFFFFFFFFFFULL) {
+        /* xsseg */
+	if ((supervisor_mode || kernel_mode) &&
+	    SX && address < (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+	} else {
+	    ret = TLBRET_BADADDR;
+        }
+    } else if (address < 0xBFFFFFFFFFFFFFFFULL) {
+        /* xkphys */
+        if (kernel_mode && KX &&
+            (address & 0x07FFFFFFFFFFFFFFULL) < 0X0000000FFFFFFFFFULL) {
+            *physical = address & 0X0000000FFFFFFFFFULL;
+            *prot = PAGE_READ | PAGE_WRITE;
+	} else {
+	    ret = TLBRET_BADADDR;
+	}
+    } else if (address < 0xFFFFFFFF7FFFFFFFULL) {
+        /* xkseg */
+	if (kernel_mode && KX &&
+	    address < (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+	} else {
+	    ret = TLBRET_BADADDR;
+	}
+#endif
     } else if (address < (int32_t)0xA0000000UL) {
         /* kseg0 */
-        /* XXX: check supervisor mode */
-        *physical = address - (int32_t)0x80000000UL;
-        *prot = PAGE_READ | PAGE_WRITE;
+        if (kernel_mode) {
+            *physical = address - (int32_t)0x80000000UL;
+            *prot = PAGE_READ | PAGE_WRITE;
+        } else {
+            ret = TLBRET_BADADDR;
+        }
     } else if (address < (int32_t)0xC0000000UL) {
         /* kseg1 */
-        /* XXX: check supervisor mode */
-        *physical = address - (int32_t)0xA0000000UL;
-        *prot = PAGE_READ | PAGE_WRITE;
+        if (kernel_mode) {
+            *physical = address - (int32_t)0xA0000000UL;
+            *prot = PAGE_READ | PAGE_WRITE;
+        } else {
+            ret = TLBRET_BADADDR;
+        }
     } else if (address < (int32_t)0xE0000000UL) {
-        /* kseg2 */
-#ifdef MIPS_USES_R4K_TLB
-        ret = map_address(env, physical, prot, address, rw, access_type);
-#else
-        *physical = address;
-        *prot = PAGE_READ | PAGE_WRITE;
-#endif
+        /* sseg */
+        if (supervisor_mode || kernel_mode) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+        } else {
+            ret = TLBRET_BADADDR;
+        }
     } else {
         /* kseg3 */
-        /* XXX: check supervisor mode */
         /* XXX: debug segment is not emulated */
-#ifdef MIPS_USES_R4K_TLB
-        ret = map_address(env, physical, prot, address, rw, access_type);
-#else
-        *physical = address;
-        *prot = PAGE_READ | PAGE_WRITE;
-#endif
+        if (kernel_mode) {
+            ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
+        } else {
+            ret = TLBRET_BADADDR;
+        }
     }
 #if 0
     if (logfile) {
-        fprintf(logfile, TLSZ " %d %d => " TLSZ " %d (%d)\n",
+        fprintf(logfile, TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n",
 		address, rw, access_type, *physical, *prot, ret);
     }
 #endif
@@ -140,13 +210,13 @@
     return ret;
 }
 
-#if defined(CONFIG_USER_ONLY) 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+#if defined(CONFIG_USER_ONLY)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
 #else
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     target_ulong phys_addr;
     int prot;
@@ -174,8 +244,8 @@
 #if 0
         cpu_dump_state(env, logfile, fprintf, 0);
 #endif
-        fprintf(logfile, "%s pc " TLSZ " ad " TLSZ " rw %d is_user %d smmu %d\n",
-                __func__, env->PC, address, rw, is_user, is_softmmu);
+        fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d is_user %d smmu %d\n",
+                __func__, env->PC[env->current_tc], address, rw, is_user, is_softmmu);
     }
 
     rw &= 1;
@@ -192,7 +262,7 @@
     ret = get_physical_address(env, &physical, &prot,
                                address, rw, access_type);
     if (logfile) {
-        fprintf(logfile, "%s address=" TLSZ " ret %d physical " TLSZ " prot %d\n",
+        fprintf(logfile, "%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_lx " prot %d\n",
                 __func__, address, ret, physical, prot);
     }
     if (ret == TLBRET_MATCH) {
@@ -230,14 +300,20 @@
             /* TLB match but 'D' bit is cleared */
             exception = EXCP_LTLBL;
             break;
-                
+
         }
         /* Raise exception */
         env->CP0_BadVAddr = address;
-        env->CP0_Context = (env->CP0_Context & 0xff800000) |
+        env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
 	                   ((address >> 9) &   0x007ffff0);
         env->CP0_EntryHi =
             (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+        env->CP0_EntryHi &= env->SEGMask;
+        env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
+                            ((address & 0xC00000000000ULL) >> (env->SEGBITS - 9)) |
+                            ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
+#endif
         env->exception_index = exception;
         env->error_code = error_code;
         ret = 1;
@@ -258,8 +334,8 @@
     int cause = -1;
 
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
-        fprintf(logfile, "%s enter: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n",
-                __func__, env->PC, env->CP0_EPC, cause, env->exception_index);
+        fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n",
+                __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index);
     }
     if (env->exception_index == EXCP_EXT_INTERRUPT &&
         (env->hflags & MIPS_HFLAG_DM))
@@ -273,7 +349,7 @@
          * (but we assume the pc has always been updated during
          *  code translation).
          */
-        env->CP0_DEPC = env->PC;
+        env->CP0_DEPC = env->PC[env->current_tc];
         goto enter_debug_mode;
     case EXCP_DINT:
         env->CP0_Debug |= 1 << CP0DB_DINT;
@@ -289,42 +365,47 @@
         goto set_DEPC;
     case EXCP_DDBL:
         env->CP0_Debug |= 1 << CP0DB_DDBL;
-        goto set_DEPC;
     set_DEPC:
         if (env->hflags & MIPS_HFLAG_BMASK) {
             /* If the exception was raised from a delay slot,
                come back to the jump.  */
-            env->CP0_DEPC = env->PC - 4;
+            env->CP0_DEPC = env->PC[env->current_tc] - 4;
             env->hflags &= ~MIPS_HFLAG_BMASK;
         } else {
-            env->CP0_DEPC = env->PC;
+            env->CP0_DEPC = env->PC[env->current_tc];
         }
     enter_debug_mode:
-        env->hflags |= MIPS_HFLAG_DM;
+        env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
+        env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM);
         /* EJTAG probe trap enable is not implemented... */
-        env->PC = (int32_t)0xBFC00480;
+        if (!(env->CP0_Status & (1 << CP0St_EXL)))
+            env->CP0_Cause &= ~(1 << CP0Ca_BD);
+        env->PC[env->current_tc] = (int32_t)0xBFC00480;
         break;
     case EXCP_RESET:
         cpu_reset(env);
         break;
     case EXCP_SRESET:
-        env->CP0_Status = (1 << CP0St_SR);
-        env->CP0_WatchLo = 0;
+        env->CP0_Status |= (1 << CP0St_SR);
+        memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
         goto set_error_EPC;
     case EXCP_NMI:
-        env->CP0_Status = (1 << CP0St_NMI);
+        env->CP0_Status |= (1 << CP0St_NMI);
     set_error_EPC:
         if (env->hflags & MIPS_HFLAG_BMASK) {
             /* If the exception was raised from a delay slot,
                come back to the jump.  */
-            env->CP0_ErrorEPC = env->PC - 4;
+            env->CP0_ErrorEPC = env->PC[env->current_tc] - 4;
             env->hflags &= ~MIPS_HFLAG_BMASK;
         } else {
-            env->CP0_ErrorEPC = env->PC;
+            env->CP0_ErrorEPC = env->PC[env->current_tc];
         }
-        env->hflags |= MIPS_HFLAG_ERL;
-	env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
-        env->PC = (int32_t)0xBFC00000;
+        env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
+        env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
+        env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM);
+        if (!(env->CP0_Status & (1 << CP0St_EXL)))
+            env->CP0_Cause &= ~(1 << CP0Ca_BD);
+        env->PC[env->current_tc] = (int32_t)0xBFC00000;
         break;
     case EXCP_MCHECK:
         cause = 24;
@@ -339,13 +420,26 @@
         /* XXX: TODO: manage defered watch exceptions */
         goto set_EPC;
     case EXCP_AdEL:
-    case EXCP_AdES:
         cause = 4;
         goto set_EPC;
+    case EXCP_AdES:
+        cause = 5;
+        goto set_EPC;
     case EXCP_TLBL:
         cause = 2;
-        if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
-            offset = 0x000;
+        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+            int R = env->CP0_BadVAddr >> 62;
+            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+
+            if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
+                offset = 0x080;
+            else
+#endif
+                offset = 0x000;
+        }
         goto set_EPC;
     case EXCP_IBE:
         cause = 6;
@@ -364,7 +458,8 @@
         goto set_EPC;
     case EXCP_CpU:
         cause = 11;
-        env->CP0_Cause = (env->CP0_Cause & ~0x03000000) | (env->error_code << 28);
+        env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
+                         (env->error_code << CP0Ca_CE);
         goto set_EPC;
     case EXCP_OVERFLOW:
         cause = 12;
@@ -372,34 +467,53 @@
     case EXCP_TRAP:
         cause = 13;
         goto set_EPC;
+    case EXCP_FPE:
+        cause = 15;
+        goto set_EPC;
     case EXCP_LTLBL:
         cause = 1;
         goto set_EPC;
     case EXCP_TLBS:
         cause = 3;
-        if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
-            offset = 0x000;
         goto set_EPC;
+    case EXCP_THREAD:
+        cause = 25;
+        if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+            int R = env->CP0_BadVAddr >> 62;
+            int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+            int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+            int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+
+            if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
+                offset = 0x080;
+            else
+#endif
+                offset = 0x000;
+        }
     set_EPC:
-        if (env->hflags & MIPS_HFLAG_BMASK) {
-            /* If the exception was raised from a delay slot,
-               come back to the jump.  */
-            env->CP0_EPC = env->PC - 4;
-            env->CP0_Cause |= 0x80000000;
-            env->hflags &= ~MIPS_HFLAG_BMASK;
-        } else {
-            env->CP0_EPC = env->PC;
-            env->CP0_Cause &= ~0x80000000;
+        if (!(env->CP0_Status & (1 << CP0St_EXL))) {
+            if (env->hflags & MIPS_HFLAG_BMASK) {
+                /* If the exception was raised from a delay slot,
+                   come back to the jump.  */
+                env->CP0_EPC = env->PC[env->current_tc] - 4;
+                env->CP0_Cause |= (1 << CP0Ca_BD);
+            } else {
+                env->CP0_EPC = env->PC[env->current_tc];
+                env->CP0_Cause &= ~(1 << CP0Ca_BD);
+            }
+            env->CP0_Status |= (1 << CP0St_EXL);
+            env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
+            env->hflags &= ~(MIPS_HFLAG_SM | MIPS_HFLAG_UM);
         }
+        env->hflags &= ~MIPS_HFLAG_BMASK;
         if (env->CP0_Status & (1 << CP0St_BEV)) {
-            env->PC = (int32_t)0xBFC00200;
+            env->PC[env->current_tc] = (int32_t)0xBFC00200;
         } else {
-            env->PC = (int32_t)0x80000000;
+            env->PC[env->current_tc] = (int32_t)(env->CP0_EBase & ~0x3ff);
         }
-        env->hflags |= MIPS_HFLAG_EXL;
-        env->CP0_Status |= (1 << CP0St_EXL);
-        env->PC += offset;
-        env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
+        env->PC[env->current_tc] += offset;
+        env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
         break;
     default:
         if (logfile) {
@@ -410,9 +524,9 @@
         exit(1);
     }
     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
-        fprintf(logfile, "%s: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n"
-                "    S %08x C %08x A " TLSZ " D " TLSZ "\n",
-                __func__, env->PC, env->CP0_EPC, cause, env->exception_index,
+        fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n"
+                "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
+                __func__, env->PC[env->current_tc], env->CP0_EPC, cause, env->exception_index,
                 env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
                 env->CP0_DEPC);
     }
@@ -420,34 +534,39 @@
 }
 #endif /* !defined(CONFIG_USER_ONLY) */
 
-void invalidate_tlb (CPUState *env, int idx, int use_extra)
+void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
 {
-    tlb_t *tlb;
+    r4k_tlb_t *tlb;
     target_ulong addr;
     target_ulong end;
     uint8_t ASID = env->CP0_EntryHi & 0xFF;
     target_ulong mask;
 
-    tlb = &env->tlb[idx];
-    /* The qemu TLB is flushed then the ASID changes, so no need to
+    tlb = &env->tlb->mmu.r4k.tlb[idx];
+    /* The qemu TLB is flushed when the ASID changes, so no need to
        flush these entries again.  */
     if (tlb->G == 0 && tlb->ASID != ASID) {
         return;
     }
 
-    if (use_extra && env->tlb_in_use < MIPS_TLB_MAX) {
+    if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
         /* For tlbwr, we can shadow the discarded entry into
 	   a new (fake) TLB entry, as long as the guest can not
 	   tell that it's there.  */
-        env->tlb[env->tlb_in_use] = *tlb;
-        env->tlb_in_use++;
+        env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
+        env->tlb->tlb_in_use++;
         return;
     }
 
     /* 1k pages are not supported. */
-    mask = tlb->PageMask | 0x1FFF;
+    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
     if (tlb->V0) {
-        addr = tlb->VPN;
+        addr = tlb->VPN & ~mask;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
+            addr |= 0x3FFFFF0000000000ULL;
+        }
+#endif
         end = addr | (mask >> 1);
         while (addr < end) {
             tlb_flush_page (env, addr);
@@ -455,8 +574,12 @@
         }
     }
     if (tlb->V1) {
-        addr = tlb->VPN | ((mask >> 1) + 1);
-        addr = tlb->VPN + TARGET_PAGE_SIZE;
+        addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+        if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
+            addr |= 0x3FFFFF0000000000ULL;
+        }
+#endif
         end = addr | mask;
         while (addr < end) {
             tlb_flush_page (env, addr);
diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
index 83480c6..5c98edf 100644
--- a/target-mips/mips-defs.h
+++ b/target-mips/mips-defs.h
@@ -1,93 +1,57 @@
 #if !defined (__QEMU_MIPS_DEFS_H__)
 #define __QEMU_MIPS_DEFS_H__
 
-/* If we want to use 64 bits host regs... */
-//#define USE_64BITS_REGS
 /* If we want to use host float regs... */
 //#define USE_HOST_FLOAT_REGS
 
-#define MIPS_R4Kc 0x00018000
-#define MIPS_R4Kp 0x00018300
-
-/* Emulate MIPS R4Kc for now */
-#define MIPS_CPU MIPS_R4Kc
-
-#if (MIPS_CPU == MIPS_R4Kc)
-/* 32 bits target */
-#undef MIPS_HAS_MIPS64
-//#define MIPS_HAS_MIPS64 1
 /* real pages are variable size... */
 #define TARGET_PAGE_BITS 12
-/* Uses MIPS R4Kx enhancements to MIPS32 architecture */
-#define MIPS_USES_R4K_EXT
-/* Uses MIPS R4Kc TLB model */
-#define MIPS_USES_R4K_TLB
-#define MIPS_TLB_NB 16
 #define MIPS_TLB_MAX 128
-/* basic FPU register support */
-#define MIPS_USES_FPU 1
-/* Define a implementation number of 1.
- * Define a major version 1, minor version 0.
- */
-#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0)
-  /* Have config1, is MIPS32R1, uses TLB, no virtual icache,
-     uncached coherency */
-#define MIPS_CONFIG0_1                                            \
-  ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) |      \
-   (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) |    \
-   (0x2 << CP0C0_K0))
-#ifdef TARGET_WORDS_BIGENDIAN
-#define MIPS_CONFIG0 (MIPS_CONFIG0_1 | (1 << CP0C0_BE))
-#else
-#define MIPS_CONFIG0 MIPS_CONFIG0_1
-#endif
-/* Have config2, 16 TLB entries, 64 sets Icache, 16 bytes Icache line,
-   2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
-   no coprocessor2 attached, no MDMX support attached,
-   no performance counters, watch registers present,
-   no code compression, EJTAG present, FPU enable bit depending on
-   MIPS_USES_FPU */
-#define MIPS_CONFIG1_1                                            \
-((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) |              \
- (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) |      \
- (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) |      \
- (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) |            \
- (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP))
-#ifdef MIPS_USES_FPU
-#define MIPS_CONFIG1  (MIPS_CONFIG1_1 | (1 << CP0C1_FP))
-#else
-#define MIPS_CONFIG1  (MIPS_CONFIG1_1 | (0 << CP0C1_FP))
-#endif
-/* Have config3, no tertiary/secondary caches implemented */
-#define MIPS_CONFIG2                                              \
-((1 << CP0C2_M))
-/* No config4, no DSP ASE, no large physaddr,
-   no external interrupt controller, no vectored interupts,
-   no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */
-#define MIPS_CONFIG3                                              \
-((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) |          \
- (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) |        \
- (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL))
-#elif (MIPS_CPU == MIPS_R4Kp)
-/* 32 bits target */
-#undef MIPS_HAS_MIPS64
-/* real pages are variable size... */
-#define TARGET_PAGE_BITS 12
-/* Uses MIPS R4Kx enhancements to MIPS32 architecture */
-#define MIPS_USES_R4K_EXT
-/* Uses MIPS R4Km FPM MMU model */
-#define MIPS_USES_R4K_FPM
-#else
-#error "MIPS CPU not defined"
-/* Reminder for other flags */
-//#undef MIPS_HAS_MIPS64
-//#define MIPS_USES_FPU
-#endif
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 #define TARGET_LONG_BITS 64
 #else
 #define TARGET_LONG_BITS 32
 #endif
 
+/* Masks used to mark instructions to indicate which ISA level they
+   were introduced in. */
+#define		ISA_MIPS1	0x00000001
+#define		ISA_MIPS2	0x00000002
+#define		ISA_MIPS3	0x00000004
+#define		ISA_MIPS4	0x00000008
+#define		ISA_MIPS5	0x00000010
+#define		ISA_MIPS32	0x00000020
+#define		ISA_MIPS32R2	0x00000040
+#define		ISA_MIPS64	0x00000080
+#define		ISA_MIPS64R2	0x00000100
+
+/* MIPS ASE */
+#define		ASE_MIPS16	0x00001000
+#define		ASE_MIPS3D	0x00002000
+#define		ASE_MDMX	0x00004000
+#define		ASE_DSP		0x00008000
+#define		ASE_DSPR2	0x00010000
+
+/* Chip specific instructions.   */
+/* Currently void */
+
+/* MIPS CPU defines.  */
+#define		CPU_MIPS1	(ISA_MIPS1)
+#define		CPU_MIPS2	(CPU_MIPS1 | ISA_MIPS2)
+#define		CPU_MIPS3	(CPU_MIPS2 | ISA_MIPS3)
+#define		CPU_MIPS4	(CPU_MIPS3 | ISA_MIPS4)
+#define		CPU_MIPS5	(CPU_MIPS4 | ISA_MIPS5)
+
+#define		CPU_MIPS32	(CPU_MIPS2 | ISA_MIPS32)
+#define		CPU_MIPS64	(CPU_MIPS5 | CPU_MIPS32 | ISA_MIPS64)
+
+#define		CPU_MIPS32R2	(CPU_MIPS32 | ISA_MIPS32R2)
+#define		CPU_MIPS64R2	(CPU_MIPS64 | CPU_MIPS32R2 | ISA_MIPS64R2)
+
+/* Strictly follow the architecture standard:
+   - Disallow "special" instruction handling for PMON/SPIM.
+   Note that we still maintain Count/Compare to match the host clock. */
+//#define MIPS_STRICT_STANDARD 1
+
 #endif /* !defined (__QEMU_MIPS_DEFS_H__) */
diff --git a/target-mips/op.c b/target-mips/op.c
index cd5c69c..4290970 100644
--- a/target-mips/op.c
+++ b/target-mips/op.c
@@ -1,8 +1,9 @@
 /*
  *  MIPS emulation micro-operations for qemu.
- * 
+ *
  *  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
@@ -23,27 +24,27 @@
 #include "exec.h"
 
 #ifndef CALL_FROM_TB0
-#define CALL_FROM_TB0(func) func();
+#define CALL_FROM_TB0(func) func()
 #endif
 #ifndef CALL_FROM_TB1
-#define CALL_FROM_TB1(func, arg0) func(arg0);
+#define CALL_FROM_TB1(func, arg0) func(arg0)
 #endif
 #ifndef CALL_FROM_TB1_CONST16
-#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0);
+#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0)
 #endif
 #ifndef CALL_FROM_TB2
-#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1);
+#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1)
 #endif
 #ifndef CALL_FROM_TB2_CONST16
 #define CALL_FROM_TB2_CONST16(func, arg0, arg1)     \
-CALL_FROM_TB2(func, arg0, arg1);
+        CALL_FROM_TB2(func, arg0, arg1)
 #endif
 #ifndef CALL_FROM_TB3
-#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2);
+#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2)
 #endif
 #ifndef CALL_FROM_TB4
 #define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
-        func(arg0, arg1, arg2, arg3);
+        func(arg0, arg1, arg2, arg3)
 #endif
 
 #define REG 1
@@ -144,143 +145,107 @@
 #include "op_template.c"
 #undef TN
 
-#ifdef MIPS_USES_FPU
-
-#define SFREG 0
-#define DFREG 0
+#define FREG 0
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 1
+#undef FREG
+#define FREG 1
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 2
-#define DFREG 2
+#undef FREG
+#define FREG 2
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 3
+#undef FREG
+#define FREG 3
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 4
-#define DFREG 4
+#undef FREG
+#define FREG 4
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 5
+#undef FREG
+#define FREG 5
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 6
-#define DFREG 6
+#undef FREG
+#define FREG 6
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 7
+#undef FREG
+#define FREG 7
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 8
-#define DFREG 8
+#undef FREG
+#define FREG 8
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 9
+#undef FREG
+#define FREG 9
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 10
-#define DFREG 10
+#undef FREG
+#define FREG 10
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 11
+#undef FREG
+#define FREG 11
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 12
-#define DFREG 12
+#undef FREG
+#define FREG 12
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 13
+#undef FREG
+#define FREG 13
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 14
-#define DFREG 14
+#undef FREG
+#define FREG 14
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 15
+#undef FREG
+#define FREG 15
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 16
-#define DFREG 16
+#undef FREG
+#define FREG 16
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 17
+#undef FREG
+#define FREG 17
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 18
-#define DFREG 18
+#undef FREG
+#define FREG 18
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 19
+#undef FREG
+#define FREG 19
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 20
-#define DFREG 20
+#undef FREG
+#define FREG 20
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 21
+#undef FREG
+#define FREG 21
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 22
-#define DFREG 22
+#undef FREG
+#define FREG 22
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 23
+#undef FREG
+#define FREG 23
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 24
-#define DFREG 24
+#undef FREG
+#define FREG 24
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 25
+#undef FREG
+#define FREG 25
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 26
-#define DFREG 26
+#undef FREG
+#define FREG 26
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 27
+#undef FREG
+#define FREG 27
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 28
-#define DFREG 28
+#undef FREG
+#define FREG 28
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 29
+#undef FREG
+#define FREG 29
 #include "fop_template.c"
-#undef SFREG
-#define SFREG 30
-#define DFREG 30
+#undef FREG
+#define FREG 30
 #include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 31
+#undef FREG
+#define FREG 31
 #include "fop_template.c"
-#undef SFREG
+#undef FREG
 
 #define FTN
 #include "fop_template.c"
 #undef FTN
 
-#endif
-
 void op_dup_T0 (void)
 {
     T2 = T0;
@@ -289,25 +254,25 @@
 
 void op_load_HI (void)
 {
-    T0 = env->HI;
+    T0 = env->HI[PARAM1][env->current_tc];
     RETURN();
 }
 
 void op_store_HI (void)
 {
-    env->HI = T0;
+    env->HI[PARAM1][env->current_tc] = T0;
     RETURN();
 }
 
 void op_load_LO (void)
 {
-    T0 = env->LO;
+    T0 = env->LO[PARAM1][env->current_tc];
     RETURN();
 }
 
 void op_store_LO (void)
 {
-    env->LO = T0;
+    env->LO[PARAM1][env->current_tc] = T0;
     RETURN();
 }
 
@@ -325,6 +290,22 @@
 #undef MEMSUFFIX
 #endif
 
+/* Addresses computation */
+void op_addr_add (void)
+{
+/* For compatibility with 32-bit code, data reference in user mode
+   with Status_UX = 0 should be casted to 32-bit and sign extended.
+   See the MIPS64 PRA manual, section 4.10. */
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    if ((env->hflags & MIPS_HFLAG_UM) &&
+        !(env->CP0_Status & (1 << CP0St_UX)))
+        T0 = (int64_t)(int32_t)(T0 + T1);
+    else
+#endif
+        T0 += T1;
+    RETURN();
+}
+
 /* Arithmetic */
 void op_add (void)
 {
@@ -340,7 +321,7 @@
     T0 = (int32_t)T0 + (int32_t)T1;
     if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) {
         /* operands of same sign, result different sign */
-        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
     }
     T0 = (int32_t)T0;
     RETURN();
@@ -360,7 +341,7 @@
     T0 = (int32_t)T0 - (int32_t)T1;
     if (((tmp ^ T1) & (tmp ^ T0)) >> 31) {
         /* operands of different sign, first operand and result different sign */
-        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
     }
     T0 = (int32_t)T0;
     RETURN();
@@ -372,25 +353,33 @@
     RETURN();
 }
 
+#if HOST_LONG_BITS < 64
+void op_div (void)
+{
+    CALL_FROM_TB0(do_div);
+    RETURN();
+}
+#else
 void op_div (void)
 {
     if (T1 != 0) {
-        env->LO = (int32_t)((int32_t)T0 / (int32_t)T1);
-        env->HI = (int32_t)((int32_t)T0 % (int32_t)T1);
+        env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
+        env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
     }
     RETURN();
 }
+#endif
 
 void op_divu (void)
 {
     if (T1 != 0) {
-        env->LO = (int32_t)((uint32_t)T0 / (uint32_t)T1);
-        env->HI = (int32_t)((uint32_t)T0 % (uint32_t)T1);
+        env->LO[0][env->current_tc] = (int32_t)((uint32_t)T0 / (uint32_t)T1);
+        env->HI[0][env->current_tc] = (int32_t)((uint32_t)T0 % (uint32_t)T1);
     }
     RETURN();
 }
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 /* Arithmetic */
 void op_dadd (void)
 {
@@ -406,7 +395,7 @@
     T0 += T1;
     if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 63) {
         /* operands of same sign, result different sign */
-        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
     }
     RETURN();
 }
@@ -425,7 +414,7 @@
     T0 = (int64_t)T0 - (int64_t)T1;
     if (((tmp ^ T1) & (tmp ^ T0)) >> 63) {
         /* operands of different sign, first operand and result different sign */
-        CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+        CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
     }
     RETURN();
 }
@@ -436,7 +425,6 @@
     RETURN();
 }
 
-#if TARGET_LONG_BITS > HOST_LONG_BITS
 /* Those might call libgcc functions.  */
 void op_ddiv (void)
 {
@@ -444,31 +432,23 @@
     RETURN();
 }
 
+#if TARGET_LONG_BITS > HOST_LONG_BITS
 void op_ddivu (void)
 {
     do_ddivu();
     RETURN();
 }
 #else
-void op_ddiv (void)
-{
-    if (T1 != 0) {
-        env->LO = (int64_t)T0 / (int64_t)T1;
-        env->HI = (int64_t)T0 % (int64_t)T1;
-    }
-    RETURN();
-}
-
 void op_ddivu (void)
 {
     if (T1 != 0) {
-        env->LO = T0 / T1;
-        env->HI = T0 % T1;
+        env->LO[0][env->current_tc] = T0 / T1;
+        env->HI[0][env->current_tc] = T0 % T1;
     }
     RETURN();
 }
 #endif
-#endif /* MIPS_HAS_MIPS64 */
+#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
 
 /* Logical */
 void op_and (void)
@@ -497,19 +477,19 @@
 
 void op_sll (void)
 {
-    T0 = (int32_t)((uint32_t)T0 << (uint32_t)T1);
+    T0 = (int32_t)((uint32_t)T0 << T1);
     RETURN();
 }
 
 void op_sra (void)
 {
-    T0 = (int32_t)((int32_t)T0 >> (uint32_t)T1);
+    T0 = (int32_t)((int32_t)T0 >> T1);
     RETURN();
 }
 
 void op_srl (void)
 {
-    T0 = (int32_t)((uint32_t)T0 >> (uint32_t)T1);
+    T0 = (int32_t)((uint32_t)T0 >> T1);
     RETURN();
 }
 
@@ -518,10 +498,9 @@
     target_ulong tmp;
 
     if (T1) {
-       tmp = (int32_t)((uint32_t)T0 << (0x20 - (uint32_t)T1));
-       T0 = (int32_t)((uint32_t)T0 >> (uint32_t)T1) | tmp;
-    } else
-       T0 = T1;
+       tmp = (int32_t)((uint32_t)T0 << (0x20 - T1));
+       T0 = (int32_t)((uint32_t)T0 >> T1) | tmp;
+    }
     RETURN();
 }
 
@@ -590,7 +569,7 @@
     RETURN();
 }
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 /* Those might call libgcc functions.  */
@@ -711,8 +690,7 @@
     if (T1) {
        tmp = T0 << (0x40 - T1);
        T0 = (T0 >> T1) | tmp;
-    } else
-       T0 = T1;
+    }
     RETURN();
 }
 
@@ -723,8 +701,7 @@
     if (T1) {
        tmp = T0 << (0x40 - (32 + T1));
        T0 = (T0 >> (32 + T1)) | tmp;
-    } else
-       T0 = T1;
+    }
     RETURN();
 }
 
@@ -793,7 +770,7 @@
     }
     RETURN();
 }
-#endif
+#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
 
 /* 64 bits arithmetic */
 #if TARGET_LONG_BITS > HOST_LONG_BITS
@@ -837,13 +814,14 @@
 
 static inline uint64_t get_HILO (void)
 {
-    return ((uint64_t)env->HI << 32) | ((uint64_t)(uint32_t)env->LO);
+    return ((uint64_t)env->HI[0][env->current_tc] << 32) |
+            ((uint64_t)(uint32_t)env->LO[0][env->current_tc]);
 }
 
 static inline void set_HILO (uint64_t HILO)
 {
-    env->LO = (int32_t)(HILO & 0xFFFFFFFF);
-    env->HI = (int32_t)(HILO >> 32);
+    env->LO[0][env->current_tc] = (int32_t)(HILO & 0xFFFFFFFF);
+    env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
 }
 
 void op_mult (void)
@@ -895,16 +873,16 @@
 }
 #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 void op_dmult (void)
 {
-    CALL_FROM_TB0(do_dmult);
+    CALL_FROM_TB4(muls64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1);
     RETURN();
 }
 
 void op_dmultu (void)
 {
-    CALL_FROM_TB0(do_dmultu);
+    CALL_FROM_TB4(mulu64, &(env->HI[0][env->current_tc]), &(env->LO[0][env->current_tc]), T0, T1);
     RETURN();
 }
 #endif
@@ -913,32 +891,30 @@
 void op_movn (void)
 {
     if (T1 != 0)
-        env->gpr[PARAM1] = T0;
+        env->gpr[PARAM1][env->current_tc] = T0;
     RETURN();
 }
 
 void op_movz (void)
 {
     if (T1 == 0)
-        env->gpr[PARAM1] = T0;
+        env->gpr[PARAM1][env->current_tc] = T0;
     RETURN();
 }
 
-#ifdef MIPS_USES_FPU
 void op_movf (void)
 {
-    if (!(env->fcr31 & PARAM1))
-        env->gpr[PARAM2] = env->gpr[PARAM3];
+    if (!(env->fpu->fcr31 & PARAM1))
+        T0 = T1;
     RETURN();
 }
 
 void op_movt (void)
 {
-    if (env->fcr31 & PARAM1)
-        env->gpr[PARAM2] = env->gpr[PARAM3];
+    if (env->fpu->fcr31 & PARAM1)
+        T0 = T1;
     RETURN();
 }
-#endif
 
 /* Tests */
 #define OP_COND(name, cond) \
@@ -954,18 +930,16 @@
 
 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 */
-//#undef USE_DIRECT_JUMP
-
 void OPPROTO op_goto_tb0(void)
 {
     GOTO_TB(op_goto_tb0, PARAM1, 0);
@@ -993,7 +967,7 @@
 
 void op_breg (void)
 {
-    env->PC = T2;
+    env->PC[env->current_tc] = T2;
     RETURN();
 }
 
@@ -1003,6 +977,14 @@
     RETURN();
 }
 
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+void op_save_btarget64 (void)
+{
+    env->btarget = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2;
+    RETURN();
+}
+#endif
+
 /* Conditional branch */
 void op_set_bcond (void)
 {
@@ -1036,18 +1018,176 @@
     RETURN();
 }
 
+void op_mfc0_mvpcontrol (void)
+{
+    T0 = env->mvp->CP0_MVPControl;
+    RETURN();
+}
+
+void op_mfc0_mvpconf0 (void)
+{
+    T0 = env->mvp->CP0_MVPConf0;
+    RETURN();
+}
+
+void op_mfc0_mvpconf1 (void)
+{
+    T0 = env->mvp->CP0_MVPConf1;
+    RETURN();
+}
+
 void op_mfc0_random (void)
 {
     CALL_FROM_TB0(do_mfc0_random);
     RETURN();
 }
 
+void op_mfc0_vpecontrol (void)
+{
+    T0 = env->CP0_VPEControl;
+    RETURN();
+}
+
+void op_mfc0_vpeconf0 (void)
+{
+    T0 = env->CP0_VPEConf0;
+    RETURN();
+}
+
+void op_mfc0_vpeconf1 (void)
+{
+    T0 = env->CP0_VPEConf1;
+    RETURN();
+}
+
+void op_mfc0_yqmask (void)
+{
+    T0 = env->CP0_YQMask;
+    RETURN();
+}
+
+void op_mfc0_vpeschedule (void)
+{
+    T0 = env->CP0_VPESchedule;
+    RETURN();
+}
+
+void op_mfc0_vpeschefback (void)
+{
+    T0 = env->CP0_VPEScheFBack;
+    RETURN();
+}
+
+void op_mfc0_vpeopt (void)
+{
+    T0 = env->CP0_VPEOpt;
+    RETURN();
+}
+
 void op_mfc0_entrylo0 (void)
 {
     T0 = (int32_t)env->CP0_EntryLo0;
     RETURN();
 }
 
+void op_mfc0_tcstatus (void)
+{
+    T0 = env->CP0_TCStatus[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcstatus(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCStatus[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tcbind (void)
+{
+    T0 = env->CP0_TCBind[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcbind(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCBind[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tcrestart (void)
+{
+    T0 = env->PC[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcrestart(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->PC[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tchalt (void)
+{
+    T0 = env->CP0_TCHalt[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tchalt(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCHalt[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tccontext (void)
+{
+    T0 = env->CP0_TCContext[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tccontext(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCContext[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tcschedule (void)
+{
+    T0 = env->CP0_TCSchedule[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcschedule(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCSchedule[other_tc];
+    RETURN();
+}
+
+void op_mfc0_tcschefback (void)
+{
+    T0 = env->CP0_TCScheFBack[env->current_tc];
+    RETURN();
+}
+
+void op_mftc0_tcschefback(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->CP0_TCScheFBack[other_tc];
+    RETURN();
+}
+
 void op_mfc0_entrylo1 (void)
 {
     T0 = (int32_t)env->CP0_EntryLo1;
@@ -1078,6 +1218,36 @@
     RETURN();
 }
 
+void op_mfc0_srsconf0 (void)
+{
+    T0 = env->CP0_SRSConf0;
+    RETURN();
+}
+
+void op_mfc0_srsconf1 (void)
+{
+    T0 = env->CP0_SRSConf1;
+    RETURN();
+}
+
+void op_mfc0_srsconf2 (void)
+{
+    T0 = env->CP0_SRSConf2;
+    RETURN();
+}
+
+void op_mfc0_srsconf3 (void)
+{
+    T0 = env->CP0_SRSConf3;
+    RETURN();
+}
+
+void op_mfc0_srsconf4 (void)
+{
+    T0 = env->CP0_SRSConf4;
+    RETURN();
+}
+
 void op_mfc0_hwrena (void)
 {
     T0 = env->CP0_HWREna;
@@ -1102,6 +1272,14 @@
     RETURN();
 }
 
+void op_mftc0_entryhi(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = (env->CP0_EntryHi & ~0xff) | (env->CP0_TCStatus[other_tc] & 0xff);
+    RETURN();
+}
+
 void op_mfc0_compare (void)
 {
     T0 = env->CP0_Compare;
@@ -1111,12 +1289,18 @@
 void op_mfc0_status (void)
 {
     T0 = env->CP0_Status;
-    if (env->hflags & MIPS_HFLAG_UM)
-        T0 |= (1 << CP0St_UM);
-    if (env->hflags & MIPS_HFLAG_ERL)
-        T0 |= (1 << CP0St_ERL);
-    if (env->hflags & MIPS_HFLAG_EXL)
-        T0 |= (1 << CP0St_EXL);
+    RETURN();
+}
+
+void op_mftc0_status(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t tcstatus = env->CP0_TCStatus[other_tc];
+
+    T0 = env->CP0_Status & ~0xf1000018;
+    T0 |= tcstatus & (0xf << CP0TCSt_TCU0);
+    T0 |= (tcstatus & (1 << CP0TCSt_TMX)) >> (CP0TCSt_TMX - CP0St_MX);
+    T0 |= (tcstatus & (0x3 << CP0TCSt_TKSU)) >> (CP0TCSt_TKSU - CP0St_R0);
     RETURN();
 }
 
@@ -1186,21 +1370,33 @@
     RETURN();
 }
 
+void op_mfc0_config6 (void)
+{
+    T0 = env->CP0_Config6;
+    RETURN();
+}
+
+void op_mfc0_config7 (void)
+{
+    T0 = env->CP0_Config7;
+    RETURN();
+}
+
 void op_mfc0_lladdr (void)
 {
     T0 = (int32_t)env->CP0_LLAddr >> 4;
     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();
 }
 
@@ -1224,6 +1420,17 @@
     RETURN();
 }
 
+void op_mftc0_debug(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    /* XXX: Might be wrong, check with EJTAG spec. */
+    T0 = (env->CP0_Debug & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
+         (env->CP0_Debug_tcstatus[other_tc] &
+          ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
+    RETURN();
+}
+
 void op_mfc0_depc (void)
 {
     T0 = (int32_t)env->CP0_DEPC;
@@ -1274,7 +1481,105 @@
 
 void op_mtc0_index (void)
 {
-    env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 & (MIPS_TLB_NB - 1));
+    env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->tlb->nb_tlb);
+    RETURN();
+}
+
+void op_mtc0_mvpcontrol (void)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP))
+        mask |= (1 << CP0MVPCo_CPA) | (1 << CP0MVPCo_VPC) |
+                (1 << CP0MVPCo_EVP);
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (1 << CP0MVPCo_STLB);
+    newval = (env->mvp->CP0_MVPControl & ~mask) | (T0 & mask);
+
+    // TODO: Enable/disable shared TLB, enable/disable VPEs.
+
+    env->mvp->CP0_MVPControl = newval;
+    RETURN();
+}
+
+void op_mtc0_vpecontrol (void)
+{
+    uint32_t mask;
+    uint32_t newval;
+
+    mask = (1 << CP0VPECo_YSI) | (1 << CP0VPECo_GSI) |
+           (1 << CP0VPECo_TE) | (0xff << CP0VPECo_TargTC);
+    newval = (env->CP0_VPEControl & ~mask) | (T0 & mask);
+
+    /* Yield scheduler intercept not implemented. */
+    /* Gating storage scheduler intercept not implemented. */
+
+    // TODO: Enable/disable TCs.
+
+    env->CP0_VPEControl = newval;
+    RETURN();
+}
+
+void op_mtc0_vpeconf0 (void)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
+        if (env->CP0_VPEConf0 & (1 << CP0VPEC0_VPA))
+            mask |= (0xff << CP0VPEC0_XTC);
+        mask |= (1 << CP0VPEC0_MVP) | (1 << CP0VPEC0_VPA);
+    }
+    newval = (env->CP0_VPEConf0 & ~mask) | (T0 & mask);
+
+    // TODO: TC exclusive handling due to ERL/EXL.
+
+    env->CP0_VPEConf0 = newval;
+    RETURN();
+}
+
+void op_mtc0_vpeconf1 (void)
+{
+    uint32_t mask = 0;
+    uint32_t newval;
+
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (0xff << CP0VPEC1_NCX) | (0xff << CP0VPEC1_NCP2) |
+                (0xff << CP0VPEC1_NCP1);
+    newval = (env->CP0_VPEConf1 & ~mask) | (T0 & mask);
+
+    /* UDI not implemented. */
+    /* CP2 not implemented. */
+
+    // TODO: Handle FPU (CP1) binding.
+
+    env->CP0_VPEConf1 = newval;
+    RETURN();
+}
+
+void op_mtc0_yqmask (void)
+{
+    /* Yield qualifier inputs not implemented. */
+    env->CP0_YQMask = 0x00000000;
+    RETURN();
+}
+
+void op_mtc0_vpeschedule (void)
+{
+    env->CP0_VPESchedule = T0;
+    RETURN();
+}
+
+void op_mtc0_vpeschefback (void)
+{
+    env->CP0_VPEScheFBack = T0;
+    RETURN();
+}
+
+void op_mtc0_vpeopt (void)
+{
+    env->CP0_VPEOpt = T0 & 0x0000ffff;
     RETURN();
 }
 
@@ -1282,7 +1587,136 @@
 {
     /* Large physaddr not implemented */
     /* 1k pages not implemented */
-    env->CP0_EntryLo0 = (int32_t)T0 & 0x3FFFFFFF;
+    env->CP0_EntryLo0 = T0 & 0x3FFFFFFF;
+    RETURN();
+}
+
+void op_mtc0_tcstatus (void)
+{
+    uint32_t mask = env->CP0_TCStatus_rw_bitmask;
+    uint32_t newval;
+
+    newval = (env->CP0_TCStatus[env->current_tc] & ~mask) | (T0 & mask);
+
+    // TODO: Sync with CP0_Status.
+
+    env->CP0_TCStatus[env->current_tc] = newval;
+    RETURN();
+}
+
+void op_mttc0_tcstatus (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    // TODO: Sync with CP0_Status.
+
+    env->CP0_TCStatus[other_tc] = T0;
+    RETURN();
+}
+
+void op_mtc0_tcbind (void)
+{
+    uint32_t mask = (1 << CP0TCBd_TBE);
+    uint32_t newval;
+
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (1 << CP0TCBd_CurVPE);
+    newval = (env->CP0_TCBind[env->current_tc] & ~mask) | (T0 & mask);
+    env->CP0_TCBind[env->current_tc] = newval;
+    RETURN();
+}
+
+void op_mttc0_tcbind (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t mask = (1 << CP0TCBd_TBE);
+    uint32_t newval;
+
+    if (env->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC))
+        mask |= (1 << CP0TCBd_CurVPE);
+    newval = (env->CP0_TCBind[other_tc] & ~mask) | (T0 & mask);
+    env->CP0_TCBind[other_tc] = newval;
+    RETURN();
+}
+
+void op_mtc0_tcrestart (void)
+{
+    env->PC[env->current_tc] = T0;
+    env->CP0_TCStatus[env->current_tc] &= ~(1 << CP0TCSt_TDS);
+    env->CP0_LLAddr = 0ULL;
+    /* MIPS16 not implemented. */
+    RETURN();
+}
+
+void op_mttc0_tcrestart (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->PC[other_tc] = T0;
+    env->CP0_TCStatus[other_tc] &= ~(1 << CP0TCSt_TDS);
+    env->CP0_LLAddr = 0ULL;
+    /* MIPS16 not implemented. */
+    RETURN();
+}
+
+void op_mtc0_tchalt (void)
+{
+    env->CP0_TCHalt[env->current_tc] = T0 & 0x1;
+
+    // TODO: Halt TC / Restart (if allocated+active) TC.
+
+    RETURN();
+}
+
+void op_mttc0_tchalt (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    // TODO: Halt TC / Restart (if allocated+active) TC.
+
+    env->CP0_TCHalt[other_tc] = T0;
+    RETURN();
+}
+
+void op_mtc0_tccontext (void)
+{
+    env->CP0_TCContext[env->current_tc] = T0;
+    RETURN();
+}
+
+void op_mttc0_tccontext (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->CP0_TCContext[other_tc] = T0;
+    RETURN();
+}
+
+void op_mtc0_tcschedule (void)
+{
+    env->CP0_TCSchedule[env->current_tc] = T0;
+    RETURN();
+}
+
+void op_mttc0_tcschedule (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->CP0_TCSchedule[other_tc] = T0;
+    RETURN();
+}
+
+void op_mtc0_tcschefback (void)
+{
+    env->CP0_TCScheFBack[env->current_tc] = T0;
+    RETURN();
+}
+
+void op_mttc0_tcschefback (void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->CP0_TCScheFBack[other_tc] = T0;
     RETURN();
 }
 
@@ -1290,20 +1724,20 @@
 {
     /* Large physaddr not implemented */
     /* 1k pages not implemented */
-    env->CP0_EntryLo1 = (int32_t)T0 & 0x3FFFFFFF;
+    env->CP0_EntryLo1 = T0 & 0x3FFFFFFF;
     RETURN();
 }
 
 void op_mtc0_context (void)
 {
-    env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0);
+    env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (T0 & ~0x007FFFFF);
     RETURN();
 }
 
 void op_mtc0_pagemask (void)
 {
     /* 1k pages not implemented */
-    env->CP0_PageMask = T0 & 0x1FFFE000;
+    env->CP0_PageMask = T0 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
     RETURN();
 }
 
@@ -1318,7 +1752,37 @@
 
 void op_mtc0_wired (void)
 {
-    env->CP0_Wired = T0 & (MIPS_TLB_NB - 1);
+    env->CP0_Wired = T0 % env->tlb->nb_tlb;
+    RETURN();
+}
+
+void op_mtc0_srsconf0 (void)
+{
+    env->CP0_SRSConf0 |= T0 & env->CP0_SRSConf0_rw_bitmask;
+    RETURN();
+}
+
+void op_mtc0_srsconf1 (void)
+{
+    env->CP0_SRSConf1 |= T0 & env->CP0_SRSConf1_rw_bitmask;
+    RETURN();
+}
+
+void op_mtc0_srsconf2 (void)
+{
+    env->CP0_SRSConf2 |= T0 & env->CP0_SRSConf2_rw_bitmask;
+    RETURN();
+}
+
+void op_mtc0_srsconf3 (void)
+{
+    env->CP0_SRSConf3 |= T0 & env->CP0_SRSConf3_rw_bitmask;
+    RETURN();
+}
+
+void op_mtc0_srsconf4 (void)
+{
+    env->CP0_SRSConf4 |= T0 & env->CP0_SRSConf4_rw_bitmask;
     RETURN();
 }
 
@@ -1339,16 +1803,31 @@
     target_ulong old, val;
 
     /* 1k pages not implemented */
-    /* Ignore MIPS64 TLB for now */
-    val = (int32_t)T0 & 0xFFFFE0FF;
+    val = T0 & ((TARGET_PAGE_MASK << 1) | 0xFF);
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    val &= env->SEGMask;
+#endif
     old = env->CP0_EntryHi;
     env->CP0_EntryHi = val;
+    if (env->CP0_Config3 & (1 << CP0C3_MT)) {
+        uint32_t tcst = env->CP0_TCStatus[env->current_tc] & ~0xff;
+        env->CP0_TCStatus[env->current_tc] = tcst | (val & 0xff);
+    }
     /* If the ASID changes, flush qemu's TLB.  */
     if ((old & 0xFF) != (val & 0xFF))
         CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1);
     RETURN();
 }
 
+void op_mttc0_entryhi(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    env->CP0_EntryHi = (env->CP0_EntryHi & 0xff) | (T0 & ~0xff);
+    env->CP0_TCStatus[other_tc] = (env->CP0_TCStatus[other_tc] & ~0xff) | (T0 & 0xff);
+    RETURN();
+}
+
 void op_mtc0_compare (void)
 {
     CALL_FROM_TB2(cpu_mips_store_compare, env, T0);
@@ -1358,52 +1837,67 @@
 void op_mtc0_status (void)
 {
     uint32_t val, old;
+    uint32_t mask = env->CP0_Status_rw_bitmask;
 
-    val = (int32_t)T0 & 0xFA78FF01;
+    val = T0 & mask;
     old = env->CP0_Status;
-    if (T0 & (1 << CP0St_UM))
-        env->hflags |= MIPS_HFLAG_UM;
-    else
-        env->hflags &= ~MIPS_HFLAG_UM;
-    if (T0 & (1 << CP0St_ERL))
-        env->hflags |= MIPS_HFLAG_ERL;
-    else
-        env->hflags &= ~MIPS_HFLAG_ERL;
-    if (T0 & (1 << CP0St_EXL))
-        env->hflags |= MIPS_HFLAG_EXL;
-    else
-        env->hflags &= ~MIPS_HFLAG_EXL;
-    env->CP0_Status = val;
-    if (loglevel & CPU_LOG_TB_IN_ASM)
-       CALL_FROM_TB2(do_mtc0_status_debug, old, val);
+    env->CP0_Status = (env->CP0_Status & ~mask) | val;
+    CALL_FROM_TB1(compute_hflags, env);
+    if (loglevel & CPU_LOG_EXEC)
+        CALL_FROM_TB2(do_mtc0_status_debug, old, val);
     CALL_FROM_TB1(cpu_mips_update_irq, env);
     RETURN();
 }
 
+void op_mttc0_status(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+    uint32_t tcstatus = env->CP0_TCStatus[other_tc];
+
+    env->CP0_Status = T0 & ~0xf1000018;
+    tcstatus = (tcstatus & ~(0xf << CP0TCSt_TCU0)) | (T0 & (0xf << CP0St_CU0));
+    tcstatus = (tcstatus & ~(1 << CP0TCSt_TMX)) | ((T0 & (1 << CP0St_MX)) << (CP0TCSt_TMX - CP0St_MX));
+    tcstatus = (tcstatus & ~(0x3 << CP0TCSt_TKSU)) | ((T0 & (0x3 << CP0St_R0)) << (CP0TCSt_TKSU - CP0St_R0));
+    env->CP0_TCStatus[other_tc] = tcstatus;
+    RETURN();
+}
+
 void op_mtc0_intctl (void)
 {
-    /* vectored interrupts not implemented */
-    env->CP0_IntCtl = 0;
+    /* vectored interrupts not implemented, no performance counters. */
+    env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000002e0) | (T0 & 0x000002e0);
     RETURN();
 }
 
 void op_mtc0_srsctl (void)
 {
-    /* shadow registers not implemented */
-    env->CP0_SRSCtl = 0;
+    uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS);
+    env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (T0 & mask);
     RETURN();
 }
 
 void op_mtc0_srsmap (void)
 {
-    /* shadow registers not implemented */
-    env->CP0_SRSMap = 0;
+    env->CP0_SRSMap = T0;
     RETURN();
 }
 
 void op_mtc0_cause (void)
 {
-    env->CP0_Cause = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300);
+    uint32_t mask = 0x00C00300;
+    uint32_t old = env->CP0_Cause;
+
+    if (env->insn_flags & ISA_MIPS32R2)
+        mask |= 1 << CP0Ca_DC;
+
+    env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask);
+
+    if ((old ^ env->CP0_Cause) & (1 << CP0Ca_DC)) {
+        if (env->CP0_Cause & (1 << CP0Ca_DC))
+            CALL_FROM_TB1(cpu_mips_stop_count, env);
+        else
+            CALL_FROM_TB1(cpu_mips_start_count, env);
+    }
 
     /* Handle the software interrupt as an hardware one, as they
        are very similar */
@@ -1415,7 +1909,7 @@
 
 void op_mtc0_epc (void)
 {
-    env->CP0_EPC = (int32_t)T0;
+    env->CP0_EPC = T0;
     RETURN();
 }
 
@@ -1429,12 +1923,7 @@
 
 void op_mtc0_config0 (void)
 {
-#if defined(MIPS_USES_R4K_TLB)
-     /* Fixed mapping MMU not implemented */
-    env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF88) | (T0 & 0x00000001);
-#else
-    env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF88) | (T0 & 0x00000001);
-#endif
+    env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (T0 & 0x00000007);
     RETURN();
 }
 
@@ -1445,21 +1934,25 @@
     RETURN();
 }
 
-void op_mtc0_watchlo0 (void)
+void op_mtc0_watchlo (void)
 {
-    env->CP0_WatchLo = (int32_t)T0;
+    /* Watch exceptions for instructions, data loads, data stores
+       not implemented. */
+    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[PARAM1] = (T0 & 0x40FF0FF8);
+    env->CP0_WatchHi[PARAM1] &= ~(env->CP0_WatchHi[PARAM1] & T0 & 0x7);
     RETURN();
 }
 
 void op_mtc0_xcontext (void)
 {
-    env->CP0_XContext = (int32_t)T0; /* XXX */
+    target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1;
+    env->CP0_XContext = (env->CP0_XContext & mask) | (T0 & ~mask);
     RETURN();
 }
 
@@ -1479,9 +1972,20 @@
     RETURN();
 }
 
+void op_mttc0_debug(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    /* XXX: Might be wrong, check with EJTAG spec. */
+    env->CP0_Debug_tcstatus[other_tc] = T0 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt));
+    env->CP0_Debug = (env->CP0_Debug & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt))) |
+                     (T0 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt)));
+    RETURN();
+}
+
 void op_mtc0_depc (void)
 {
-    env->CP0_DEPC = (int32_t)T0;
+    env->CP0_DEPC = T0;
     RETURN();
 }
 
@@ -1517,7 +2021,7 @@
 
 void op_mtc0_errorepc (void)
 {
-    env->CP0_ErrorEPC = (int32_t)T0;
+    env->CP0_ErrorEPC = T0;
     RETURN();
 }
 
@@ -1527,12 +2031,61 @@
     RETURN();
 }
 
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+void op_dmfc0_yqmask (void)
+{
+    T0 = env->CP0_YQMask;
+    RETURN();
+}
+
+void op_dmfc0_vpeschedule (void)
+{
+    T0 = env->CP0_VPESchedule;
+    RETURN();
+}
+
+void op_dmfc0_vpeschefback (void)
+{
+    T0 = env->CP0_VPEScheFBack;
+    RETURN();
+}
+
 void op_dmfc0_entrylo0 (void)
 {
     T0 = env->CP0_EntryLo0;
     RETURN();
 }
 
+void op_dmfc0_tcrestart (void)
+{
+    T0 = env->PC[env->current_tc];
+    RETURN();
+}
+
+void op_dmfc0_tchalt (void)
+{
+    T0 = env->CP0_TCHalt[env->current_tc];
+    RETURN();
+}
+
+void op_dmfc0_tccontext (void)
+{
+    T0 = env->CP0_TCContext[env->current_tc];
+    RETURN();
+}
+
+void op_dmfc0_tcschedule (void)
+{
+    T0 = env->CP0_TCSchedule[env->current_tc];
+    RETURN();
+}
+
+void op_dmfc0_tcschefback (void)
+{
+    T0 = env->CP0_TCScheFBack[env->current_tc];
+    RETURN();
+}
+
 void op_dmfc0_entrylo1 (void)
 {
     T0 = env->CP0_EntryLo1;
@@ -1569,9 +2122,9 @@
     RETURN();
 }
 
-void op_dmfc0_watchlo0 (void)
+void op_dmfc0_watchlo (void)
 {
-    T0 = env->CP0_WatchLo;
+    T0 = env->CP0_WatchLo[PARAM1];
     RETURN();
 }
 
@@ -1592,120 +2145,176 @@
     T0 = env->CP0_ErrorEPC;
     RETURN();
 }
+#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
 
-void op_dmtc0_entrylo0 (void)
+/* MIPS MT functions */
+void op_mftgpr(void)
 {
-    /* Large physaddr not implemented */
-    /* 1k pages not implemented */
-    env->CP0_EntryLo0 = T0 & 0x3FFFFFFF;
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->gpr[PARAM1][other_tc];
     RETURN();
 }
 
-void op_dmtc0_entrylo1 (void)
+void op_mftlo(void)
 {
-    /* Large physaddr not implemented */
-    /* 1k pages not implemented */
-    env->CP0_EntryLo1 = T0 & 0x3FFFFFFF;
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->LO[PARAM1][other_tc];
     RETURN();
 }
 
-void op_dmtc0_context (void)
+void op_mfthi(void)
 {
-    env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0);
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->HI[PARAM1][other_tc];
     RETURN();
 }
 
-void op_dmtc0_epc (void)
+void op_mftacx(void)
 {
-    env->CP0_EPC = T0;
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->ACX[PARAM1][other_tc];
     RETURN();
 }
 
-void op_dmtc0_watchlo0 (void)
+void op_mftdsp(void)
 {
-    env->CP0_WatchLo = T0;
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->DSPControl[other_tc];
     RETURN();
 }
 
-void op_dmtc0_xcontext (void)
+void op_mttgpr(void)
 {
-    env->CP0_XContext = T0; /* XXX */
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->gpr[PARAM1][other_tc];
     RETURN();
 }
 
-void op_dmtc0_depc (void)
+void op_mttlo(void)
 {
-    env->CP0_DEPC = T0;
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->LO[PARAM1][other_tc];
     RETURN();
 }
 
-void op_dmtc0_errorepc (void)
+void op_mtthi(void)
 {
-    env->CP0_ErrorEPC = T0;
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->HI[PARAM1][other_tc];
     RETURN();
 }
 
-#ifdef MIPS_USES_FPU
+void op_mttacx(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
+    T0 = env->ACX[PARAM1][other_tc];
+    RETURN();
+}
+
+void op_mttdsp(void)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    T0 = env->DSPControl[other_tc];
+    RETURN();
+}
+
+
+void op_dmt(void)
+{
+    // TODO
+    T0 = 0;
+    // rt = T0
+    RETURN();
+}
+
+void op_emt(void)
+{
+    // TODO
+    T0 = 0;
+    // rt = T0
+    RETURN();
+}
+
+void op_dvpe(void)
+{
+    // TODO
+    T0 = 0;
+    // rt = T0
+    RETURN();
+}
+
+void op_evpe(void)
+{
+    // TODO
+    T0 = 0;
+    // rt = T0
+    RETURN();
+}
+
+void op_fork(void)
+{
+    // T0 = rt, T1 = rs
+    T0 = 0;
+    // TODO: store to TC register
+    RETURN();
+}
+
+void op_yield(void)
+{
+    if (T0 < 0) {
+        /* No scheduling policy implemented. */
+        if (T0 != -2) {
+            if (env->CP0_VPEControl & (1 << CP0VPECo_YSI) &&
+                env->CP0_TCStatus[env->current_tc] & (1 << CP0TCSt_DT)) {
+                env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+                env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT;
+                CALL_FROM_TB1(do_raise_exception, EXCP_THREAD);
+            }
+        }
+    } else if (T0 == 0) {
+	if (0 /* TODO: TC underflow */) {
+            env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+            CALL_FROM_TB1(do_raise_exception, EXCP_THREAD);
+        } else {
+            // TODO: Deallocate TC
+        }
+    } else if (T0 > 0) {
+        /* Yield qualifier inputs not implemented. */
+        env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT);
+        env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT;
+        CALL_FROM_TB1(do_raise_exception, EXCP_THREAD);
+    }
+    T0 = env->CP0_YQMask;
+    RETURN();
+}
+
+/* CP1 functions */
 #if 0
 # define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env)
 #else
 # define DEBUG_FPU_STATE() do { } while(0)
 #endif
 
-void op_cp1_enabled(void)
-{
-    if (!(env->CP0_Status & (1 << CP0St_CU1))) {
-        CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1);
-    }
-    RETURN();
-}
-
-/* CP1 functions */
 void op_cfc1 (void)
 {
-    if (T1 == 0) {
-        T0 = env->fcr0;
-    }
-    else {
-        /* fetch fcr31, masking unused bits */
-        T0 = env->fcr31 & 0x0183FFFF;
-    }
+    CALL_FROM_TB1(do_cfc1, PARAM1);
     DEBUG_FPU_STATE();
     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)
-
 void op_ctc1 (void)
 {
-    if (T1 == 0) {
-        /* XXX should this throw an exception?
-         * don't write to FCR0.
-         * env->fcr0 = T0; 
-         */
-    }
-    else {
-        /* store new fcr31, masking unused bits */  
-        env->fcr31 = T0 & 0x0183FFFF;
-
-        /* set rounding mode */
-        RESTORE_ROUNDING_MODE;
-
-#ifndef CONFIG_SOFTFLOAT
-        /* no floating point exception for native float */
-        SET_FP_ENABLE(env->fcr31, 0);
-#endif
-    }
+    CALL_FROM_TB1(do_ctc1, PARAM1);
     DEBUG_FPU_STATE();
     RETURN();
 }
@@ -1724,145 +2333,415 @@
     RETURN();
 }
 
+void op_dmfc1 (void)
+{
+    T0 = DT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+void op_dmtc1 (void)
+{
+    DT0 = T0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+void op_mfhc1 (void)
+{
+    T0 = WTH0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
+void op_mthc1 (void)
+{
+    WTH0 = T0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+
 /* Float support.
    Single precition routines have a "s" suffix, double precision a
-   "d" suffix.  */
+   "d" suffix, 32bit integer "w", 64bit integer "l", paired singe "ps",
+   paired single lowwer "pl", paired single upper "pu".  */
 
 #define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void)
 
 FLOAT_OP(cvtd, s)
 {
-    FDT2 = float32_to_float64(WT0, &env->fp_status);
+    CALL_FROM_TB0(do_float_cvtd_s);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtd, w)
 {
-    FDT2 = int32_to_float64(WT0, &env->fp_status);
+    CALL_FROM_TB0(do_float_cvtd_w);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvtd, l)
+{
+    CALL_FROM_TB0(do_float_cvtd_l);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvtl, d)
+{
+    CALL_FROM_TB0(do_float_cvtl_d);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvtl, s)
+{
+    CALL_FROM_TB0(do_float_cvtl_s);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvtps, s)
+{
+    WT2 = WT0;
+    WTH2 = WT1;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvtps, pw)
+{
+    CALL_FROM_TB0(do_float_cvtps_pw);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvtpw, ps)
+{
+    CALL_FROM_TB0(do_float_cvtpw_ps);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvts, d)
 {
-    FST2 = float64_to_float32(FDT0, &env->fp_status);
+    CALL_FROM_TB0(do_float_cvts_d);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvts, w)
 {
-    FST2 = int32_to_float32(WT0, &env->fp_status);
+    CALL_FROM_TB0(do_float_cvts_w);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvts, l)
+{
+    CALL_FROM_TB0(do_float_cvts_l);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvts, pl)
+{
+    CALL_FROM_TB0(do_float_cvts_pl);
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(cvts, pu)
+{
+    CALL_FROM_TB0(do_float_cvts_pu);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtw, s)
 {
-    WT2 = float32_to_int32(FST0, &env->fp_status);
+    CALL_FROM_TB0(do_float_cvtw_s);
     DEBUG_FPU_STATE();
     RETURN();
 }
 FLOAT_OP(cvtw, d)
 {
-    WT2 = float64_to_int32(FDT0, &env->fp_status);
+    CALL_FROM_TB0(do_float_cvtw_d);
     DEBUG_FPU_STATE();
     RETURN();
 }
 
-FLOAT_OP(roundw, d)
+FLOAT_OP(pll, ps)
 {
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    WT2 = float64_round_to_int(FDT0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
-
+    DT2 = ((uint64_t)WT0 << 32) | WT1;
     DEBUG_FPU_STATE();
     RETURN();
 }
-FLOAT_OP(roundw, s)
+FLOAT_OP(plu, ps)
 {
-    set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
-    WT2 = float32_round_to_int(FST0, &env->fp_status);
-    RESTORE_ROUNDING_MODE;
+    DT2 = ((uint64_t)WT0 << 32) | WTH1;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(pul, ps)
+{
+    DT2 = ((uint64_t)WTH0 << 32) | WT1;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(puu, ps)
+{
+    DT2 = ((uint64_t)WTH0 << 32) | WTH1;
     DEBUG_FPU_STATE();
     RETURN();
 }
 
-FLOAT_OP(truncw, d)
+#define FLOAT_ROUNDOP(op, ttype, stype)                    \
+FLOAT_OP(op ## ttype, stype)                               \
+{                                                          \
+    CALL_FROM_TB0(do_float_ ## op ## ttype ## _ ## stype); \
+    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_ROUNDOP(trunc, l, d)
+FLOAT_ROUNDOP(trunc, l, s)
+FLOAT_ROUNDOP(trunc, w, d)
+FLOAT_ROUNDOP(trunc, w, s)
+
+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)
 {
-    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
+    if (!(env->fpu->fcr31 & PARAM1))
+        DT2 = DT0;
     DEBUG_FPU_STATE();
     RETURN();
 }
-FLOAT_OP(truncw, s)
+FLOAT_OP(movf, s)
 {
-    WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
+    if (!(env->fpu->fcr31 & PARAM1))
+        WT2 = WT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movf, ps)
+{
+    if (!(env->fpu->fcr31 & PARAM1)) {
+        WT2 = WT0;
+        WTH2 = WTH0;
+    }
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movt, d)
+{
+    if (env->fpu->fcr31 & PARAM1)
+        DT2 = DT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movt, s)
+{
+    if (env->fpu->fcr31 & PARAM1)
+        WT2 = WT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movt, ps)
+{
+    if (env->fpu->fcr31 & PARAM1) {
+        WT2 = WT0;
+        WTH2 = WTH0;
+    }
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movz, d)
+{
+    if (!T0)
+        DT2 = DT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movz, s)
+{
+    if (!T0)
+        WT2 = WT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movz, ps)
+{
+    if (!T0) {
+        WT2 = WT0;
+        WTH2 = WTH0;
+    }
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movn, d)
+{
+    if (T0)
+        DT2 = DT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movn, s)
+{
+    if (T0)
+        WT2 = WT0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(movn, ps)
+{
+    if (T0) {
+        WT2 = WT0;
+        WTH2 = WTH0;
+    }
     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;
-
-    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;
-    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;
-
-    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;
-    DEBUG_FPU_STATE();
-    RETURN();
-}
-
-/* binary operations */
-#define FLOAT_BINOP(name) \
+/* operations calling helpers, for s, d and ps */
+#define FLOAT_HOP(name) \
 FLOAT_OP(name, d)         \
 {                         \
-    FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status);    \
+    CALL_FROM_TB0(do_float_ ## name ## _d);  \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
-    FST2 = float32_ ## name (FST0, FST1, &env->fp_status);    \
+    CALL_FROM_TB0(do_float_ ## name ## _s);  \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
+}                         \
+FLOAT_OP(name, ps)        \
+{                         \
+    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
+
+/* 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)        \
+{                                  \
+    FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status);    \
+    FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status);    \
+    DEBUG_FPU_STATE();             \
+    RETURN();                      \
+}                                  \
+FLOAT_OP(name1 ## name2, s)        \
+{                                  \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
+    DEBUG_FPU_STATE();             \
+    RETURN();                      \
+}                                  \
+FLOAT_OP(name1 ## name2, ps)       \
+{                                  \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
+    FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
+    FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
+    DEBUG_FPU_STATE();             \
+    RETURN();                      \
+}
+FLOAT_TERNOP(mul, add)
+FLOAT_TERNOP(mul, sub)
+#undef FLOAT_TERNOP
+
+/* negated ternary operations */
+#define FLOAT_NTERNOP(name1, name2) \
+FLOAT_OP(n ## name1 ## name2, d)    \
+{                                   \
+    FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fpu->fp_status);    \
+    FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fpu->fp_status);    \
+    FDT2 ^= 1ULL << 63;             \
+    DEBUG_FPU_STATE();              \
+    RETURN();                       \
+}                                   \
+FLOAT_OP(n ## name1 ## name2, s)    \
+{                                   \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
+    FST2 ^= 1 << 31;                \
+    DEBUG_FPU_STATE();              \
+    RETURN();                       \
+}                                   \
+FLOAT_OP(n ## name1 ## name2, ps)   \
+{                                   \
+    FST0 = float32_ ## name1 (FST0, FST1, &env->fpu->fp_status);    \
+    FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fpu->fp_status); \
+    FST2 = float32_ ## name2 (FST0, FST2, &env->fpu->fp_status);    \
+    FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fpu->fp_status); \
+    FST2 ^= 1 << 31;                \
+    FSTH2 ^= 1 << 31;               \
+    DEBUG_FPU_STATE();              \
+    RETURN();                       \
+}
+FLOAT_NTERNOP(mul, add)
+FLOAT_NTERNOP(mul, sub)
+#undef FLOAT_NTERNOP
 
 /* unary operations, modifying fp status  */
 #define FLOAT_UNOP(name)  \
 FLOAT_OP(name, d)         \
 {                         \
-    FDT2 = float64_ ## name(FDT0, &env->fp_status);   \
+    FDT2 = float64_ ## name(FDT0, &env->fpu->fp_status);   \
     DEBUG_FPU_STATE();    \
+    RETURN();                      \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
-    FST2 = float32_ ## name(FST0, &env->fp_status);   \
+    FST2 = float32_ ## name(FST0, &env->fpu->fp_status);   \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }
 FLOAT_UNOP(sqrt)
 #undef FLOAT_UNOP
@@ -1873,11 +2752,20 @@
 {                         \
     FDT2 = float64_ ## name(FDT0);   \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
 }                         \
 FLOAT_OP(name, s)         \
 {                         \
     FST2 = float32_ ## name(FST0);   \
     DEBUG_FPU_STATE();    \
+    RETURN();             \
+}                         \
+FLOAT_OP(name, ps)        \
+{                         \
+    FST2 = float32_ ## name(FST0);   \
+    FSTH2 = float32_ ## name(FSTH0); \
+    DEBUG_FPU_STATE();    \
+    RETURN();             \
 }
 FLOAT_UNOP(abs)
 FLOAT_UNOP(chs)
@@ -1895,12 +2783,41 @@
     DEBUG_FPU_STATE();
     RETURN();
 }
+FLOAT_OP(mov, ps)
+{
+    FST2 = FST0;
+    FSTH2 = FSTH0;
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+FLOAT_OP(alnv, ps)
+{
+    switch (T0 & 0x7) {
+    case 0:
+        FST2 = FST0;
+        FSTH2 = FSTH0;
+        break;
+    case 4:
+#ifdef TARGET_WORDS_BIGENDIAN
+        FSTH2 = FST0;
+        FST2 = FSTH1;
+#else
+        FSTH2 = FST1;
+        FST2 = FSTH0;
+#endif
+        break;
+    default: /* unpredictable */
+        break;
+    }
+    DEBUG_FPU_STATE();
+    RETURN();
+}
 
 #ifdef CONFIG_SOFTFLOAT
 #define clear_invalid() do {                                \
-    int flags = get_float_exception_flags(&env->fp_status); \
+    int flags = get_float_exception_flags(&env->fpu->fp_status); \
     flags &= ~float_flag_invalid;                           \
-    set_float_exception_flags(flags, &env->fp_status);      \
+    set_float_exception_flags(flags, &env->fpu->fp_status);      \
 } while(0)
 #else
 #define clear_invalid() do { } while(0)
@@ -1908,128 +2825,113 @@
 
 extern void dump_fpu_s(CPUState *env);
 
-#define FOP_COND(fmt, op, sig, cond)           \
-void op_cmp_ ## fmt ## _ ## op (void)          \
-{                                              \
-    if (cond)                                  \
-        SET_FP_COND(env->fcr31);               \
-    else                                       \
-        CLEAR_FP_COND(env->fcr31);             \
-    if (!sig)                                  \
-        clear_invalid();                       \
-    /*CALL_FROM_TB1(dump_fpu_s, 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(float64 a, float64 b STATUS_PARAM)
-{
-    if (float64_is_nan(a) || float64_is_nan(b)) {
-        float_raise(float_flag_invalid, status);
-        return 1;
-    }
-    else {
-        return 0;
-    }
-}
-
-FOP_COND(d, f,   0,                                                      0) 
-FOP_COND(d, un,  0, float64_is_unordered(FDT1, FDT0, &env->fp_status))
-FOP_COND(d, eq,  0,                                                      float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, olt, 0,                                                      float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ole, 0,                                                      float64_le(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ule, 0, float64_is_unordered(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,  1,                                                      (float64_is_unordered(FDT0, FDT1, &env->fp_status), 0))
-FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status))
-FOP_COND(d, seq, 1,                                                      float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, lt,  1,                                                      float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, le,  1,                                                      float64_le(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
-
-flag float32_is_unordered(float32 a, float32 b STATUS_PARAM)
-{
-    extern flag float32_is_nan( float32 a );
-    if (float32_is_nan(a) || float32_is_nan(b)) {
-        float_raise(float_flag_invalid, status);
-        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,   0,                                                      0) 
-FOP_COND(s, un,  0, float32_is_unordered(FST1, FST0, &env->fp_status))
-FOP_COND(s, eq,  0,                                                      float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND(s, olt, 0,                                                      float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND(s, ole, 0,                                                      float32_le(FST0, FST1, &env->fp_status))
-FOP_COND(s, ule, 0, float32_is_unordered(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,  1,                                                      (float32_is_unordered(FST0, FST1, &env->fp_status), 0))
-FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status))
-FOP_COND(s, seq, 1,                                                      float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND(s, lt,  1,                                                      float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND(s, le,  1,                                                      float32_le(FST0, FST1, &env->fp_status))
-FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
+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
 
 void op_bc1f (void)
 {
-    T0 = ! IS_FP_COND_SET(env->fcr31);
+    T0 = !!(~GET_FP_COND(env->fpu) & (0x1 << PARAM1));
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+void op_bc1any2f (void)
+{
+    T0 = !!(~GET_FP_COND(env->fpu) & (0x3 << PARAM1));
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+void op_bc1any4f (void)
+{
+    T0 = !!(~GET_FP_COND(env->fpu) & (0xf << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
 
 void op_bc1t (void)
 {
-    T0 = IS_FP_COND_SET(env->fcr31);
+    T0 = !!(GET_FP_COND(env->fpu) & (0x1 << PARAM1));
     DEBUG_FPU_STATE();
     RETURN();
 }
-#endif /* MIPS_USES_FPU */
+void op_bc1any2t (void)
+{
+    T0 = !!(GET_FP_COND(env->fpu) & (0x3 << PARAM1));
+    DEBUG_FPU_STATE();
+    RETURN();
+}
+void op_bc1any4t (void)
+{
+    T0 = !!(GET_FP_COND(env->fpu) & (0xf << PARAM1));
+    DEBUG_FPU_STATE();
+    RETURN();
+}
 
-#if defined(MIPS_USES_R4K_TLB)
 void op_tlbwi (void)
 {
-    CALL_FROM_TB0(do_tlbwi);
+    CALL_FROM_TB0(env->tlb->do_tlbwi);
     RETURN();
 }
 
 void op_tlbwr (void)
 {
-    CALL_FROM_TB0(do_tlbwr);
+    CALL_FROM_TB0(env->tlb->do_tlbwr);
     RETURN();
 }
 
 void op_tlbp (void)
 {
-    CALL_FROM_TB0(do_tlbp);
+    CALL_FROM_TB0(env->tlb->do_tlbp);
     RETURN();
 }
 
 void op_tlbr (void)
 {
-    CALL_FROM_TB0(do_tlbr);
+    CALL_FROM_TB0(env->tlb->do_tlbr);
     RETURN();
 }
+
+/* Specials */
+#if defined (CONFIG_USER_ONLY)
+void op_tls_value (void)
+{
+    T0 = env->tls_value;
+}
 #endif
 
-/* Specials */
 void op_pmon (void)
 {
     CALL_FROM_TB1(do_pmon, PARAM1);
@@ -2055,7 +2957,7 @@
 void op_trap (void)
 {
     if (T0) {
-        CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP);
+        CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
     }
     RETURN();
 }
@@ -2072,63 +2974,76 @@
     RETURN();
 }
 
-void debug_eret (void);
+void debug_pre_eret (void);
+void debug_post_eret (void);
 void op_eret (void)
 {
-    CALL_FROM_TB0(debug_eret);
-    if (env->hflags & MIPS_HFLAG_ERL) {
-        env->PC = env->CP0_ErrorEPC;
-        env->hflags &= ~MIPS_HFLAG_ERL;
-	env->CP0_Status &= ~(1 << CP0St_ERL);
+    if (loglevel & CPU_LOG_EXEC)
+        CALL_FROM_TB0(debug_pre_eret);
+    if (env->CP0_Status & (1 << CP0St_ERL)) {
+        env->PC[env->current_tc] = env->CP0_ErrorEPC;
+        env->CP0_Status &= ~(1 << CP0St_ERL);
     } else {
-        env->PC = env->CP0_EPC;
-        env->hflags &= ~MIPS_HFLAG_EXL;
-	env->CP0_Status &= ~(1 << CP0St_EXL);
+        env->PC[env->current_tc] = env->CP0_EPC;
+        env->CP0_Status &= ~(1 << CP0St_EXL);
     }
+    CALL_FROM_TB1(compute_hflags, env);
+    if (loglevel & CPU_LOG_EXEC)
+        CALL_FROM_TB0(debug_post_eret);
     env->CP0_LLAddr = 1;
     RETURN();
 }
 
 void op_deret (void)
 {
-    CALL_FROM_TB0(debug_eret);
-    env->PC = env->CP0_DEPC;
+    if (loglevel & CPU_LOG_EXEC)
+        CALL_FROM_TB0(debug_pre_eret);
+    env->PC[env->current_tc] = env->CP0_DEPC;
+    env->hflags &= MIPS_HFLAG_DM;
+    CALL_FROM_TB1(compute_hflags, env);
+    if (loglevel & CPU_LOG_EXEC)
+        CALL_FROM_TB0(debug_post_eret);
+    env->CP0_LLAddr = 1;
     RETURN();
 }
 
 void op_rdhwr_cpunum(void)
 {
-    if (env->CP0_HWREna & (1 << 0))
-       T0 = env->CP0_EBase & 0x2ff;
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 0)))
+        T0 = env->CP0_EBase & 0x3ff;
     else
-       CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+        CALL_FROM_TB1(do_raise_exception, EXCP_RI);
     RETURN();
 }
 
 void op_rdhwr_synci_step(void)
 {
-    if (env->CP0_HWREna & (1 << 1))
-       T0 = env->SYNCI_Step;
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 1)))
+        T0 = env->SYNCI_Step;
     else
-       CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+        CALL_FROM_TB1(do_raise_exception, EXCP_RI);
     RETURN();
 }
 
 void op_rdhwr_cc(void)
 {
-    if (env->CP0_HWREna & (1 << 2))
-       T0 = env->CP0_Count;
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 2)))
+        T0 = env->CP0_Count;
     else
-       CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+        CALL_FROM_TB1(do_raise_exception, EXCP_RI);
     RETURN();
 }
 
 void op_rdhwr_ccres(void)
 {
-    if (env->CP0_HWREna & (1 << 3))
-       T0 = env->CCRes;
+    if ((env->hflags & MIPS_HFLAG_CP0) ||
+        (env->CP0_HWREna & (1 << 3)))
+        T0 = env->CCRes;
     else
-       CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+        CALL_FROM_TB1(do_raise_exception, EXCP_RI);
     RETURN();
 }
 
@@ -2140,7 +3055,28 @@
 
 void op_save_pc (void)
 {
-    env->PC = PARAM1;
+    env->PC[env->current_tc] = PARAM1;
+    RETURN();
+}
+
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+void op_save_pc64 (void)
+{
+    env->PC[env->current_tc] = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2;
+    RETURN();
+}
+#endif
+
+void op_interrupt_restart (void)
+{
+    if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+        !(env->CP0_Status & (1 << CP0St_ERL)) &&
+        !(env->hflags & MIPS_HFLAG_DM) &&
+        (env->CP0_Status & (1 << CP0St_IE)) &&
+        (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
+        env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
+        CALL_FROM_TB1(do_raise_exception, EXCP_EXT_INTERRUPT);
+    }
     RETURN();
 }
 
@@ -2175,7 +3111,7 @@
     unsigned int pos = PARAM1;
     unsigned int size = PARAM2;
 
-    T0 = ((uint32_t)T1 >> pos) & ((1 << size) - 1);
+    T0 = ((uint32_t)T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0);
     RETURN();
 }
 
@@ -2183,9 +3119,9 @@
 {
     unsigned int pos = PARAM1;
     unsigned int size = PARAM2;
-    target_ulong mask = ((1 << size) - 1) << pos;
+    target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos;
 
-    T0 = (T2 & ~mask) | (((uint32_t)T1 << pos) & mask);
+    T0 = (T0 & ~mask) | (((uint32_t)T1 << pos) & mask);
     RETURN();
 }
 
@@ -2195,13 +3131,13 @@
     RETURN();
 }
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 void op_dext(void)
 {
     unsigned int pos = PARAM1;
     unsigned int size = PARAM2;
 
-    T0 = (T1 >> pos) & ((1 << size) - 1);
+    T0 = (T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0);
     RETURN();
 }
 
@@ -2209,9 +3145,9 @@
 {
     unsigned int pos = PARAM1;
     unsigned int size = PARAM2;
-    target_ulong mask = ((1 << size) - 1) << pos;
+    target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos;
 
-    T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+    T0 = (T0 & ~mask) | ((T1 << pos) & mask);
     RETURN();
 }
 
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 9596d04..f431328 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -1,6 +1,6 @@
 /*
  *  MIPS emulation helpers for qemu.
- * 
+ *
  *  Copyright (c) 2004-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
@@ -17,18 +17,13 @@
  * 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 <stdlib.h>
 #include "exec.h"
 
-#define MIPS_DEBUG_DISAS
-
 #define GETPC() (__builtin_return_address(0))
 
 /*****************************************************************************/
 /* Exceptions processing helpers */
-void cpu_loop_exit(void)
-{
-    longjmp(env->jmp_env, 1);
-}
 
 void do_raise_exception_err (uint32_t exception, int error_code)
 {
@@ -56,10 +51,15 @@
   cpu_restore_state (tb, env, pc, NULL);
 }
 
-void do_raise_exception_direct (uint32_t exception)
+void do_raise_exception_direct_err (uint32_t exception, int error_code)
 {
     do_restore_state (GETPC ());
-    do_raise_exception_err (exception, 0);
+    do_raise_exception_err (exception, error_code);
+}
+
+void do_raise_exception_direct (uint32_t exception)
+{
+    do_raise_exception_direct_err (exception, 0);
 }
 
 #define MEMSUFFIX _raw
@@ -74,7 +74,7 @@
 #undef MEMSUFFIX
 #endif
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 /* Those might call libgcc functions.  */
 void do_dsll (void)
@@ -114,8 +114,7 @@
     if (T1) {
        tmp = T0 << (0x40 - T1);
        T0 = (T0 >> T1) | tmp;
-    } else
-       T0 = T1;
+    }
 }
 
 void do_drotr32 (void)
@@ -125,8 +124,7 @@
     if (T1) {
        tmp = T0 << (0x40 - (32 + T1));
        T0 = (T0 >> (32 + T1)) | tmp;
-    } else
-       T0 = T1;
+    }
 }
 
 void do_dsllv (void)
@@ -156,19 +154,19 @@
        T0 = T1;
 }
 #endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
-#endif /* MIPS_HAS_MIPS64 */
+#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
 
 /* 64 bits arithmetic for 32 bits hosts */
 #if TARGET_LONG_BITS > HOST_LONG_BITS
 static inline uint64_t get_HILO (void)
 {
-    return (env->HI << 32) | (uint32_t)env->LO;
+    return (env->HI[0][env->current_tc] << 32) | (uint32_t)env->LO[0][env->current_tc];
 }
 
 static inline void set_HILO (uint64_t HILO)
 {
-    env->LO = (int32_t)HILO;
-    env->HI = (int32_t)(HILO >> 32);
+    env->LO[0][env->current_tc] = (int32_t)HILO;
+    env->HI[0][env->current_tc] = (int32_t)(HILO >> 32);
 }
 
 void do_mult (void)
@@ -214,37 +212,39 @@
 }
 #endif
 
-#ifdef MIPS_HAS_MIPS64
-void do_dmult (void)
+#if HOST_LONG_BITS < 64
+void do_div (void)
 {
-    /* XXX */
-    set_HILO((int64_t)T0 * (int64_t)T1);
-}
-
-void do_dmultu (void)
-{
-    /* XXX */
-    set_HILO((uint64_t)T0 * (uint64_t)T1);
-}
-
-void do_ddiv (void)
-{
+    /* 64bit datatypes because we may see overflow/underflow. */
     if (T1 != 0) {
-        env->LO = (int64_t)T0 / (int64_t)T1;
-        env->HI = (int64_t)T0 % (int64_t)T1;
-    }
-}
-
-void do_ddivu (void)
-{
-    if (T1 != 0) {
-        env->LO = T0 / T1;
-        env->HI = T0 % T1;
+        env->LO[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
+        env->HI[0][env->current_tc] = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
     }
 }
 #endif
 
-#if defined(CONFIG_USER_ONLY) 
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+void do_ddiv (void)
+{
+    if (T1 != 0) {
+        lldiv_t res = lldiv((int64_t)T0, (int64_t)T1);
+        env->LO[0][env->current_tc] = res.quot;
+        env->HI[0][env->current_tc] = res.rem;
+    }
+}
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+void do_ddivu (void)
+{
+    if (T1 != 0) {
+        env->LO[0][env->current_tc] = T0 / T1;
+        env->HI[0][env->current_tc] = T0 % T1;
+    }
+}
+#endif
+#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
+
+#if defined(CONFIG_USER_ONLY)
 void do_mfc0_random (void)
 {
     cpu_abort(env, "mfc0 random\n");
@@ -265,6 +265,16 @@
     cpu_abort(env, "mtc0 compare\n");
 }
 
+void cpu_mips_start_count(CPUState *env)
+{
+    cpu_abort(env, "start count\n");
+}
+
+void cpu_mips_stop_count(CPUState *env)
+{
+    cpu_abort(env, "stop count\n");
+}
+
 void cpu_mips_update_irq(CPUState *env)
 {
     cpu_abort(env, "mtc0 status / mtc0 cause\n");
@@ -280,26 +290,6 @@
     cpu_abort(env, "mtc0 status irqraise debug\n");
 }
 
-void do_tlbwi (void)
-{
-    cpu_abort(env, "tlbwi\n");
-}
-
-void do_tlbwr (void)
-{
-    cpu_abort(env, "tlbwr\n");
-}
-
-void do_tlbp (void)
-{
-    cpu_abort(env, "tlbp\n");
-}
-
-void do_tlbr (void)
-{
-    cpu_abort(env, "tlbr\n");
-}
-
 void cpu_mips_tlb_flush (CPUState *env, int flush_global)
 {
     cpu_abort(env, "mips_tlb_flush\n");
@@ -320,10 +310,12 @@
 
 void do_mtc0_status_debug(uint32_t old, uint32_t val)
 {
-    const uint32_t mask = 0x0000FF00;
-    fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
-            old, val, env->CP0_Cause, old & mask, val & mask,
-            env->CP0_Cause & mask);
+    fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
+            old, old & env->CP0_Cause & CP0Ca_IP_mask,
+            val, val & env->CP0_Cause & CP0Ca_IP_mask,
+            env->CP0_Cause);
+    (env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile)
+                                  : fputs("\n", logfile);
 }
 
 void do_mtc0_status_irqraise_debug(void)
@@ -331,71 +323,69 @@
     fprintf(logfile, "Raise pending IRQs\n");
 }
 
-#ifdef MIPS_USES_FPU
-#include "softfloat.h"
-
 void fpu_handle_exception(void)
 {
 #ifdef CONFIG_SOFTFLOAT
-    int flags = get_float_exception_flags(&env->fp_status);
+    int flags = get_float_exception_flags(&env->fpu->fp_status);
     unsigned int cpuflags = 0, enable, cause = 0;
 
-    enable = GET_FP_ENABLE(env->fcr31);
+    enable = GET_FP_ENABLE(env->fpu->fcr31);
 
-    /* determine current flags */   
+    /* determine current flags */
     if (flags & float_flag_invalid) {
         cpuflags |= FP_INVALID;
         cause |= FP_INVALID & enable;
     }
     if (flags & float_flag_divbyzero) {
-        cpuflags |= FP_DIV0;    
+        cpuflags |= FP_DIV0;
         cause |= FP_DIV0 & enable;
     }
     if (flags & float_flag_overflow) {
-        cpuflags |= FP_OVERFLOW;    
+        cpuflags |= FP_OVERFLOW;
         cause |= FP_OVERFLOW & enable;
     }
     if (flags & float_flag_underflow) {
-        cpuflags |= FP_UNDERFLOW;   
+        cpuflags |= FP_UNDERFLOW;
         cause |= FP_UNDERFLOW & enable;
     }
     if (flags & float_flag_inexact) {
-        cpuflags |= FP_INEXACT; 
+        cpuflags |= FP_INEXACT;
         cause |= FP_INEXACT & enable;
     }
-    SET_FP_FLAGS(env->fcr31, cpuflags);
-    SET_FP_CAUSE(env->fcr31, cause);
+    SET_FP_FLAGS(env->fpu->fcr31, cpuflags);
+    SET_FP_CAUSE(env->fpu->fcr31, cause);
 #else
-    SET_FP_FLAGS(env->fcr31, 0);
-    SET_FP_CAUSE(env->fcr31, 0);
+    SET_FP_FLAGS(env->fpu->fcr31, 0);
+    SET_FP_CAUSE(env->fpu->fcr31, 0);
 #endif
 }
-#endif /* MIPS_USES_FPU */
 
 /* TLB management */
-#if defined(MIPS_USES_R4K_TLB)
 void cpu_mips_tlb_flush (CPUState *env, int flush_global)
 {
     /* Flush qemu's TLB and discard all shadowed entries.  */
     tlb_flush (env, flush_global);
-    env->tlb_in_use = MIPS_TLB_NB;
+    env->tlb->tlb_in_use = env->tlb->nb_tlb;
 }
 
-static void mips_tlb_flush_extra (CPUState *env, int first)
+static void r4k_mips_tlb_flush_extra (CPUState *env, int first)
 {
     /* Discard entries from env->tlb[first] onwards.  */
-    while (env->tlb_in_use > first) {
-        invalidate_tlb(env, --env->tlb_in_use, 0);
+    while (env->tlb->tlb_in_use > first) {
+        r4k_invalidate_tlb(env, --env->tlb->tlb_in_use, 0);
     }
 }
 
-static void fill_tlb (int idx)
+static void r4k_fill_tlb (int idx)
 {
-    tlb_t *tlb;
+    r4k_tlb_t *tlb;
 
     /* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
-    tlb = &env->tlb[idx];
-    tlb->VPN = env->CP0_EntryHi & (int32_t)0xFFFFE000;
+    tlb = &env->tlb->mmu.r4k.tlb[idx];
+    tlb->VPN = env->CP0_EntryHi & (TARGET_PAGE_MASK << 1);
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    tlb->VPN &= env->SEGMask;
+#endif
     tlb->ASID = env->CP0_EntryHi & 0xFF;
     tlb->PageMask = env->CP0_PageMask;
     tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
@@ -409,53 +399,59 @@
     tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
 }
 
-void do_tlbwi (void)
+void r4k_do_tlbwi (void)
 {
     /* Discard cached TLB entries.  We could avoid doing this if the
        tlbwi is just upgrading access permissions on the current entry;
        that might be a further win.  */
-    mips_tlb_flush_extra (env, MIPS_TLB_NB);
+    r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb);
 
-    /* Wildly undefined effects for CP0_Index containing a too high value and
-       MIPS_TLB_NB not being a power of two.  But so does real silicon.  */
-    invalidate_tlb(env, env->CP0_Index & (MIPS_TLB_NB - 1), 0);
-    fill_tlb(env->CP0_Index & (MIPS_TLB_NB - 1));
+    r4k_invalidate_tlb(env, env->CP0_Index % env->tlb->nb_tlb, 0);
+    r4k_fill_tlb(env->CP0_Index % env->tlb->nb_tlb);
 }
 
-void do_tlbwr (void)
+void r4k_do_tlbwr (void)
 {
     int r = cpu_mips_get_random(env);
 
-    invalidate_tlb(env, r, 1);
-    fill_tlb(r);
+    r4k_invalidate_tlb(env, r, 1);
+    r4k_fill_tlb(r);
 }
 
-void do_tlbp (void)
+void r4k_do_tlbp (void)
 {
-    tlb_t *tlb;
+    r4k_tlb_t *tlb;
+    target_ulong mask;
     target_ulong tag;
+    target_ulong VPN;
     uint8_t ASID;
     int i;
 
-    tag = env->CP0_EntryHi & (int32_t)0xFFFFE000;
     ASID = env->CP0_EntryHi & 0xFF;
-    for (i = 0; i < MIPS_TLB_NB; i++) {
-        tlb = &env->tlb[i];
+    for (i = 0; i < env->tlb->nb_tlb; i++) {
+        tlb = &env->tlb->mmu.r4k.tlb[i];
+        /* 1k pages are not supported. */
+        mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+        tag = env->CP0_EntryHi & ~mask;
+        VPN = tlb->VPN & ~mask;
         /* Check ASID, virtual page number & size */
-        if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
+        if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
             /* TLB match */
             env->CP0_Index = i;
             break;
         }
     }
-    if (i == MIPS_TLB_NB) {
+    if (i == env->tlb->nb_tlb) {
         /* No match.  Discard any shadow entries, if any of them match.  */
-        for (i = MIPS_TLB_NB; i < env->tlb_in_use; i++) {
-	    tlb = &env->tlb[i];
-
+        for (i = env->tlb->nb_tlb; i < env->tlb->tlb_in_use; i++) {
+	    tlb = &env->tlb->mmu.r4k.tlb[i];
+	    /* 1k pages are not supported. */
+	    mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
+	    tag = env->CP0_EntryHi & ~mask;
+	    VPN = tlb->VPN & ~mask;
 	    /* Check ASID, virtual page number & size */
-	    if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
-                mips_tlb_flush_extra (env, i);
+	    if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
+                r4k_mips_tlb_flush_extra (env, i);
 	        break;
 	    }
 	}
@@ -464,19 +460,19 @@
     }
 }
 
-void do_tlbr (void)
+void r4k_do_tlbr (void)
 {
-    tlb_t *tlb;
+    r4k_tlb_t *tlb;
     uint8_t ASID;
 
     ASID = env->CP0_EntryHi & 0xFF;
-    tlb = &env->tlb[env->CP0_Index & (MIPS_TLB_NB - 1)];
+    tlb = &env->tlb->mmu.r4k.tlb[env->CP0_Index % env->tlb->nb_tlb];
 
     /* If this will change the current ASID, flush qemu's TLB.  */
     if (ASID != tlb->ASID)
         cpu_mips_tlb_flush (env, 1);
 
-    mips_tlb_flush_extra(env, MIPS_TLB_NB);
+    r4k_mips_tlb_flush_extra(env, env->tlb->nb_tlb);
 
     env->CP0_EntryHi = tlb->VPN | tlb->ASID;
     env->CP0_PageMask = tlb->PageMask;
@@ -485,31 +481,46 @@
     env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
                         (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
 }
-#endif
 
 #endif /* !CONFIG_USER_ONLY */
 
 void dump_ldst (const unsigned char *func)
 {
     if (loglevel)
-        fprintf(logfile, "%s => " TLSZ " " TLSZ "\n", __func__, T0, T1);
+        fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1);
 }
 
 void dump_sc (void)
 {
     if (loglevel) {
-        fprintf(logfile, "%s " TLSZ " at " TLSZ " (" TLSZ ")\n", __func__,
+        fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__,
                 T1, T0, env->CP0_LLAddr);
     }
 }
 
-void debug_eret (void)
+void debug_pre_eret (void)
 {
-    if (loglevel) {
-        fprintf(logfile, "ERET: pc " TLSZ " EPC " TLSZ " ErrorEPC " TLSZ " (%d)\n",
-                env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
-                env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
-    }
+    fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
+            env->PC[env->current_tc], env->CP0_EPC);
+    if (env->CP0_Status & (1 << CP0St_ERL))
+        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
+    if (env->hflags & MIPS_HFLAG_DM)
+        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
+    fputs("\n", logfile);
+}
+
+void debug_post_eret (void)
+{
+    fprintf(logfile, "  =>  PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
+            env->PC[env->current_tc], env->CP0_EPC);
+    if (env->CP0_Status & (1 << CP0St_ERL))
+        fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
+    if (env->hflags & MIPS_HFLAG_DM)
+        fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
+    if (env->hflags & MIPS_HFLAG_UM)
+        fputs(", UM\n", logfile);
+    else
+        fputs("\n", logfile);
 }
 
 void do_pmon (int function)
@@ -517,28 +528,28 @@
     function /= 2;
     switch (function) {
     case 2: /* TODO: char inbyte(int waitflag); */
-        if (env->gpr[4] == 0)
-            env->gpr[2] = -1;
+        if (env->gpr[4][env->current_tc] == 0)
+            env->gpr[2][env->current_tc] = -1;
         /* Fall through */
     case 11: /* TODO: char inbyte (void); */
-        env->gpr[2] = -1;
+        env->gpr[2][env->current_tc] = -1;
         break;
     case 3:
     case 12:
-        printf("%c", (char)(env->gpr[4] & 0xFF));
+        printf("%c", (char)(env->gpr[4][env->current_tc] & 0xFF));
         break;
     case 17:
         break;
     case 158:
         {
-            unsigned char *fmt = (void *)(unsigned long)env->gpr[4];
+            unsigned char *fmt = (void *)(unsigned long)env->gpr[4][env->current_tc];
             printf("%s", fmt);
         }
         break;
     }
 }
 
-#if !defined(CONFIG_USER_ONLY) 
+#if !defined(CONFIG_USER_ONLY)
 
 static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr);
 
@@ -593,3 +604,718 @@
 }
 
 #endif
+
+/* Complex FPU operations which may need stack space. */
+
+#define FLOAT_SIGN32 (1 << 31)
+#define FLOAT_SIGN64 (1ULL << 63)
+#define FLOAT_ONE32 (0x3f8 << 20)
+#define FLOAT_ONE64 (0x3ffULL << 52)
+#define FLOAT_TWO32 (1 << 30)
+#define FLOAT_TWO64 (1ULL << 62)
+#define FLOAT_QNAN32 0x7fbfffff
+#define FLOAT_QNAN64 0x7ff7ffffffffffffULL
+#define FLOAT_SNAN32 0x7fffffff
+#define FLOAT_SNAN64 0x7fffffffffffffffULL
+
+/* 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->fpu->fcr31 & 3], &env->fpu->fp_status)
+
+void do_cfc1 (int reg)
+{
+    switch (reg) {
+    case 0:
+        T0 = (int32_t)env->fpu->fcr0;
+        break;
+    case 25:
+        T0 = ((env->fpu->fcr31 >> 24) & 0xfe) | ((env->fpu->fcr31 >> 23) & 0x1);
+        break;
+    case 26:
+        T0 = env->fpu->fcr31 & 0x0003f07c;
+        break;
+    case 28:
+        T0 = (env->fpu->fcr31 & 0x00000f83) | ((env->fpu->fcr31 >> 22) & 0x4);
+        break;
+    default:
+        T0 = (int32_t)env->fpu->fcr31;
+        break;
+    }
+}
+
+void do_ctc1 (int reg)
+{
+    switch(reg) {
+    case 25:
+        if (T0 & 0xffffff00)
+            return;
+        env->fpu->fcr31 = (env->fpu->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
+                     ((T0 & 0x1) << 23);
+        break;
+    case 26:
+        if (T0 & 0x007c0000)
+            return;
+        env->fpu->fcr31 = (env->fpu->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
+        break;
+    case 28:
+        if (T0 & 0x007c0000)
+            return;
+        env->fpu->fcr31 = (env->fpu->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
+                     ((T0 & 0x4) << 22);
+        break;
+    case 31:
+        if (T0 & 0x007c0000)
+            return;
+        env->fpu->fcr31 = T0;
+        break;
+    default:
+        return;
+    }
+    /* set rounding mode */
+    RESTORE_ROUNDING_MODE;
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    if ((GET_FP_ENABLE(env->fpu->fcr31) | 0x20) & GET_FP_CAUSE(env->fpu->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->fpu->fp_status));
+
+    SET_FP_CAUSE(env->fpu->fcr31, tmp);
+    if (GET_FP_ENABLE(env->fpu->fcr31) & tmp)
+        do_raise_exception(EXCP_FPE);
+    else
+        UPDATE_FP_FLAGS(env->fpu->fcr31, tmp);
+}
+
+#define FLOAT_OP(name, p) void do_float_##name##_##p(void)
+
+FLOAT_OP(cvtd, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float32_to_float64(FST0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvtd, w)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = int32_to_float64(WT0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvtd, l)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = int64_to_float64(DT0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvtl, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(cvtl, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+
+FLOAT_OP(cvtps, pw)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
+    FSTH2 = int32_to_float32(WTH0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvtpw, ps)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+    WTH2 = float32_to_int32(FSTH0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+FLOAT_OP(cvts, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float64_to_float32(FDT0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvts, w)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = int32_to_float32(WT0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvts, l)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = int64_to_float32(DT0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(cvts, pl)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    WT2 = WT0;
+    update_fcr31();
+}
+FLOAT_OP(cvts, pu)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    WT2 = WTH0;
+    update_fcr31();
+}
+FLOAT_OP(cvtw, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+FLOAT_OP(cvtw, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+
+FLOAT_OP(roundl, d)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(roundl, s)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(roundw, d)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+FLOAT_OP(roundw, s)
+{
+    set_float_rounding_mode(float_round_nearest_even, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+
+FLOAT_OP(truncl, d)
+{
+    DT2 = float64_to_int64_round_to_zero(FDT0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(truncl, s)
+{
+    DT2 = float32_to_int64_round_to_zero(FST0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(truncw, d)
+{
+    WT2 = float64_to_int32_round_to_zero(FDT0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+FLOAT_OP(truncw, s)
+{
+    WT2 = float32_to_int32_round_to_zero(FST0, &env->fpu->fp_status);
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+
+FLOAT_OP(ceill, d)
+{
+    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(ceill, s)
+{
+    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(ceilw, d)
+{
+    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+FLOAT_OP(ceilw, s)
+{
+    set_float_rounding_mode(float_round_up, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+
+FLOAT_OP(floorl, d)
+{
+    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
+    DT2 = float64_to_int64(FDT0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(floorl, s)
+{
+    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
+    DT2 = float32_to_int64(FST0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        DT2 = FLOAT_SNAN64;
+}
+FLOAT_OP(floorw, d)
+{
+    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
+    WT2 = float64_to_int32(FDT0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+FLOAT_OP(floorw, s)
+{
+    set_float_rounding_mode(float_round_down, &env->fpu->fp_status);
+    WT2 = float32_to_int32(FST0, &env->fpu->fp_status);
+    RESTORE_ROUNDING_MODE;
+    update_fcr31();
+    if (GET_FP_CAUSE(env->fpu->fcr31) & (FP_OVERFLOW | FP_INVALID))
+        WT2 = FLOAT_SNAN32;
+}
+
+/* MIPS specific unary operations */
+FLOAT_OP(recip, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(recip, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
+    update_fcr31();
+}
+
+FLOAT_OP(rsqrt, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(rsqrt, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
+    update_fcr31();
+}
+
+FLOAT_OP(recip1, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(recip1, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(recip1, ps)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST0, &env->fpu->fp_status);
+    FSTH2 = float32_div(FLOAT_ONE32, FSTH0, &env->fpu->fp_status);
+    update_fcr31();
+}
+
+FLOAT_OP(rsqrt1, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_sqrt(FDT0, &env->fpu->fp_status);
+    FDT2 = float64_div(FLOAT_ONE64, FDT2, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(rsqrt1, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
+    update_fcr31();
+}
+FLOAT_OP(rsqrt1, ps)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_sqrt(FST0, &env->fpu->fp_status);
+    FSTH2 = float32_sqrt(FSTH0, &env->fpu->fp_status);
+    FST2 = float32_div(FLOAT_ONE32, FST2, &env->fpu->fp_status);
+    FSTH2 = float32_div(FLOAT_ONE32, FSTH2, &env->fpu->fp_status);
+    update_fcr31();
+}
+
+/* binary operations */
+#define FLOAT_BINOP(name) \
+FLOAT_OP(name, d)         \
+{                         \
+    set_float_exception_flags(0, &env->fpu->fp_status);            \
+    FDT2 = float64_ ## name (FDT0, FDT1, &env->fpu->fp_status);    \
+    update_fcr31();                                                \
+    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
+        FDT2 = FLOAT_QNAN64;                                       \
+}                         \
+FLOAT_OP(name, s)         \
+{                         \
+    set_float_exception_flags(0, &env->fpu->fp_status);            \
+    FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
+    update_fcr31();                                                \
+    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID)                \
+        FST2 = FLOAT_QNAN32;                                       \
+}                         \
+FLOAT_OP(name, ps)        \
+{                         \
+    set_float_exception_flags(0, &env->fpu->fp_status);            \
+    FST2 = float32_ ## name (FST0, FST1, &env->fpu->fp_status);    \
+    FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fpu->fp_status); \
+    update_fcr31();       \
+    if (GET_FP_CAUSE(env->fpu->fcr31) & FP_INVALID) {              \
+        FST2 = FLOAT_QNAN32;                                       \
+        FSTH2 = FLOAT_QNAN32;                                      \
+    }                     \
+}
+FLOAT_BINOP(add)
+FLOAT_BINOP(sub)
+FLOAT_BINOP(mul)
+FLOAT_BINOP(div)
+#undef FLOAT_BINOP
+
+/* MIPS specific binary operations */
+FLOAT_OP(recip2, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
+    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status) ^ FLOAT_SIGN64;
+    update_fcr31();
+}
+FLOAT_OP(recip2, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
+    update_fcr31();
+}
+FLOAT_OP(recip2, ps)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
+    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
+    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
+    update_fcr31();
+}
+
+FLOAT_OP(rsqrt2, d)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FDT2 = float64_mul(FDT0, FDT2, &env->fpu->fp_status);
+    FDT2 = float64_sub(FDT2, FLOAT_ONE64, &env->fpu->fp_status);
+    FDT2 = float64_div(FDT2, FLOAT_TWO64, &env->fpu->fp_status) ^ FLOAT_SIGN64;
+    update_fcr31();
+}
+FLOAT_OP(rsqrt2, s)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
+    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
+    update_fcr31();
+}
+FLOAT_OP(rsqrt2, ps)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul(FST0, FST2, &env->fpu->fp_status);
+    FSTH2 = float32_mul(FSTH0, FSTH2, &env->fpu->fp_status);
+    FST2 = float32_sub(FST2, FLOAT_ONE32, &env->fpu->fp_status);
+    FSTH2 = float32_sub(FSTH2, FLOAT_ONE32, &env->fpu->fp_status);
+    FST2 = float32_div(FST2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
+    FSTH2 = float32_div(FSTH2, FLOAT_TWO32, &env->fpu->fp_status) ^ FLOAT_SIGN32;
+    update_fcr31();
+}
+
+FLOAT_OP(addr, ps)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_add (FST0, FSTH0, &env->fpu->fp_status);
+    FSTH2 = float32_add (FST1, FSTH1, &env->fpu->fp_status);
+    update_fcr31();
+}
+
+FLOAT_OP(mulr, ps)
+{
+    set_float_exception_flags(0, &env->fpu->fp_status);
+    FST2 = float32_mul (FST0, FSTH0, &env->fpu->fp_status);
+    FSTH2 = float32_mul (FST1, FSTH1, &env->fpu->fp_status);
+    update_fcr31();
+}
+
+/* compare operations */
+#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->fpu);             \
+    else                                       \
+        CLEAR_FP_COND(cc, env->fpu);           \
+}                                              \
+void do_cmpabs_d_ ## op (long cc)              \
+{                                              \
+    int c;                                     \
+    FDT0 &= ~FLOAT_SIGN64;                     \
+    FDT1 &= ~FLOAT_SIGN64;                     \
+    c = cond;                                  \
+    update_fcr31();                            \
+    if (c)                                     \
+        SET_FP_COND(cc, env->fpu);             \
+    else                                       \
+        CLEAR_FP_COND(cc, env->fpu);           \
+}
+
+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->fpu->fp_status), 0))
+FOP_COND_D(un,  float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status))
+FOP_COND_D(eq,  !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->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->fpu->fp_status), 0))
+FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status))
+FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_eq(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_eq(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(lt,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_lt(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_lt(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(le,  !float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status) && float64_le(FDT0, FDT1, &env->fpu->fp_status))
+FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fpu->fp_status)  || float64_le(FDT0, FDT1, &env->fpu->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->fpu);             \
+    else                                       \
+        CLEAR_FP_COND(cc, env->fpu);           \
+}                                              \
+void do_cmpabs_s_ ## op (long cc)              \
+{                                              \
+    int c;                                     \
+    FST0 &= ~FLOAT_SIGN32;                     \
+    FST1 &= ~FLOAT_SIGN32;                     \
+    c = cond;                                  \
+    update_fcr31();                            \
+    if (c)                                     \
+        SET_FP_COND(cc, env->fpu);             \
+    else                                       \
+        CLEAR_FP_COND(cc, env->fpu);           \
+}
+
+flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
+{
+    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->fpu->fp_status), 0))
+FOP_COND_S(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status))
+FOP_COND_S(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_eq(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_lt(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)  || float32_le(FST0, FST1, &env->fpu->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->fpu->fp_status), 0))
+FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status))
+FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_eq(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_eq(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_lt(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_lt(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status) && float32_le(FST0, FST1, &env->fpu->fp_status))
+FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)  || float32_le(FST0, FST1, &env->fpu->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->fpu);             \
+    else                                       \
+        CLEAR_FP_COND(cc, env->fpu);           \
+    if (ch)                                    \
+        SET_FP_COND(cc + 1, env->fpu);         \
+    else                                       \
+        CLEAR_FP_COND(cc + 1, env->fpu);       \
+}                                              \
+void do_cmpabs_ps_ ## op (long cc)             \
+{                                              \
+    int cl, ch;                                \
+    FST0 &= ~FLOAT_SIGN32;                     \
+    FSTH0 &= ~FLOAT_SIGN32;                    \
+    FST1 &= ~FLOAT_SIGN32;                     \
+    FSTH1 &= ~FLOAT_SIGN32;                    \
+    cl = condl;                                \
+    ch = condh;                                \
+    update_fcr31();                            \
+    if (cl)                                    \
+        SET_FP_COND(cc, env->fpu);             \
+    else                                       \
+        CLEAR_FP_COND(cc, env->fpu);           \
+    if (ch)                                    \
+        SET_FP_COND(cc + 1, env->fpu);         \
+    else                                       \
+        CLEAR_FP_COND(cc + 1, env->fpu);       \
+}
+
+/* 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->fpu->fp_status), 0),
+                 (float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status), 0))
+FOP_COND_PS(un,  float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status))
+FOP_COND_PS(eq,  !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(0, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->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->fpu->fp_status), 0),
+                 (float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status), 0))
+FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status))
+FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_eq(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_eq(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_eq(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(lt,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_lt(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_lt(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_lt(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(le,  !float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)   && float32_le(FST0, FST1, &env->fpu->fp_status),
+                 !float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status) && float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
+FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fpu->fp_status)    || float32_le(FST0, FST1, &env->fpu->fp_status),
+                 float32_is_unordered(1, FSTH1, FSTH0, &env->fpu->fp_status)  || float32_le(FSTH0, FSTH1, &env->fpu->fp_status))
diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c
index 6af78ce..700fc17 100644
--- a/target-mips/op_helper_mem.c
+++ b/target-mips/op_helper_mem.c
@@ -28,7 +28,7 @@
     }
 #if defined (DEBUG_OP)
     if (logfile) {
-        fprintf(logfile, "%s: " TLSZ " - %08x " TLSZ " => " TLSZ "\n",
+        fprintf(logfile, "%s: " TARGET_FMT_lx " - %08x " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
                 __func__, sav, tmp, T1, T0);
     }
 #endif
@@ -57,7 +57,7 @@
     }
 #if defined (DEBUG_OP)
     if (logfile) {
-        fprintf(logfile, "%s: " TLSZ " - %08x " TLSZ " => " TLSZ "\n",
+        fprintf(logfile, "%s: " TARGET_FMT_lx " - %08x " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
                 __func__, sav, tmp, T1, T0);
     }
 #endif
@@ -86,7 +86,7 @@
     }
 #if defined (DEBUG_OP)
     if (logfile) {
-        fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => %08x\n",
+        fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => %08x\n",
                 __func__, T0, sav, T1, tmp);
     }
 #endif
@@ -116,7 +116,7 @@
     }
 #if defined (DEBUG_OP)
     if (logfile) {
-        fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => %08x\n",
+        fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => %08x\n",
                 __func__, T0, sav, T1, tmp);
     }
 #endif
@@ -124,12 +124,12 @@
     return tmp;
 }
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 
-# ifdef TARGET_WORDS_BIGENDIAN
-#define GET_LMASK64(v) ((v) & 4)
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK64(v) ((v) & 7)
 #else
-#define GET_LMASK64(v) (((v) & 4) ^ 4)
+#define GET_LMASK64(v) (((v) & 7) ^ 7)
 #endif
 
 void glue(do_ldl, MEMSUFFIX) (uint64_t tmp)
@@ -166,7 +166,7 @@
     }
 #if defined (DEBUG_OP)
     if (logfile) {
-        fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n",
+        fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
                 __func__, sav, tmp, T1, T0);
     }
 #endif
@@ -207,7 +207,7 @@
     }
 #if defined (DEBUG_OP)
     if (logfile) {
-        fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n",
+        fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
                 __func__, sav, tmp, T1, T0);
     }
 #endif
@@ -248,7 +248,7 @@
     }
 #if defined (DEBUG_OP)
     if (logfile) {
-        fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n",
+        fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
                 __func__, T0, sav, T1, tmp);
     }
 #endif
@@ -290,7 +290,7 @@
     }
 #if defined (DEBUG_OP)
     if (logfile) {
-        fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n",
+        fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
                 __func__, T0, sav, T1, tmp);
     }
 #endif
@@ -298,4 +298,4 @@
     return tmp;
 }
 
-#endif /* MIPS_HAS_MIPS64 */
+#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c
index a328979..a15ad5a 100644
--- a/target-mips/op_mem.c
+++ b/target-mips/op_mem.c
@@ -1,6 +1,6 @@
 /*
  *  MIPS emulation memory micro-operations for qemu.
- * 
+ *
  *  Copyright (c) 2004-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
@@ -63,7 +63,7 @@
 
 void glue(op_lwu, MEMSUFFIX) (void)
 {
-    T0 = glue(ldl, MEMSUFFIX)(T0);
+    T0 = (uint32_t)glue(ldl, MEMSUFFIX)(T0);
     RETURN();
 }
 
@@ -117,6 +117,10 @@
 void glue(op_sc, MEMSUFFIX) (void)
 {
     CALL_FROM_TB0(dump_sc);
+    if (T0 & 0x3) {
+        env->CP0_BadVAddr = T0;
+        CALL_FROM_TB1(do_raise_exception, EXCP_AdES);
+    }
     if (T0 == env->CP0_LLAddr) {
         glue(stl, MEMSUFFIX)(T0, T1);
         T0 = 1;
@@ -126,7 +130,7 @@
     RETURN();
 }
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 void glue(op_ld, MEMSUFFIX) (void)
 {
     T0 = glue(ldq, MEMSUFFIX)(T0);
@@ -182,6 +186,10 @@
 void glue(op_scd, MEMSUFFIX) (void)
 {
     CALL_FROM_TB0(dump_sc);
+    if (T0 & 0x7) {
+        env->CP0_BadVAddr = T0;
+        CALL_FROM_TB1(do_raise_exception, EXCP_AdES);
+    }
     if (T0 == env->CP0_LLAddr) {
         glue(stq, MEMSUFFIX)(T0, T1);
         T0 = 1;
@@ -190,9 +198,8 @@
     }
     RETURN();
 }
-#endif /* MIPS_HAS_MIPS64 */
+#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
 
-#ifdef MIPS_USES_FPU
 void glue(op_lwc1, MEMSUFFIX) (void)
 {
     WT0 = glue(ldl, MEMSUFFIX)(T0);
@@ -213,4 +220,13 @@
     glue(stq, MEMSUFFIX)(T0, DT0);
     RETURN();
 }
-#endif
+void glue(op_luxc1, MEMSUFFIX) (void)
+{
+    DT0 = glue(ldq, MEMSUFFIX)(T0 & ~0x7);
+    RETURN();
+}
+void glue(op_suxc1, MEMSUFFIX) (void)
+{
+    glue(stq, MEMSUFFIX)(T0 & ~0x7, DT0);
+    RETURN();
+}
diff --git a/target-mips/op_template.c b/target-mips/op_template.c
index 8d4c4e4..148656e 100644
--- a/target-mips/op_template.c
+++ b/target-mips/op_template.c
@@ -1,6 +1,6 @@
 /*
  *  MIPS emulation micro-operations templates for reg load & store for qemu.
- * 
+ *
  *  Copyright (c) 2004-2005 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
@@ -21,31 +21,44 @@
 #if defined(REG)
 void glue(op_load_gpr_T0_gpr, REG) (void)
 {
-    T0 = env->gpr[REG];
+    T0 = env->gpr[REG][env->current_tc];
     RETURN();
 }
 
 void glue(op_store_T0_gpr_gpr, REG) (void)
 {
-    env->gpr[REG] = T0;
+    env->gpr[REG][env->current_tc] = T0;
     RETURN();
 }
 
 void glue(op_load_gpr_T1_gpr, REG) (void)
 {
-    T1 = env->gpr[REG];
+    T1 = env->gpr[REG][env->current_tc];
     RETURN();
 }
 
 void glue(op_store_T1_gpr_gpr, REG) (void)
 {
-    env->gpr[REG] = T1;
+    env->gpr[REG][env->current_tc] = T1;
     RETURN();
 }
 
 void glue(op_load_gpr_T2_gpr, REG) (void)
 {
-    T2 = env->gpr[REG];
+    T2 = env->gpr[REG][env->current_tc];
+    RETURN();
+}
+
+
+void glue(op_load_srsgpr_T0_gpr, REG) (void)
+{
+    T0 = env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf];
+    RETURN();
+}
+
+void glue(op_store_T0_srsgpr_gpr, REG) (void)
+{
+    env->gpr[REG][(env->CP0_SRSCtl >> CP0SRSCtl_PSS) & 0xf] = T0;
     RETURN();
 }
 #endif
@@ -54,7 +67,7 @@
 #define SET_RESET(treg, tregname)        \
     void glue(op_set, tregname)(void)    \
     {                                    \
-        treg = PARAM1;                   \
+        treg = (int32_t)PARAM1;          \
         RETURN();                        \
     }                                    \
     void glue(op_reset, tregname)(void)  \
@@ -68,4 +81,20 @@
 SET_RESET(T2, _T2)
 
 #undef SET_RESET
+
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+#define SET64(treg, tregname)                               \
+    void glue(op_set64, tregname)(void)                     \
+    {                                                       \
+        treg = ((uint64_t)PARAM1 << 32) | (uint32_t)PARAM2; \
+        RETURN();                                           \
+    }
+
+SET64(T0, _T0)
+SET64(T1, _T1)
+SET64(T2, _T2)
+
+#undef SET64
+
+#endif
 #endif
diff --git a/target-mips/translate.c b/target-mips/translate.c
index ce56bb0..d3f80f2 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1,6 +1,6 @@
 /*
  *  MIPS32 emulation for qemu: main translation routines.
- * 
+ *
  *  Copyright (c) 2004-2005 Jocelyn Mayer
  *  Copyright (c) 2006 Marius Groeger (FPU operations)
  *  Copyright (c) 2006 Thiemo Seufer (MIPS32R2 support)
@@ -142,7 +142,7 @@
     OPC_SRL      = 0x02 | OPC_SPECIAL, /* also ROTR */
     OPC_SRA      = 0x03 | OPC_SPECIAL,
     OPC_SLLV     = 0x04 | OPC_SPECIAL,
-    OPC_SRLV     = 0x06 | OPC_SPECIAL,
+    OPC_SRLV     = 0x06 | OPC_SPECIAL, /* also ROTRV */
     OPC_SRAV     = 0x07 | OPC_SPECIAL,
     OPC_DSLLV    = 0x14 | OPC_SPECIAL,
     OPC_DSRLV    = 0x16 | OPC_SPECIAL, /* also DROTRV */
@@ -266,6 +266,8 @@
     OPC_DINSM    = 0x05 | OPC_SPECIAL3,
     OPC_DINSU    = 0x06 | OPC_SPECIAL3,
     OPC_DINS     = 0x07 | OPC_SPECIAL3,
+    OPC_FORK     = 0x08 | OPC_SPECIAL3,
+    OPC_YIELD    = 0x09 | OPC_SPECIAL3,
     OPC_BSHFL    = 0x20 | OPC_SPECIAL3,
     OPC_DBSHFL   = 0x24 | OPC_SPECIAL3,
     OPC_RDHWR    = 0x3B | OPC_SPECIAL3,
@@ -296,8 +298,10 @@
     OPC_DMFC0    = (0x01 << 21) | OPC_CP0,
     OPC_MTC0     = (0x04 << 21) | OPC_CP0,
     OPC_DMTC0    = (0x05 << 21) | OPC_CP0,
+    OPC_MFTR     = (0x08 << 21) | OPC_CP0,
     OPC_RDPGPR   = (0x0A << 21) | OPC_CP0,
     OPC_MFMC0    = (0x0B << 21) | OPC_CP0,
+    OPC_MTTR     = (0x0C << 21) | OPC_CP0,
     OPC_WRPGPR   = (0x0E << 21) | OPC_CP0,
     OPC_C0       = (0x10 << 21) | OPC_CP0,
     OPC_C0_FIRST = (0x10 << 21) | OPC_CP0,
@@ -305,9 +309,13 @@
 };
 
 /* MFMC0 opcodes */
-#define MASK_MFMC0(op)     MASK_CP0(op) | (op & ((0x0C << 11) | (1 << 5)))
+#define MASK_MFMC0(op)     MASK_CP0(op) | (op & 0xFFFF)
 
 enum {
+    OPC_DMT      = 0x01 | (0 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0,
+    OPC_EMT      = 0x01 | (1 << 5) | (0x0F << 6) | (0x01 << 11) | OPC_MFMC0,
+    OPC_DVPE     = 0x01 | (0 << 5) | OPC_MFMC0,
+    OPC_EVPE     = 0x01 | (1 << 5) | OPC_MFMC0,
     OPC_DI       = (0 << 5) | (0x0C << 11) | OPC_MFMC0,
     OPC_EI       = (1 << 5) | (0x0C << 11) | OPC_MFMC0,
 };
@@ -333,20 +341,26 @@
     OPC_MFC1     = (0x00 << 21) | OPC_CP1,
     OPC_DMFC1    = (0x01 << 21) | OPC_CP1,
     OPC_CFC1     = (0x02 << 21) | OPC_CP1,
-    OPC_MFHCI    = (0x03 << 21) | OPC_CP1,
+    OPC_MFHC1    = (0x03 << 21) | OPC_CP1,
     OPC_MTC1     = (0x04 << 21) | OPC_CP1,
     OPC_DMTC1    = (0x05 << 21) | OPC_CP1,
     OPC_CTC1     = (0x06 << 21) | OPC_CP1,
-    OPC_MTHCI    = (0x07 << 21) | OPC_CP1,
+    OPC_MTHC1    = (0x07 << 21) | OPC_CP1,
     OPC_BC1      = (0x08 << 21) | OPC_CP1, /* bc */
+    OPC_BC1ANY2  = (0x09 << 21) | OPC_CP1,
+    OPC_BC1ANY4  = (0x0A << 21) | OPC_CP1,
     OPC_S_FMT    = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */
     OPC_D_FMT    = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */
     OPC_E_FMT    = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */
     OPC_Q_FMT    = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */
     OPC_W_FMT    = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */
     OPC_L_FMT    = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */
+    OPC_PS_FMT   = (0x16 << 21) | OPC_CP1, /* 22: fmt=paired single fp */
 };
 
+#define MASK_CP1_FUNC(op)       MASK_CP1(op) | (op & 0x3F)
+#define MASK_BC1(op)            MASK_CP1(op) | (op & (0x3 << 16))
+
 enum {
     OPC_BC1F     = (0x00 << 16) | OPC_BC1,
     OPC_BC1T     = (0x01 << 16) | OPC_BC1,
@@ -354,11 +368,55 @@
     OPC_BC1TL    = (0x03 << 16) | OPC_BC1,
 };
 
-#define MASK_CP1_BCOND(op)      MASK_CP1(op) | (op & (0x3 << 16))
-#define MASK_CP1_FUNC(op)       MASK_CP1(op) | (op & 0x3F)
+enum {
+    OPC_BC1FANY2     = (0x00 << 16) | OPC_BC1ANY2,
+    OPC_BC1TANY2     = (0x01 << 16) | OPC_BC1ANY2,
+};
+
+enum {
+    OPC_BC1FANY4     = (0x00 << 16) | OPC_BC1ANY4,
+    OPC_BC1TANY4     = (0x01 << 16) | OPC_BC1ANY4,
+};
 
 #define MASK_CP2(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
-#define MASK_CP3(op)       MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+
+enum {
+    OPC_MFC2    = (0x00 << 21) | OPC_CP2,
+    OPC_DMFC2   = (0x01 << 21) | OPC_CP2,
+    OPC_CFC2    = (0x02 << 21) | OPC_CP2,
+    OPC_MFHC2   = (0x03 << 21) | OPC_CP2,
+    OPC_MTC2    = (0x04 << 21) | OPC_CP2,
+    OPC_DMTC2   = (0x05 << 21) | OPC_CP2,
+    OPC_CTC2    = (0x06 << 21) | OPC_CP2,
+    OPC_MTHC2   = (0x07 << 21) | OPC_CP2,
+    OPC_BC2     = (0x08 << 21) | OPC_CP2,
+};
+
+#define MASK_CP3(op)       MASK_OP_MAJOR(op) | (op & 0x3F)
+
+enum {
+    OPC_LWXC1   = 0x00 | OPC_CP3,
+    OPC_LDXC1   = 0x01 | OPC_CP3,
+    OPC_LUXC1   = 0x05 | OPC_CP3,
+    OPC_SWXC1   = 0x08 | OPC_CP3,
+    OPC_SDXC1   = 0x09 | OPC_CP3,
+    OPC_SUXC1   = 0x0D | OPC_CP3,
+    OPC_PREFX   = 0x0F | OPC_CP3,
+    OPC_ALNV_PS = 0x1E | OPC_CP3,
+    OPC_MADD_S  = 0x20 | OPC_CP3,
+    OPC_MADD_D  = 0x21 | OPC_CP3,
+    OPC_MADD_PS = 0x26 | OPC_CP3,
+    OPC_MSUB_S  = 0x28 | OPC_CP3,
+    OPC_MSUB_D  = 0x29 | OPC_CP3,
+    OPC_MSUB_PS = 0x2E | OPC_CP3,
+    OPC_NMADD_S = 0x30 | OPC_CP3,
+    OPC_NMADD_D = 0x31 | OPC_CP3,
+    OPC_NMADD_PS= 0x36 | OPC_CP3,
+    OPC_NMSUB_S = 0x38 | OPC_CP3,
+    OPC_NMSUB_D = 0x39 | OPC_CP3,
+    OPC_NMSUB_PS= 0x3E | OPC_CP3,
+};
+
 
 const unsigned char *regnames[] =
     { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
@@ -367,20 +425,20 @@
       "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
 
 /* Warning: no function for r0 register (hard wired to zero) */
-#define GEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [32] = {                                     \
-NULL,       NAME ## 1, NAME ## 2, NAME ## 3,                                  \
-NAME ## 4,  NAME ## 5, NAME ## 6, NAME ## 7,                                  \
-NAME ## 8,  NAME ## 9, NAME ## 10, NAME ## 11,                                \
-NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
-NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
-NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
-NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
-NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
-};                                                                            \
-static inline void func(int n)                                                \
-{                                                                             \
-    NAME ## _table[n]();                                                      \
+#define GEN32(func, NAME)                        \
+static GenOpFunc *NAME ## _table [32] = {        \
+NULL,       NAME ## 1, NAME ## 2, NAME ## 3,     \
+NAME ## 4,  NAME ## 5, NAME ## 6, NAME ## 7,     \
+NAME ## 8,  NAME ## 9, NAME ## 10, NAME ## 11,   \
+NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,  \
+NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,  \
+NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,  \
+NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,  \
+NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,  \
+};                                               \
+static inline void func(int n)                   \
+{                                                \
+    NAME ## _table[n]();                         \
 }
 
 /* General purpose registers moves */
@@ -391,7 +449,9 @@
 GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
 GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
 
-#ifdef MIPS_USES_FPU
+/* Moves to/from shadow registers */
+GEN32(gen_op_load_srsgpr_T0, gen_op_load_srsgpr_T0_gpr);
+GEN32(gen_op_store_T0_srsgpr, gen_op_store_T0_srsgpr_gpr);
 
 static const char *fregnames[] =
     { "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
@@ -399,93 +459,88 @@
       "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
       "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", };
 
-# define SFGEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [32] = {                                     \
-NAME ## 0,  NAME ## 1,  NAME ## 2,  NAME ## 3,                                \
-NAME ## 4,  NAME ## 5,  NAME ## 6,  NAME ## 7,                                \
-NAME ## 8,  NAME ## 9,  NAME ## 10, NAME ## 11,                               \
-NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,                               \
-NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,                               \
-NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,                               \
-NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,                               \
-NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,                               \
-};                                                                            \
-static inline void func(int n)                                                \
-{                                                                             \
-    NAME ## _table[n]();                                                      \
+#define FGEN32(func, NAME)                       \
+static GenOpFunc *NAME ## _table [32] = {        \
+NAME ## 0,  NAME ## 1,  NAME ## 2,  NAME ## 3,   \
+NAME ## 4,  NAME ## 5,  NAME ## 6,  NAME ## 7,   \
+NAME ## 8,  NAME ## 9,  NAME ## 10, NAME ## 11,  \
+NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15,  \
+NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19,  \
+NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23,  \
+NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27,  \
+NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31,  \
+};                                               \
+static inline void func(int n)                   \
+{                                                \
+    NAME ## _table[n]();                         \
 }
 
-# define DFGEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [32] = {                                     \
-NAME ## 0,  0, NAME ## 2,  0,                                                 \
-NAME ## 4,  0, NAME ## 6,  0,                                                 \
-NAME ## 8,  0, NAME ## 10, 0,                                                 \
-NAME ## 12, 0, NAME ## 14, 0,                                                 \
-NAME ## 16, 0, NAME ## 18, 0,                                                 \
-NAME ## 20, 0, NAME ## 22, 0,                                                 \
-NAME ## 24, 0, NAME ## 26, 0,                                                 \
-NAME ## 28, 0, NAME ## 30, 0,                                                 \
-};                                                                            \
-static inline void func(int n)                                                \
-{                                                                             \
-    NAME ## _table[n]();                                                      \
-}
+FGEN32(gen_op_load_fpr_WT0,  gen_op_load_fpr_WT0_fpr);
+FGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
 
-SFGEN32(gen_op_load_fpr_WT0,  gen_op_load_fpr_WT0_fpr);
-SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
+FGEN32(gen_op_load_fpr_WT1,  gen_op_load_fpr_WT1_fpr);
+FGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
 
-SFGEN32(gen_op_load_fpr_WT1,  gen_op_load_fpr_WT1_fpr);
-SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
+FGEN32(gen_op_load_fpr_WT2,  gen_op_load_fpr_WT2_fpr);
+FGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
 
-SFGEN32(gen_op_load_fpr_WT2,  gen_op_load_fpr_WT2_fpr);
-SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
+FGEN32(gen_op_load_fpr_DT0,  gen_op_load_fpr_DT0_fpr);
+FGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
 
-DFGEN32(gen_op_load_fpr_DT0,  gen_op_load_fpr_DT0_fpr);
-DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
+FGEN32(gen_op_load_fpr_DT1,  gen_op_load_fpr_DT1_fpr);
+FGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
 
-DFGEN32(gen_op_load_fpr_DT1,  gen_op_load_fpr_DT1_fpr);
-DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
+FGEN32(gen_op_load_fpr_DT2,  gen_op_load_fpr_DT2_fpr);
+FGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
 
-DFGEN32(gen_op_load_fpr_DT2,  gen_op_load_fpr_DT2_fpr);
-DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
+FGEN32(gen_op_load_fpr_WTH0,  gen_op_load_fpr_WTH0_fpr);
+FGEN32(gen_op_store_fpr_WTH0, gen_op_store_fpr_WTH0_fpr);
 
-#define FOP_CONDS(fmt) \
-static GenOpFunc * cond_ ## fmt ## _table[16] = {                       \
-    gen_op_cmp_ ## fmt ## _f,                                           \
-    gen_op_cmp_ ## fmt ## _un,                                          \
-    gen_op_cmp_ ## fmt ## _eq,                                          \
-    gen_op_cmp_ ## fmt ## _ueq,                                         \
-    gen_op_cmp_ ## fmt ## _olt,                                         \
-    gen_op_cmp_ ## fmt ## _ult,                                         \
-    gen_op_cmp_ ## fmt ## _ole,                                         \
-    gen_op_cmp_ ## fmt ## _ule,                                         \
-    gen_op_cmp_ ## fmt ## _sf,                                          \
-    gen_op_cmp_ ## fmt ## _ngle,                                        \
-    gen_op_cmp_ ## fmt ## _seq,                                         \
-    gen_op_cmp_ ## fmt ## _ngl,                                         \
-    gen_op_cmp_ ## fmt ## _lt,                                          \
-    gen_op_cmp_ ## fmt ## _nge,                                         \
-    gen_op_cmp_ ## fmt ## _le,                                          \
-    gen_op_cmp_ ## fmt ## _ngt,                                         \
+FGEN32(gen_op_load_fpr_WTH1,  gen_op_load_fpr_WTH1_fpr);
+FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr);
+
+FGEN32(gen_op_load_fpr_WTH2,  gen_op_load_fpr_WTH2_fpr);
+FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr);
+
+#define FOP_CONDS(type, fmt)                                            \
+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,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _ueq,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _olt,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _ult,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _ole,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _ule,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _sf,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _ngle,                            \
+    gen_op_cmp ## type ## _ ## fmt ## _seq,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _ngl,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _lt,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _nge,                             \
+    gen_op_cmp ## type ## _ ## fmt ## _le,                              \
+    gen_op_cmp ## type ## _ ## fmt ## _ngt,                             \
 };                                                                      \
-static inline void gen_cmp_ ## fmt(int n)                               \
+static inline void gen_cmp ## type ## _ ## fmt(int n, long cc)          \
 {                                                                       \
-    cond_ ## fmt ## _table[n]();                                        \
+    gen_op_cmp ## type ## _ ## fmt ## _table[n](cc);                    \
 }
 
-FOP_CONDS(d)
-FOP_CONDS(s)
-
-#endif /* MIPS_USES_FPU */
+FOP_CONDS(, d)
+FOP_CONDS(abs, d)
+FOP_CONDS(, s)
+FOP_CONDS(abs, s)
+FOP_CONDS(, ps)
+FOP_CONDS(abs, ps)
 
 typedef struct DisasContext {
     struct TranslationBlock *tb;
     target_ulong pc, saved_pc;
     uint32_t opcode;
+    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;
@@ -499,11 +554,11 @@
     BS_EXCP     = 3, /* We reached an exception condition */
 };
 
-#if defined MIPS_DEBUG_DISAS
+#ifdef MIPS_DEBUG_DISAS
 #define MIPS_DEBUG(fmt, args...)                                              \
 do {                                                                          \
     if (loglevel & CPU_LOG_TB_IN_ASM) {                                       \
-        fprintf(logfile, TLSZ ": %08x " fmt "\n",                             \
+        fprintf(logfile, TARGET_FMT_lx ": %08x " fmt "\n",                    \
                 ctx->pc, ctx->opcode , ##args);                               \
     }                                                                         \
 } while (0)
@@ -526,6 +581,27 @@
     }                                                                         \
 } while (0)
 
+#define GEN_LOAD_SRSREG_TN(Tn, Rn)                                            \
+do {                                                                          \
+    if (Rn == 0) {                                                            \
+        glue(gen_op_reset_, Tn)();                                            \
+    } else {                                                                  \
+        glue(gen_op_load_srsgpr_, Tn)(Rn);                                    \
+    }                                                                         \
+} while (0)
+
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+#define GEN_LOAD_IMM_TN(Tn, Imm)                                              \
+do {                                                                          \
+    if (Imm == 0) {                                                           \
+        glue(gen_op_reset_, Tn)();                                            \
+    } else if ((int32_t)Imm == Imm) {                                         \
+        glue(gen_op_set_, Tn)(Imm);                                           \
+    } else {                                                                  \
+        glue(gen_op_set64_, Tn)(((uint64_t)Imm) >> 32, (uint32_t)Imm);        \
+    }                                                                         \
+} while (0)
+#else
 #define GEN_LOAD_IMM_TN(Tn, Imm)                                              \
 do {                                                                          \
     if (Imm == 0) {                                                           \
@@ -534,6 +610,7 @@
         glue(gen_op_set_, Tn)(Imm);                                           \
     }                                                                         \
 } while (0)
+#endif
 
 #define GEN_STORE_TN_REG(Rn, Tn)                                              \
 do {                                                                          \
@@ -542,6 +619,13 @@
     }                                                                         \
 } while (0)
 
+#define GEN_STORE_TN_SRSREG(Rn, Tn)                                           \
+do {                                                                          \
+    if (Rn != 0) {                                                            \
+        glue(glue(gen_op_store_, Tn),_srsgpr)(Rn);                            \
+    }                                                                         \
+} while (0)
+
 #define GEN_LOAD_FREG_FTN(FTn, Fn)                                            \
 do {                                                                          \
     glue(gen_op_load_fpr_, FTn)(Fn);                                          \
@@ -552,6 +636,32 @@
     glue(gen_op_store_fpr_, FTn)(Fn);                                         \
 } while (0)
 
+static inline void gen_save_pc(target_ulong pc)
+{
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    if (pc == (int32_t)pc) {
+        gen_op_save_pc(pc);
+    } else {
+        gen_op_save_pc64(pc >> 32, (uint32_t)pc);
+    }
+#else
+    gen_op_save_pc(pc);
+#endif
+}
+
+static inline void gen_save_btarget(target_ulong btarget)
+{
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    if (btarget == (int32_t)btarget) {
+        gen_op_save_btarget(btarget);
+    } else {
+        gen_op_save_btarget64(btarget >> 32, (uint32_t)btarget);
+    }
+#else
+    gen_op_save_btarget(btarget);
+#endif
+}
+
 static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
 {
 #if defined MIPS_DEBUG_DISAS
@@ -561,23 +671,47 @@
     }
 #endif
     if (do_save_pc && ctx->pc != ctx->saved_pc) {
-        gen_op_save_pc(ctx->pc);
+        gen_save_pc(ctx->pc);
         ctx->saved_pc = ctx->pc;
     }
     if (ctx->hflags != ctx->saved_hflags) {
         gen_op_save_state(ctx->hflags);
         ctx->saved_hflags = ctx->hflags;
-        if (ctx->hflags & MIPS_HFLAG_BR) {
+        switch (ctx->hflags & MIPS_HFLAG_BMASK) {
+        case MIPS_HFLAG_BR:
             gen_op_save_breg_target();
-        } else if (ctx->hflags & MIPS_HFLAG_B) {
-            gen_op_save_btarget(ctx->btarget);
-        } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
+            break;
+        case MIPS_HFLAG_BC:
             gen_op_save_bcond();
-            gen_op_save_btarget(ctx->btarget);
+            /* fall through */
+        case MIPS_HFLAG_BL:
+            /* bcond was already saved by the BL insn */
+            /* fall through */
+        case MIPS_HFLAG_B:
+            gen_save_btarget(ctx->btarget);
+            break;
         }
     }
 }
 
+static inline void restore_cpu_state (CPUState *env, DisasContext *ctx)
+{
+    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;
+    }
+}
+
 static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
 {
 #if defined MIPS_DEBUG_DISAS
@@ -597,6 +731,65 @@
     generate_exception_err (ctx, excp, 0);
 }
 
+static inline void check_cp0_enabled(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0)))
+        generate_exception_err(ctx, EXCP_CpU, 1);
+}
+
+static inline void check_cp1_enabled(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_FPU)))
+        generate_exception_err(ctx, EXCP_CpU, 1);
+}
+
+static inline void check_cp1_64bitmode(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/*
+ * 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 check_cp1_registers(DisasContext *ctx, int regs)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_F64) && (regs & 1)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/* This code generates a "reserved instruction" exception if the
+   CPU does not support the instruction set corresponding to flags. */
+static inline void check_insn(CPUState *env, DisasContext *ctx, int flags)
+{
+    if (unlikely(!(env->insn_flags & flags)))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/* This code generates a "reserved instruction" exception if the
+   CPU is not MIPS MT capable. */
+static inline void check_mips_mt(CPUState *env, DisasContext *ctx)
+{
+    if (unlikely(!(env->CP0_Config3 & (1 << CP0C3_MT))))
+        generate_exception(ctx, EXCP_RI);
+}
+
+/* This code generates a "reserved instruction" exception if 64-bit
+   instructions are not enabled. */
+static inline void check_mips_64(DisasContext *ctx)
+{
+    if (unlikely(!(ctx->hflags & MIPS_HFLAG_64)))
+        generate_exception(ctx, EXCP_RI);
+}
+
 #if defined(CONFIG_USER_ONLY)
 #define op_ldst(name)        gen_op_##name##_raw()
 #define OP_LD_TABLE(width)
@@ -615,7 +808,7 @@
 }
 #endif
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 OP_LD_TABLE(d);
 OP_LD_TABLE(dl);
 OP_LD_TABLE(dr);
@@ -624,9 +817,9 @@
 OP_ST_TABLE(dr);
 OP_LD_TABLE(ld);
 OP_ST_TABLE(cd);
+OP_LD_TABLE(wu);
 #endif
 OP_LD_TABLE(w);
-OP_LD_TABLE(wu);
 OP_LD_TABLE(wl);
 OP_LD_TABLE(wr);
 OP_ST_TABLE(w);
@@ -640,18 +833,18 @@
 OP_ST_TABLE(b);
 OP_LD_TABLE(l);
 OP_ST_TABLE(c);
-#ifdef MIPS_USES_FPU
 OP_LD_TABLE(wc1);
 OP_ST_TABLE(wc1);
 OP_LD_TABLE(dc1);
 OP_ST_TABLE(dc1);
-#endif
+OP_LD_TABLE(uxc1);
+OP_ST_TABLE(uxc1);
 
 /* Load and store */
 static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
                       int base, int16_t offset)
 {
-    const char *opn = "unk";
+    const char *opn = "ldst";
 
     if (base == 0) {
         GEN_LOAD_IMM_TN(T0, offset);
@@ -660,13 +853,17 @@
     } else {
         gen_op_load_gpr_T0(base);
         gen_op_set_T1(offset);
-        gen_op_add();
+        gen_op_addr_add();
     }
     /* Don't do NOP if destination is zero: we must perform the actual
-     * memory access
-     */
+       memory access. */
     switch (opc) {
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    case OPC_LWU:
+        op_ldst(lwu);
+        GEN_STORE_TN_REG(rt, T0);
+        opn = "lwu";
+        break;
     case OPC_LD:
         op_ldst(ld);
         GEN_STORE_TN_REG(rt, T0);
@@ -683,11 +880,14 @@
         opn = "sd";
         break;
     case OPC_SCD:
+        save_cpu_state(ctx, 1);
         GEN_LOAD_REG_TN(T1, rt);
         op_ldst(scd);
+        GEN_STORE_TN_REG(rt, T0);
         opn = "scd";
         break;
     case OPC_LDL:
+        GEN_LOAD_REG_TN(T1, rt);
         op_ldst(ldl);
         GEN_STORE_TN_REG(rt, T0);
         opn = "ldl";
@@ -698,6 +898,7 @@
         opn = "sdl";
         break;
     case OPC_LDR:
+        GEN_LOAD_REG_TN(T1, rt);
         op_ldst(ldr);
         GEN_STORE_TN_REG(rt, T0);
         opn = "ldr";
@@ -713,11 +914,6 @@
         GEN_STORE_TN_REG(rt, T0);
         opn = "lw";
         break;
-    case OPC_LWU:
-        op_ldst(lwu);
-        GEN_STORE_TN_REG(rt, T0);
-        opn = "lwu";
-        break;
     case OPC_SW:
         GEN_LOAD_REG_TN(T1, rt);
         op_ldst(sw);
@@ -781,26 +977,25 @@
         opn = "ll";
         break;
     case OPC_SC:
+        save_cpu_state(ctx, 1);
         GEN_LOAD_REG_TN(T1, rt);
         op_ldst(sc);
         GEN_STORE_TN_REG(rt, T0);
         opn = "sc";
         break;
     default:
-        MIPS_INVAL("load/store");
+        MIPS_INVAL(opn);
         generate_exception(ctx, EXCP_RI);
         return;
     }
     MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
 }
 
-#ifdef MIPS_USES_FPU
-
 /* Load and store */
 static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
                       int base, int16_t offset)
 {
-    const char *opn = "unk";
+    const char *opn = "flt_ldst";
 
     if (base == 0) {
         GEN_LOAD_IMM_TN(T0, offset);
@@ -809,11 +1004,10 @@
     } else {
         gen_op_load_gpr_T0(base);
         gen_op_set_T1(offset);
-        gen_op_add();
+        gen_op_addr_add();
     }
     /* Don't do NOP if destination is zero: we must perform the actual
-     * memory access
-     */
+       memory access. */
     switch (opc) {
     case OPC_LWC1:
         op_ldst(lwc1);
@@ -836,41 +1030,62 @@
         opn = "sdc1";
         break;
     default:
-        MIPS_INVAL("float load/store");
-        generate_exception_err(ctx, EXCP_CpU, 1);
+        MIPS_INVAL(opn);
+        generate_exception(ctx, EXCP_RI);
         return;
     }
     MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
 }
 
-#endif /* MIPS_USES_FPU */
-
 /* Arithmetic with immediate operand */
-static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
-                           int rs, int16_t imm)
+static void gen_arith_imm (CPUState *env, DisasContext *ctx, uint32_t opc,
+                           int rt, int rs, int16_t imm)
 {
-    uint32_t uimm;
-    const char *opn = "unk";
+    target_ulong uimm;
+    const char *opn = "imm arith";
 
     if (rt == 0 && opc != OPC_ADDI && opc != OPC_DADDI) {
-        /* if no destination, treat it as a NOP 
-         * For addi, we must generate the overflow exception when needed.
-         */
+        /* If no destination, treat it as a NOP.
+           For addi, we must generate the overflow exception when needed. */
         MIPS_DEBUG("NOP");
         return;
     }
-    if (opc == OPC_ADDI || opc == OPC_ADDIU ||
-        opc == OPC_DADDI || opc == OPC_DADDIU ||
-        opc == OPC_SLTI || opc == OPC_SLTIU)
-        uimm = (int32_t)imm; /* Sign extend to 32 bits */
-    else
-        uimm = (uint16_t)imm;
-    if (opc != OPC_LUI) {
+    uimm = (uint16_t)imm;
+    switch (opc) {
+    case OPC_ADDI:
+    case OPC_ADDIU:
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    case OPC_DADDI:
+    case OPC_DADDIU:
+#endif
+    case OPC_SLTI:
+    case OPC_SLTIU:
+        uimm = (target_long)imm; /* Sign extend to 32/64 bits */
+        /* Fall through. */
+    case OPC_ANDI:
+    case OPC_ORI:
+    case OPC_XORI:
         GEN_LOAD_REG_TN(T0, rs);
         GEN_LOAD_IMM_TN(T1, uimm);
-    } else {
-        uimm = uimm << 16;
-        GEN_LOAD_IMM_TN(T0, uimm);
+        break;
+    case OPC_LUI:
+        GEN_LOAD_IMM_TN(T0, imm << 16);
+        break;
+    case OPC_SLL:
+    case OPC_SRA:
+    case OPC_SRL:
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    case OPC_DSLL:
+    case OPC_DSRA:
+    case OPC_DSRL:
+    case OPC_DSLL32:
+    case OPC_DSRA32:
+    case OPC_DSRL32:
+#endif
+        uimm &= 0x1f;
+        GEN_LOAD_REG_TN(T0, rs);
+        GEN_LOAD_IMM_TN(T1, uimm);
+        break;
     }
     switch (opc) {
     case OPC_ADDI:
@@ -882,7 +1097,7 @@
         gen_op_add();
         opn = "addiu";
         break;
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
     case OPC_DADDI:
         save_cpu_state(ctx, 1);
         gen_op_daddo();
@@ -925,15 +1140,28 @@
         opn = "sra";
         break;
     case OPC_SRL:
-       if ((ctx->opcode >> 21) & 1) {
-            gen_op_rotr();
-            opn = "rotr";
-       } else {
+        switch ((ctx->opcode >> 21) & 0x1f) {
+        case 0:
             gen_op_srl();
             opn = "srl";
-       }
+            break;
+        case 1:
+            /* rotr is decoded as srl on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_rotr();
+                opn = "rotr";
+            } else {
+                gen_op_srl();
+                opn = "srl";
+            }
+            break;
+        default:
+            MIPS_INVAL("invalid srl flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
     case OPC_DSLL:
         gen_op_dsll();
         opn = "dsll";
@@ -943,13 +1171,26 @@
         opn = "dsra";
         break;
     case OPC_DSRL:
-       if ((ctx->opcode >> 21) & 1) {
-            gen_op_drotr();
-            opn = "drotr";
-       } else {
+        switch ((ctx->opcode >> 21) & 0x1f) {
+        case 0:
             gen_op_dsrl();
             opn = "dsrl";
-       }
+            break;
+        case 1:
+            /* drotr is decoded as dsrl on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_drotr();
+                opn = "drotr";
+            } else {
+                gen_op_dsrl();
+                opn = "dsrl";
+            }
+            break;
+        default:
+            MIPS_INVAL("invalid dsrl flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
     case OPC_DSLL32:
         gen_op_dsll32();
@@ -960,35 +1201,47 @@
         opn = "dsra32";
         break;
     case OPC_DSRL32:
-       if ((ctx->opcode >> 21) & 1) {
-            gen_op_drotr32();
-            opn = "drotr32";
-       } else {
+        switch ((ctx->opcode >> 21) & 0x1f) {
+        case 0:
             gen_op_dsrl32();
             opn = "dsrl32";
-       }
+            break;
+        case 1:
+            /* drotr32 is decoded as dsrl32 on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_drotr32();
+                opn = "drotr32";
+            } else {
+                gen_op_dsrl32();
+                opn = "dsrl32";
+            }
+            break;
+        default:
+            MIPS_INVAL("invalid dsrl32 flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
 #endif
     default:
-        MIPS_INVAL("imm arith");
+        MIPS_INVAL(opn);
         generate_exception(ctx, EXCP_RI);
         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 */
-static void gen_arith (DisasContext *ctx, uint32_t opc,
+static void gen_arith (CPUState *env, DisasContext *ctx, uint32_t opc,
                        int rd, int rs, int rt)
 {
-    const char *opn = "unk";
+    const char *opn = "arith";
 
     if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB
        && opc != OPC_DADD && opc != OPC_DSUB) {
-        /* if no destination, treat it as a NOP 
-         * For add & sub, we must generate the overflow exception when needed.
-         */
+        /* If no destination, treat it as a NOP.
+           For add & sub, we must generate the overflow exception when needed. */
         MIPS_DEBUG("NOP");
         return;
     }
@@ -1013,7 +1266,7 @@
         gen_op_sub();
         opn = "subu";
         break;
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
     case OPC_DADD:
         save_cpu_state(ctx, 1);
         gen_op_daddo();
@@ -1078,15 +1331,28 @@
         opn = "srav";
         break;
     case OPC_SRLV:
-       if ((ctx->opcode >> 6) & 1) {
-            gen_op_rotrv();
-            opn = "rotrv";
-       } else {
+        switch ((ctx->opcode >> 6) & 0x1f) {
+        case 0:
             gen_op_srlv();
             opn = "srlv";
-       }
+            break;
+        case 1:
+            /* rotrv is decoded as srlv on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_rotrv();
+                opn = "rotrv";
+            } else {
+                gen_op_srlv();
+                opn = "srlv";
+            }
+            break;
+        default:
+            MIPS_INVAL("invalid srlv flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
     case OPC_DSLLV:
         gen_op_dsllv();
         opn = "dsllv";
@@ -1096,17 +1362,30 @@
         opn = "dsrav";
         break;
     case OPC_DSRLV:
-       if ((ctx->opcode >> 6) & 1) {
-            gen_op_drotrv();
-            opn = "drotrv";
-       } else {
+        switch ((ctx->opcode >> 6) & 0x1f) {
+        case 0:
             gen_op_dsrlv();
             opn = "dsrlv";
-       }
+            break;
+        case 1:
+            /* drotrv is decoded as dsrlv on non-R2 CPUs */
+            if (env->insn_flags & ISA_MIPS32R2) {
+                gen_op_drotrv();
+                opn = "drotrv";
+            } else {
+                gen_op_dsrlv();
+                opn = "dsrlv";
+            }
+            break;
+        default:
+            MIPS_INVAL("invalid dsrlv flag");
+            generate_exception(ctx, EXCP_RI);
+            break;
+        }
         break;
 #endif
     default:
-        MIPS_INVAL("arith");
+        MIPS_INVAL(opn);
         generate_exception(ctx, EXCP_RI);
         return;
     }
@@ -1118,36 +1397,36 @@
 /* Arithmetic on HI/LO registers */
 static void gen_HILO (DisasContext *ctx, uint32_t opc, int reg)
 {
-    const char *opn = "unk";
+    const char *opn = "hilo";
 
     if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
-        /* Treat as a NOP */
+        /* Treat as NOP. */
         MIPS_DEBUG("NOP");
         return;
     }
     switch (opc) {
     case OPC_MFHI:
-        gen_op_load_HI();
+        gen_op_load_HI(0);
         GEN_STORE_TN_REG(reg, T0);
         opn = "mfhi";
         break;
     case OPC_MFLO:
-        gen_op_load_LO();
+        gen_op_load_LO(0);
         GEN_STORE_TN_REG(reg, T0);
         opn = "mflo";
         break;
     case OPC_MTHI:
         GEN_LOAD_REG_TN(T0, reg);
-        gen_op_store_HI();
+        gen_op_store_HI(0);
         opn = "mthi";
         break;
     case OPC_MTLO:
         GEN_LOAD_REG_TN(T0, reg);
-        gen_op_store_LO();
+        gen_op_store_LO(0);
         opn = "mtlo";
         break;
     default:
-        MIPS_INVAL("HILO");
+        MIPS_INVAL(opn);
         generate_exception(ctx, EXCP_RI);
         return;
     }
@@ -1157,7 +1436,7 @@
 static void gen_muldiv (DisasContext *ctx, uint32_t opc,
                         int rs, int rt)
 {
-    const char *opn = "unk";
+    const char *opn = "mul/div";
 
     GEN_LOAD_REG_TN(T0, rs);
     GEN_LOAD_REG_TN(T1, rt);
@@ -1178,7 +1457,7 @@
         gen_op_multu();
         opn = "multu";
         break;
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
     case OPC_DDIV:
         gen_op_ddiv();
         opn = "ddiv";
@@ -1213,7 +1492,7 @@
         opn = "msubu";
         break;
     default:
-        MIPS_INVAL("mul/div");
+        MIPS_INVAL(opn);
         generate_exception(ctx, EXCP_RI);
         return;
     }
@@ -1223,9 +1502,9 @@
 static void gen_cl (DisasContext *ctx, uint32_t opc,
                     int rd, int rs)
 {
-    const char *opn = "unk";
+    const char *opn = "CLx";
     if (rd == 0) {
-        /* Treat as a NOP */
+        /* Treat as NOP. */
         MIPS_DEBUG("NOP");
         return;
     }
@@ -1239,7 +1518,7 @@
         gen_op_clz();
         opn = "clz";
         break;
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
     case OPC_DCLO:
         gen_op_dclo();
         opn = "dclo";
@@ -1250,7 +1529,7 @@
         break;
 #endif
     default:
-        MIPS_INVAL("CLx");
+        MIPS_INVAL(opn);
         generate_exception(ctx, EXCP_RI);
         return;
     }
@@ -1311,10 +1590,10 @@
         case OPC_TLTIU: /* r0 < 0  unsigned  */
         case OPC_TNE:   /* rs != rs          */
         case OPC_TNEI:  /* r0 != 0           */
-            /* Never trap: treat as NOP */
+            /* Never trap: treat as NOP. */
             return;
         default:
-            MIPS_INVAL("TRAP");
+            MIPS_INVAL("trap");
             generate_exception(ctx, EXCP_RI);
             return;
         }
@@ -1345,7 +1624,7 @@
             gen_op_ne();
             break;
         default:
-            MIPS_INVAL("TRAP");
+            MIPS_INVAL("trap");
             generate_exception(ctx, EXCP_RI);
             return;
         }
@@ -1364,26 +1643,35 @@
             gen_op_goto_tb0(TBPARAM(tb));
         else
             gen_op_goto_tb1(TBPARAM(tb));
-        gen_op_save_pc(dest);
+        gen_save_pc(dest);
         gen_op_set_T0((long)tb + n);
-        gen_op_exit_tb();
     } else {
-        gen_op_save_pc(dest);
-        gen_op_set_T0(0);
-        gen_op_exit_tb();
+        gen_save_pc(dest);
+        gen_op_reset_T0();
     }
+    gen_op_exit_tb();
 }
 
 /* Branches (before delay slot) */
 static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
                                 int rs, int rt, int32_t offset)
 {
-    target_ulong btarget;
-    int blink, bcond;
+    target_ulong btarget = -1;
+    int blink = 0;
+    int bcond = 0;
 
-    btarget = -1;
-    blink = 0;
-    bcond = 0;
+    if (ctx->hflags & MIPS_HFLAG_BMASK) {
+#ifdef MIPS_DEBUG_DISAS
+        if (loglevel & CPU_LOG_TB_IN_ASM) {
+            fprintf(logfile,
+                    "Branch in delay slot at PC 0x" TARGET_FMT_lx "\n",
+                    ctx->pc);
+	}
+#endif
+        generate_exception(ctx, EXCP_RI);
+        return;
+    }
+
     /* Load needed operands */
     switch (opc) {
     case OPC_BEQ:
@@ -1420,14 +1708,15 @@
     case OPC_J:
     case OPC_JAL:
         /* Jump to immediate */
-        btarget = ((ctx->pc + 4) & (int32_t)0xF0000000) | offset;
+        btarget = ((ctx->pc + 4) & (int32_t)0xF0000000) | (uint32_t)offset;
         break;
     case OPC_JR:
     case OPC_JALR:
         /* Jump to register */
         if (offset != 0 && offset != 16) {
             /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
-              others are reserved. */
+               others are reserved. */
+            MIPS_INVAL("jump hint");
             generate_exception(ctx, EXCP_RI);
             return;
         }
@@ -1461,33 +1750,36 @@
         case OPC_BNE:     /* rx != rx        */
         case OPC_BGTZ:    /* 0 > 0           */
         case OPC_BLTZ:    /* 0 < 0           */
-            /* Treated as NOP */
+            /* Treat as NOP. */
             MIPS_DEBUG("bnever (NOP)");
             return;
         case OPC_BLTZAL:  /* 0 < 0           */
-            gen_op_set_T0(ctx->pc + 8);
+            GEN_LOAD_IMM_TN(T0, ctx->pc + 8);
             gen_op_store_T0_gpr(31);
+            MIPS_DEBUG("bnever and link");
             return;
         case OPC_BLTZALL: /* 0 < 0 likely */
-            gen_op_set_T0(ctx->pc + 8);
+            GEN_LOAD_IMM_TN(T0, ctx->pc + 8);
             gen_op_store_T0_gpr(31);
-            gen_goto_tb(ctx, 0, ctx->pc + 4);
+            /* Skip the instruction in the delay slot */
+            MIPS_DEBUG("bnever, link and skip");
+            ctx->pc += 4;
             return;
         case OPC_BNEL:    /* rx != rx likely */
         case OPC_BGTZL:   /* 0 > 0 likely */
         case OPC_BLTZL:   /* 0 < 0 likely */
             /* Skip the instruction in the delay slot */
             MIPS_DEBUG("bnever and skip");
-            gen_goto_tb(ctx, 0, ctx->pc + 4);
+            ctx->pc += 4;
             return;
         case OPC_J:
             ctx->hflags |= MIPS_HFLAG_B;
-            MIPS_DEBUG("j %08x", btarget);
+            MIPS_DEBUG("j " TARGET_FMT_lx, btarget);
             break;
         case OPC_JAL:
             blink = 31;
             ctx->hflags |= MIPS_HFLAG_B;
-            MIPS_DEBUG("jal %08x", btarget);
+            MIPS_DEBUG("jal " TARGET_FMT_lx, btarget);
             break;
         case OPC_JR:
             ctx->hflags |= MIPS_HFLAG_BR;
@@ -1507,91 +1799,97 @@
         switch (opc) {
         case OPC_BEQ:
             gen_op_eq();
-            MIPS_DEBUG("beq %s, %s, %08x",
+            MIPS_DEBUG("beq %s, %s, " TARGET_FMT_lx,
                        regnames[rs], regnames[rt], btarget);
             goto not_likely;
         case OPC_BEQL:
             gen_op_eq();
-            MIPS_DEBUG("beql %s, %s, %08x",
+            MIPS_DEBUG("beql %s, %s, " TARGET_FMT_lx,
                        regnames[rs], regnames[rt], btarget);
             goto likely;
         case OPC_BNE:
             gen_op_ne();
-            MIPS_DEBUG("bne %s, %s, %08x",
+            MIPS_DEBUG("bne %s, %s, " TARGET_FMT_lx,
                        regnames[rs], regnames[rt], btarget);
             goto not_likely;
         case OPC_BNEL:
             gen_op_ne();
-            MIPS_DEBUG("bnel %s, %s, %08x",
+            MIPS_DEBUG("bnel %s, %s, " TARGET_FMT_lx,
                        regnames[rs], regnames[rt], btarget);
             goto likely;
         case OPC_BGEZ:
             gen_op_gez();
-            MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bgez %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto not_likely;
         case OPC_BGEZL:
             gen_op_gez();
-            MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto likely;
         case OPC_BGEZAL:
             gen_op_gez();
-            MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btarget);
             blink = 31;
             goto not_likely;
         case OPC_BGEZALL:
             gen_op_gez();
             blink = 31;
-            MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bgezall %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto likely;
         case OPC_BGTZ:
             gen_op_gtz();
-            MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bgtz %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto not_likely;
         case OPC_BGTZL:
             gen_op_gtz();
-            MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bgtzl %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto likely;
         case OPC_BLEZ:
             gen_op_lez();
-            MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("blez %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto not_likely;
         case OPC_BLEZL:
             gen_op_lez();
-            MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("blezl %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto likely;
         case OPC_BLTZ:
             gen_op_ltz();
-            MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bltz %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto not_likely;
         case OPC_BLTZL:
             gen_op_ltz();
-            MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bltzl %s, " TARGET_FMT_lx, regnames[rs], btarget);
             goto likely;
         case OPC_BLTZAL:
             gen_op_ltz();
             blink = 31;
-            MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btarget);
         not_likely:
             ctx->hflags |= MIPS_HFLAG_BC;
+            gen_op_set_bcond();
             break;
         case OPC_BLTZALL:
             gen_op_ltz();
             blink = 31;
-            MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
+            MIPS_DEBUG("bltzall %s, " TARGET_FMT_lx, regnames[rs], btarget);
         likely:
             ctx->hflags |= MIPS_HFLAG_BL;
+            gen_op_set_bcond();
+            gen_op_save_bcond();
             break;
+        default:
+            MIPS_INVAL("conditional branch/jump");
+            generate_exception(ctx, EXCP_RI);
+            return;
         }
-        gen_op_set_bcond();
     }
-    MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
+    MIPS_DEBUG("enter ds: link %d cond %02x target " TARGET_FMT_lx,
                blink, ctx->hflags, btarget);
+
     ctx->btarget = btarget;
     if (blink > 0) {
-        gen_op_set_T0(ctx->pc + 8);
+        GEN_LOAD_IMM_TN(T0, ctx->pc + 8);
         gen_op_store_T0_gpr(blink);
     }
-    return;
 }
 
 /* special3 bitfield operations */
@@ -1621,25 +1919,25 @@
     case OPC_INS:
         if (lsb > msb)
             goto fail;
-        GEN_LOAD_REG_TN(T2, rt);
+        GEN_LOAD_REG_TN(T0, rt);
         gen_op_ins(lsb, msb - lsb + 1);
         break;
     case OPC_DINSM:
         if (lsb > msb)
             goto fail;
-        GEN_LOAD_REG_TN(T2, rt);
+        GEN_LOAD_REG_TN(T0, rt);
         gen_op_ins(lsb, msb - lsb + 1 + 32);
         break;
     case OPC_DINSU:
         if (lsb > msb)
             goto fail;
-        GEN_LOAD_REG_TN(T2, rt);
+        GEN_LOAD_REG_TN(T0, rt);
         gen_op_ins(lsb + 32, msb - lsb + 1);
         break;
     case OPC_DINS:
         if (lsb > msb)
             goto fail;
-        GEN_LOAD_REG_TN(T2, rt);
+        GEN_LOAD_REG_TN(T0, rt);
         gen_op_ins(lsb, msb - lsb + 1);
         break;
     default:
@@ -1652,29 +1950,35 @@
 }
 
 /* CP0 (MMU and control) */
-static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
+static void gen_mfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
 {
     const char *rn = "invalid";
 
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS32);
+
     switch (reg) {
     case 0:
         switch (sel) {
         case 0:
-           gen_op_mfc0_index();
+            gen_op_mfc0_index();
             rn = "Index";
             break;
         case 1:
-//         gen_op_mfc0_mvpcontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpcontrol();
             rn = "MVPControl";
-//         break;
+            break;
         case 2:
-//         gen_op_mfc0_mvpconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpconf0();
             rn = "MVPConf0";
-//         break;
+            break;
         case 3:
-//         gen_op_mfc0_mvpconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpconf1();
             rn = "MVPConf1";
-//         break;
+            break;
         default:
             goto die;
         }
@@ -1684,35 +1988,42 @@
         case 0:
             gen_op_mfc0_random();
             rn = "Random";
-           break;
+            break;
         case 1:
-//         gen_op_mfc0_vpecontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpecontrol();
             rn = "VPEControl";
-//         break;
+            break;
         case 2:
-//         gen_op_mfc0_vpeconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeconf0();
             rn = "VPEConf0";
-//         break;
+            break;
         case 3:
-//         gen_op_mfc0_vpeconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeconf1();
             rn = "VPEConf1";
-//         break;
+            break;
         case 4:
-//         gen_op_mfc0_YQMask(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_yqmask();
             rn = "YQMask";
-//         break;
+            break;
         case 5:
-//         gen_op_mfc0_vpeschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeschedule();
             rn = "VPESchedule";
-//         break;
+            break;
         case 6:
-//         gen_op_mfc0_vpeschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeschefback();
             rn = "VPEScheFBack";
-//         break;
+            break;
         case 7:
-//         gen_op_mfc0_vpeopt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeopt();
             rn = "VPEOpt";
-//         break;
+            break;
         default:
             goto die;
         }
@@ -1720,37 +2031,44 @@
     case 2:
         switch (sel) {
         case 0:
-           gen_op_mfc0_entrylo0();
-           rn = "EntryLo0";
-           break;
+            gen_op_mfc0_entrylo0();
+            rn = "EntryLo0";
+            break;
         case 1:
-//         gen_op_mfc0_tcstatus(); /* MT ASE */
-           rn = "TCStatus";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcstatus();
+            rn = "TCStatus";
+            break;
         case 2:
-//         gen_op_mfc0_tcbind(); /* MT ASE */
-           rn = "TCBind";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcbind();
+            rn = "TCBind";
+            break;
         case 3:
-//         gen_op_mfc0_tcrestart(); /* MT ASE */
-           rn = "TCRestart";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcrestart();
+            rn = "TCRestart";
+            break;
         case 4:
-//         gen_op_mfc0_tchalt(); /* MT ASE */
-           rn = "TCHalt";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tchalt();
+            rn = "TCHalt";
+            break;
         case 5:
-//         gen_op_mfc0_tccontext(); /* MT ASE */
-           rn = "TCContext";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tccontext();
+            rn = "TCContext";
+            break;
         case 6:
-//         gen_op_mfc0_tcschedule(); /* MT ASE */
-           rn = "TCSchedule";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcschedule();
+            rn = "TCSchedule";
+            break;
         case 7:
-//         gen_op_mfc0_tcschefback(); /* MT ASE */
-           rn = "TCScheFBack";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcschefback();
+            rn = "TCScheFBack";
+            break;
         default:
             goto die;
         }
@@ -1758,87 +2076,94 @@
     case 3:
         switch (sel) {
         case 0:
-           gen_op_mfc0_entrylo1();
-           rn = "EntryLo1";
-           break;
+            gen_op_mfc0_entrylo1();
+            rn = "EntryLo1";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 4:
         switch (sel) {
         case 0:
-           gen_op_mfc0_context();
-           rn = "Context";
-           break;
+            gen_op_mfc0_context();
+            rn = "Context";
+            break;
         case 1:
-//         gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */
-           rn = "ContextConfig";
-//         break;
+//            gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */
+            rn = "ContextConfig";
+//            break;
         default:
             goto die;
-       }
+        }
         break;
     case 5:
         switch (sel) {
         case 0:
-           gen_op_mfc0_pagemask();
-           rn = "PageMask";
-           break;
+            gen_op_mfc0_pagemask();
+            rn = "PageMask";
+            break;
         case 1:
-           gen_op_mfc0_pagegrain();
-           rn = "PageGrain";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_pagegrain();
+            rn = "PageGrain";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 6:
         switch (sel) {
         case 0:
-           gen_op_mfc0_wired();
-           rn = "Wired";
-           break;
+            gen_op_mfc0_wired();
+            rn = "Wired";
+            break;
         case 1:
-//         gen_op_mfc0_srsconf0(); /* shadow registers */
-           rn = "SRSConf0";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf0();
+            rn = "SRSConf0";
+            break;
         case 2:
-//         gen_op_mfc0_srsconf1(); /* shadow registers */
-           rn = "SRSConf1";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf1();
+            rn = "SRSConf1";
+            break;
         case 3:
-//         gen_op_mfc0_srsconf2(); /* shadow registers */
-           rn = "SRSConf2";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf2();
+            rn = "SRSConf2";
+            break;
         case 4:
-//         gen_op_mfc0_srsconf3(); /* shadow registers */
-           rn = "SRSConf3";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf3();
+            rn = "SRSConf3";
+            break;
         case 5:
-//         gen_op_mfc0_srsconf4(); /* shadow registers */
-           rn = "SRSConf4";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf4();
+            rn = "SRSConf4";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 7:
         switch (sel) {
         case 0:
-           gen_op_mfc0_hwrena();
-           rn = "HWREna";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_hwrena();
+            rn = "HWREna";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 8:
         switch (sel) {
         case 0:
-           gen_op_mfc0_badvaddr();
-           rn = "BadVaddr";
-           break;
+            gen_op_mfc0_badvaddr();
+            rn = "BadVaddr";
+            break;
         default:
             goto die;
        }
@@ -1846,53 +2171,56 @@
     case 9:
         switch (sel) {
         case 0:
-           gen_op_mfc0_count();
-           rn = "Count";
-           break;
-       /* 6,7 are implementation dependent */
+            gen_op_mfc0_count();
+            rn = "Count";
+            break;
+        /* 6,7 are implementation dependent */
         default:
             goto die;
-       }
+        }
         break;
     case 10:
         switch (sel) {
         case 0:
-           gen_op_mfc0_entryhi();
-           rn = "EntryHi";
-           break;
+            gen_op_mfc0_entryhi();
+            rn = "EntryHi";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 11:
         switch (sel) {
         case 0:
-           gen_op_mfc0_compare();
-           rn = "Compare";
-           break;
-       /* 6,7 are implementation dependent */
+            gen_op_mfc0_compare();
+            rn = "Compare";
+            break;
+        /* 6,7 are implementation dependent */
         default:
             goto die;
-       }
+        }
         break;
     case 12:
         switch (sel) {
         case 0:
-           gen_op_mfc0_status();
-           rn = "Status";
-           break;
+            gen_op_mfc0_status();
+            rn = "Status";
+            break;
         case 1:
-           gen_op_mfc0_intctl();
-           rn = "IntCtl";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_intctl();
+            rn = "IntCtl";
+            break;
         case 2:
-           gen_op_mfc0_srsctl();
-           rn = "SRSCtl";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsctl();
+            rn = "SRSCtl";
+            break;
         case 3:
-//         gen_op_mfc0_srsmap(); /* shadow registers */
-           rn = "SRSMap";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsmap();
+            rn = "SRSMap";
+            break;
         default:
             goto die;
        }
@@ -1900,9 +2228,9 @@
     case 13:
         switch (sel) {
         case 0:
-           gen_op_mfc0_cause();
-           rn = "Cause";
-           break;
+            gen_op_mfc0_cause();
+            rn = "Cause";
+            break;
         default:
             goto die;
        }
@@ -1910,23 +2238,24 @@
     case 14:
         switch (sel) {
         case 0:
-           gen_op_mfc0_epc();
-           rn = "EPC";
-           break;
+            gen_op_mfc0_epc();
+            rn = "EPC";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 15:
         switch (sel) {
         case 0:
-           gen_op_mfc0_prid();
-           rn = "PRid";
-           break;
+            gen_op_mfc0_prid();
+            rn = "PRid";
+            break;
         case 1:
-           gen_op_mfc0_ebase();
-           rn = "EBase";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_ebase();
+            rn = "EBase";
+            break;
         default:
             goto die;
        }
@@ -1934,22 +2263,31 @@
     case 16:
         switch (sel) {
         case 0:
-           gen_op_mfc0_config0();
+            gen_op_mfc0_config0();
             rn = "Config";
             break;
         case 1:
-           gen_op_mfc0_config1();
+            gen_op_mfc0_config1();
             rn = "Config1";
             break;
         case 2:
-           gen_op_mfc0_config2();
+            gen_op_mfc0_config2();
             rn = "Config2";
             break;
         case 3:
-           gen_op_mfc0_config3();
+            gen_op_mfc0_config3();
             rn = "Config3";
             break;
-       /* 6,7 are implementation dependent */
+        /* 4,5 are reserved */
+        /* 6,7 are implementation dependent */
+        case 6:
+            gen_op_mfc0_config6();
+            rn = "Config6";
+            break;
+        case 7:
+            gen_op_mfc0_config7();
+            rn = "Config7";
+            break;
         default:
             goto die;
         }
@@ -1957,85 +2295,29 @@
     case 17:
         switch (sel) {
         case 0:
-           gen_op_mfc0_lladdr();
-           rn = "LLAddr";
-           break;
+            gen_op_mfc0_lladdr();
+            rn = "LLAddr";
+            break;
         default:
             goto die;
         }
         break;
     case 18:
         switch (sel) {
-        case 0:
-           gen_op_mfc0_watchlo0();
-           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;
+        case 0 ... 7:
+            gen_op_mfc0_watchlo(sel);
+            rn = "WatchLo";
+            break;
         default:
             goto die;
         }
         break;
     case 19:
         switch (sel) {
-        case 0:
-           gen_op_mfc0_watchhi0();
-           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;
+        case 0 ...7:
+            gen_op_mfc0_watchhi(sel);
+            rn = "WatchHi";
+            break;
         default:
             goto die;
         }
@@ -2043,10 +2325,12 @@
     case 20:
         switch (sel) {
         case 0:
-           /* 64 bit MMU only */
-           gen_op_mfc0_xcontext();
-           rn = "XContext";
-           break;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+            check_insn(env, ctx, ISA_MIPS3);
+            gen_op_mfc0_xcontext();
+            rn = "XContext";
+            break;
+#endif
         default:
             goto die;
         }
@@ -2055,39 +2339,39 @@
        /* Officially reserved, but sel 0 is used for R1x000 framemask */
         switch (sel) {
         case 0:
-           gen_op_mfc0_framemask();
-           rn = "Framemask";
-           break;
+            gen_op_mfc0_framemask();
+            rn = "Framemask";
+            break;
         default:
             goto die;
         }
         break;
     case 22:
-       /* ignored */
-       rn = "'Diagnostic"; /* implementation dependent */
-       break;
+        /* ignored */
+        rn = "'Diagnostic"; /* implementation dependent */
+        break;
     case 23:
         switch (sel) {
         case 0:
-           gen_op_mfc0_debug(); /* EJTAG support */
-           rn = "Debug";
-           break;
+            gen_op_mfc0_debug(); /* EJTAG support */
+            rn = "Debug";
+            break;
         case 1:
-//         gen_op_mfc0_tracecontrol(); /* PDtrace support */
-           rn = "TraceControl";
-//         break;
+//            gen_op_mfc0_tracecontrol(); /* PDtrace support */
+            rn = "TraceControl";
+//            break;
         case 2:
-//         gen_op_mfc0_tracecontrol2(); /* PDtrace support */
-           rn = "TraceControl2";
-//         break;
+//            gen_op_mfc0_tracecontrol2(); /* PDtrace support */
+            rn = "TraceControl2";
+//            break;
         case 3:
-//         gen_op_mfc0_usertracedata(); /* PDtrace support */
-           rn = "UserTraceData";
-//         break;
+//            gen_op_mfc0_usertracedata(); /* PDtrace support */
+            rn = "UserTraceData";
+//            break;
         case 4:
-//         gen_op_mfc0_debug(); /* PDtrace support */
-           rn = "TraceBPC";
-//         break;
+//            gen_op_mfc0_debug(); /* PDtrace support */
+            rn = "TraceBPC";
+//            break;
         default:
             goto die;
         }
@@ -2095,9 +2379,9 @@
     case 24:
         switch (sel) {
         case 0:
-           gen_op_mfc0_depc(); /* EJTAG support */
-           rn = "DEPC";
-           break;
+            gen_op_mfc0_depc(); /* EJTAG support */
+            rn = "DEPC";
+            break;
         default:
             goto die;
         }
@@ -2105,37 +2389,37 @@
     case 25:
         switch (sel) {
         case 0:
-           gen_op_mfc0_performance0();
-           rn = "Performance0";
+            gen_op_mfc0_performance0();
+            rn = "Performance0";
             break;
         case 1:
-//         gen_op_mfc0_performance1();
-           rn = "Performance1";
-//         break;
+//            gen_op_mfc0_performance1();
+            rn = "Performance1";
+//            break;
         case 2:
-//         gen_op_mfc0_performance2();
-           rn = "Performance2";
-//         break;
+//            gen_op_mfc0_performance2();
+            rn = "Performance2";
+//            break;
         case 3:
-//         gen_op_mfc0_performance3();
-           rn = "Performance3";
-//         break;
+//            gen_op_mfc0_performance3();
+            rn = "Performance3";
+//            break;
         case 4:
-//         gen_op_mfc0_performance4();
-           rn = "Performance4";
-//         break;
+//            gen_op_mfc0_performance4();
+            rn = "Performance4";
+//            break;
         case 5:
-//         gen_op_mfc0_performance5();
-           rn = "Performance5";
-//         break;
+//            gen_op_mfc0_performance5();
+            rn = "Performance5";
+//            break;
         case 6:
-//         gen_op_mfc0_performance6();
-           rn = "Performance6";
-//         break;
+//            gen_op_mfc0_performance6();
+            rn = "Performance6";
+//            break;
         case 7:
-//         gen_op_mfc0_performance7();
-           rn = "Performance7";
-//         break;
+//            gen_op_mfc0_performance7();
+            rn = "Performance7";
+//            break;
         default:
             goto die;
         }
@@ -2147,8 +2431,8 @@
         switch (sel) {
         /* ignored */
         case 0 ... 3:
-           rn = "CacheErr";
-           break;
+            rn = "CacheErr";
+            break;
         default:
             goto die;
         }
@@ -2196,9 +2480,9 @@
     case 30:
         switch (sel) {
         case 0:
-           gen_op_mfc0_errorepc();
-           rn = "ErrorEPC";
-           break;
+            gen_op_mfc0_errorepc();
+            rn = "ErrorEPC";
+            break;
         default:
             goto die;
         }
@@ -2206,9 +2490,9 @@
     case 31:
         switch (sel) {
         case 0:
-           gen_op_mfc0_desave(); /* EJTAG support */
-           rn = "DESAVE";
-           break;
+            gen_op_mfc0_desave(); /* EJTAG support */
+            rn = "DESAVE";
+            break;
         default:
             goto die;
         }
@@ -2234,10 +2518,13 @@
     generate_exception(ctx, EXCP_RI);
 }
 
-static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
+static void gen_mtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
 {
     const char *rn = "invalid";
 
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS32);
+
     switch (reg) {
     case 0:
         switch (sel) {
@@ -2246,17 +2533,20 @@
             rn = "Index";
             break;
         case 1:
-//         gen_op_mtc0_mvpcontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_mvpcontrol();
             rn = "MVPControl";
-//         break;
+            break;
         case 2:
-//         gen_op_mtc0_mvpconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            /* ignored */
             rn = "MVPConf0";
-//         break;
+            break;
         case 3:
-//         gen_op_mtc0_mvpconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            /* ignored */
             rn = "MVPConf1";
-//         break;
+            break;
         default:
             goto die;
         }
@@ -2264,37 +2554,44 @@
     case 1:
         switch (sel) {
         case 0:
-           /* ignored */
+            /* ignored */
             rn = "Random";
-           break;
+            break;
         case 1:
-//         gen_op_mtc0_vpecontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpecontrol();
             rn = "VPEControl";
-//         break;
+            break;
         case 2:
-//         gen_op_mtc0_vpeconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeconf0();
             rn = "VPEConf0";
-//         break;
+            break;
         case 3:
-//         gen_op_mtc0_vpeconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeconf1();
             rn = "VPEConf1";
-//         break;
+            break;
         case 4:
-//         gen_op_mtc0_YQMask(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_yqmask();
             rn = "YQMask";
-//         break;
+            break;
         case 5:
-//         gen_op_mtc0_vpeschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeschedule();
             rn = "VPESchedule";
-//         break;
+            break;
         case 6:
-//         gen_op_mtc0_vpeschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeschefback();
             rn = "VPEScheFBack";
-//         break;
+            break;
         case 7:
-//         gen_op_mtc0_vpeopt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeopt();
             rn = "VPEOpt";
-//         break;
+            break;
         default:
             goto die;
         }
@@ -2302,37 +2599,44 @@
     case 2:
         switch (sel) {
         case 0:
-           gen_op_mtc0_entrylo0();
-           rn = "EntryLo0";
-           break;
+            gen_op_mtc0_entrylo0();
+            rn = "EntryLo0";
+            break;
         case 1:
-//         gen_op_mtc0_tcstatus(); /* MT ASE */
-           rn = "TCStatus";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcstatus();
+            rn = "TCStatus";
+            break;
         case 2:
-//         gen_op_mtc0_tcbind(); /* MT ASE */
-           rn = "TCBind";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcbind();
+            rn = "TCBind";
+            break;
         case 3:
-//         gen_op_mtc0_tcrestart(); /* MT ASE */
-           rn = "TCRestart";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcrestart();
+            rn = "TCRestart";
+            break;
         case 4:
-//         gen_op_mtc0_tchalt(); /* MT ASE */
-           rn = "TCHalt";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tchalt();
+            rn = "TCHalt";
+            break;
         case 5:
-//         gen_op_mtc0_tccontext(); /* MT ASE */
-           rn = "TCContext";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tccontext();
+            rn = "TCContext";
+            break;
         case 6:
-//         gen_op_mtc0_tcschedule(); /* MT ASE */
-           rn = "TCSchedule";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcschedule();
+            rn = "TCSchedule";
+            break;
         case 7:
-//         gen_op_mtc0_tcschefback(); /* MT ASE */
-           rn = "TCScheFBack";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcschefback();
+            rn = "TCScheFBack";
+            break;
         default:
             goto die;
         }
@@ -2340,80 +2644,87 @@
     case 3:
         switch (sel) {
         case 0:
-           gen_op_mtc0_entrylo1();
-           rn = "EntryLo1";
-           break;
+            gen_op_mtc0_entrylo1();
+            rn = "EntryLo1";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 4:
         switch (sel) {
         case 0:
-           gen_op_mtc0_context();
-           rn = "Context";
-           break;
+            gen_op_mtc0_context();
+            rn = "Context";
+            break;
         case 1:
-//         gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */
-           rn = "ContextConfig";
-//         break;
+//            gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */
+            rn = "ContextConfig";
+//            break;
         default:
             goto die;
-       }
+        }
         break;
     case 5:
         switch (sel) {
         case 0:
-           gen_op_mtc0_pagemask();
-           rn = "PageMask";
-           break;
+            gen_op_mtc0_pagemask();
+            rn = "PageMask";
+            break;
         case 1:
-           gen_op_mtc0_pagegrain();
-           rn = "PageGrain";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_pagegrain();
+            rn = "PageGrain";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 6:
         switch (sel) {
         case 0:
-           gen_op_mtc0_wired();
-           rn = "Wired";
-           break;
+            gen_op_mtc0_wired();
+            rn = "Wired";
+            break;
         case 1:
-//         gen_op_mtc0_srsconf0(); /* shadow registers */
-           rn = "SRSConf0";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf0();
+            rn = "SRSConf0";
+            break;
         case 2:
-//         gen_op_mtc0_srsconf1(); /* shadow registers */
-           rn = "SRSConf1";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf1();
+            rn = "SRSConf1";
+            break;
         case 3:
-//         gen_op_mtc0_srsconf2(); /* shadow registers */
-           rn = "SRSConf2";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf2();
+            rn = "SRSConf2";
+            break;
         case 4:
-//         gen_op_mtc0_srsconf3(); /* shadow registers */
-           rn = "SRSConf3";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf3();
+            rn = "SRSConf3";
+            break;
         case 5:
-//         gen_op_mtc0_srsconf4(); /* shadow registers */
-           rn = "SRSConf4";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf4();
+            rn = "SRSConf4";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 7:
         switch (sel) {
         case 0:
-           gen_op_mtc0_hwrena();
-           rn = "HWREna";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_hwrena();
+            rn = "HWREna";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 8:
         /* ignored */
@@ -2422,207 +2733,173 @@
     case 9:
         switch (sel) {
         case 0:
-           gen_op_mtc0_count();
-           rn = "Count";
-           break;
-       /* 6,7 are implementation dependent */
+            gen_op_mtc0_count();
+            rn = "Count";
+            break;
+        /* 6,7 are implementation dependent */
         default:
             goto die;
-       }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
         break;
     case 10:
         switch (sel) {
         case 0:
-           gen_op_mtc0_entryhi();
-           rn = "EntryHi";
-           break;
+            gen_op_mtc0_entryhi();
+            rn = "EntryHi";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 11:
         switch (sel) {
         case 0:
-           gen_op_mtc0_compare();
-           rn = "Compare";
-           break;
-       /* 6,7 are implementation dependent */
+            gen_op_mtc0_compare();
+            rn = "Compare";
+            break;
+        /* 6,7 are implementation dependent */
         default:
             goto die;
-       }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
         break;
     case 12:
         switch (sel) {
         case 0:
-           gen_op_mtc0_status();
-           rn = "Status";
-           break;
+            gen_op_mtc0_status();
+            /* BS_STOP isn't good enough here, hflags may have changed. */
+            gen_save_pc(ctx->pc + 4);
+            ctx->bstate = BS_EXCP;
+            rn = "Status";
+            break;
         case 1:
-           gen_op_mtc0_intctl();
-           rn = "IntCtl";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_intctl();
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "IntCtl";
+            break;
         case 2:
-           gen_op_mtc0_srsctl();
-           rn = "SRSCtl";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsctl();
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "SRSCtl";
+            break;
         case 3:
-//         gen_op_mtc0_srsmap(); /* shadow registers */
-           rn = "SRSMap";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsmap();
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "SRSMap";
+            break;
         default:
             goto die;
-       }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        }
         break;
     case 13:
         switch (sel) {
         case 0:
-           gen_op_mtc0_cause();
-           rn = "Cause";
-           break;
+            gen_op_mtc0_cause();
+            rn = "Cause";
+            break;
         default:
             goto die;
-       }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
         break;
     case 14:
         switch (sel) {
         case 0:
-           gen_op_mtc0_epc();
-           rn = "EPC";
-           break;
+            gen_op_mtc0_epc();
+            rn = "EPC";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 15:
         switch (sel) {
         case 0:
-           /* ignored */
-           rn = "PRid";
-           break;
+            /* ignored */
+            rn = "PRid";
+            break;
         case 1:
-           gen_op_mtc0_ebase();
-           rn = "EBase";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_ebase();
+            rn = "EBase";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 16:
         switch (sel) {
         case 0:
-           gen_op_mtc0_config0();
+            gen_op_mtc0_config0();
             rn = "Config";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
             break;
         case 1:
-           /* ignored */
+            /* ignored, read only */
             rn = "Config1";
             break;
         case 2:
-           gen_op_mtc0_config2();
+            gen_op_mtc0_config2();
             rn = "Config2";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
             break;
         case 3:
-           /* ignored */
+            /* ignored, read only */
             rn = "Config3";
             break;
-       /* 6,7 are implementation dependent */
+        /* 4,5 are reserved */
+        /* 6,7 are implementation dependent */
+        case 6:
+            /* ignored */
+            rn = "Config6";
+            break;
+        case 7:
+            /* ignored */
+            rn = "Config7";
+            break;
         default:
             rn = "Invalid config selector";
             goto die;
         }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
         break;
     case 17:
         switch (sel) {
         case 0:
-           /* ignored */
-           rn = "LLAddr";
-           break;
+            /* ignored */
+            rn = "LLAddr";
+            break;
         default:
             goto die;
         }
         break;
     case 18:
         switch (sel) {
-        case 0:
-           gen_op_mtc0_watchlo0();
-           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;
+        case 0 ... 7:
+            gen_op_mtc0_watchlo(sel);
+            rn = "WatchLo";
+            break;
         default:
             goto die;
         }
         break;
     case 19:
         switch (sel) {
-        case 0:
-           gen_op_mtc0_watchhi0();
-           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;
+        case 0 ... 7:
+            gen_op_mtc0_watchhi(sel);
+            rn = "WatchHi";
+            break;
         default:
             goto die;
         }
@@ -2630,10 +2907,12 @@
     case 20:
         switch (sel) {
         case 0:
-           /* 64 bit MMU only */
-           gen_op_mtc0_xcontext();
-           rn = "XContext";
-           break;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+            check_insn(env, ctx, ISA_MIPS3);
+            gen_op_mtc0_xcontext();
+            rn = "XContext";
+            break;
+#endif
         default:
             goto die;
         }
@@ -2642,9 +2921,9 @@
        /* Officially reserved, but sel 0 is used for R1x000 framemask */
         switch (sel) {
         case 0:
-           gen_op_mtc0_framemask();
-           rn = "Framemask";
-           break;
+            gen_op_mtc0_framemask();
+            rn = "Framemask";
+            break;
         default:
             goto die;
         }
@@ -2652,41 +2931,52 @@
     case 22:
         /* ignored */
         rn = "Diagnostic"; /* implementation dependent */
-       break;
+        break;
     case 23:
         switch (sel) {
         case 0:
-           gen_op_mtc0_debug(); /* EJTAG support */
-           rn = "Debug";
-           break;
+            gen_op_mtc0_debug(); /* EJTAG support */
+            /* BS_STOP isn't good enough here, hflags may have changed. */
+            gen_save_pc(ctx->pc + 4);
+            ctx->bstate = BS_EXCP;
+            rn = "Debug";
+            break;
         case 1:
-//         gen_op_mtc0_tracecontrol(); /* PDtrace support */
-           rn = "TraceControl";
-//         break;
+//            gen_op_mtc0_tracecontrol(); /* PDtrace support */
+            rn = "TraceControl";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+//            break;
         case 2:
-//         gen_op_mtc0_tracecontrol2(); /* PDtrace support */
-           rn = "TraceControl2";
-//         break;
+//            gen_op_mtc0_tracecontrol2(); /* PDtrace support */
+            rn = "TraceControl2";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+//            break;
         case 3:
-//         gen_op_mtc0_usertracedata(); /* PDtrace support */
-           rn = "UserTraceData";
-//         break;
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+//            gen_op_mtc0_usertracedata(); /* PDtrace support */
+            rn = "UserTraceData";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+//            break;
         case 4:
-//         gen_op_mtc0_debug(); /* PDtrace support */
-           rn = "TraceBPC";
-//         break;
+//            gen_op_mtc0_debug(); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "TraceBPC";
+//            break;
         default:
             goto die;
         }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
         break;
     case 24:
         switch (sel) {
         case 0:
-           gen_op_mtc0_depc(); /* EJTAG support */
-           rn = "DEPC";
-           break;
+            gen_op_mtc0_depc(); /* EJTAG support */
+            rn = "DEPC";
+            break;
         default:
             goto die;
         }
@@ -2694,51 +2984,51 @@
     case 25:
         switch (sel) {
         case 0:
-           gen_op_mtc0_performance0();
-           rn = "Performance0";
-           break;
+            gen_op_mtc0_performance0();
+            rn = "Performance0";
+            break;
         case 1:
-//         gen_op_mtc0_performance1();
-           rn = "Performance1";
-//         break;
+//            gen_op_mtc0_performance1();
+            rn = "Performance1";
+//            break;
         case 2:
-//         gen_op_mtc0_performance2();
-           rn = "Performance2";
-//         break;
+//            gen_op_mtc0_performance2();
+            rn = "Performance2";
+//            break;
         case 3:
-//         gen_op_mtc0_performance3();
-           rn = "Performance3";
-//         break;
+//            gen_op_mtc0_performance3();
+            rn = "Performance3";
+//            break;
         case 4:
-//         gen_op_mtc0_performance4();
-           rn = "Performance4";
-//         break;
+//            gen_op_mtc0_performance4();
+            rn = "Performance4";
+//            break;
         case 5:
-//         gen_op_mtc0_performance5();
-           rn = "Performance5";
-//         break;
+//            gen_op_mtc0_performance5();
+            rn = "Performance5";
+//            break;
         case 6:
-//         gen_op_mtc0_performance6();
-           rn = "Performance6";
-//         break;
+//            gen_op_mtc0_performance6();
+            rn = "Performance6";
+//            break;
         case 7:
-//         gen_op_mtc0_performance7();
-           rn = "Performance7";
-//         break;
+//            gen_op_mtc0_performance7();
+            rn = "Performance7";
+//            break;
         default:
             goto die;
         }
        break;
     case 26:
-       /* ignored */
+        /* ignored */
         rn = "ECC";
-       break;
+        break;
     case 27:
         switch (sel) {
         case 0 ... 3:
-           /* ignored */
-           rn = "CacheErr";
-           break;
+            /* ignored */
+            rn = "CacheErr";
+            break;
         default:
             goto die;
         }
@@ -2756,7 +3046,7 @@
         case 3:
         case 5:
         case 7:
-           gen_op_mtc0_datalo();
+            gen_op_mtc0_datalo();
             rn = "DataLo";
             break;
         default:
@@ -2776,7 +3066,7 @@
         case 3:
         case 5:
         case 7:
-           gen_op_mtc0_datahi();
+            gen_op_mtc0_datahi();
             rn = "DataHi";
             break;
         default:
@@ -2787,9 +3077,9 @@
     case 30:
         switch (sel) {
         case 0:
-           gen_op_mtc0_errorepc();
-           rn = "ErrorEPC";
-           break;
+            gen_op_mtc0_errorepc();
+            rn = "ErrorEPC";
+            break;
         default:
             goto die;
         }
@@ -2797,14 +3087,14 @@
     case 31:
         switch (sel) {
         case 0:
-           gen_op_mtc0_desave(); /* EJTAG support */
-           rn = "DESAVE";
-           break;
+            gen_op_mtc0_desave(); /* EJTAG support */
+            rn = "DESAVE";
+            break;
         default:
             goto die;
         }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
         break;
     default:
        goto die;
@@ -2827,29 +3117,36 @@
     generate_exception(ctx, EXCP_RI);
 }
 
-static void gen_dmfc0 (DisasContext *ctx, int reg, int sel)
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+static void gen_dmfc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
 {
     const char *rn = "invalid";
 
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS64);
+
     switch (reg) {
     case 0:
         switch (sel) {
         case 0:
-           gen_op_mfc0_index();
+            gen_op_mfc0_index();
             rn = "Index";
             break;
         case 1:
-//         gen_op_dmfc0_mvpcontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpcontrol();
             rn = "MVPControl";
-//         break;
+            break;
         case 2:
-//         gen_op_dmfc0_mvpconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpconf0();
             rn = "MVPConf0";
-//         break;
+            break;
         case 3:
-//         gen_op_dmfc0_mvpconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_mvpconf1();
             rn = "MVPConf1";
-//         break;
+            break;
         default:
             goto die;
         }
@@ -2859,35 +3156,42 @@
         case 0:
             gen_op_mfc0_random();
             rn = "Random";
-           break;
+            break;
         case 1:
-//         gen_op_dmfc0_vpecontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpecontrol();
             rn = "VPEControl";
-//         break;
+            break;
         case 2:
-//         gen_op_dmfc0_vpeconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeconf0();
             rn = "VPEConf0";
-//         break;
+            break;
         case 3:
-//         gen_op_dmfc0_vpeconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeconf1();
             rn = "VPEConf1";
-//         break;
+            break;
         case 4:
-//         gen_op_dmfc0_YQMask(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_yqmask();
             rn = "YQMask";
-//         break;
+            break;
         case 5:
-//         gen_op_dmfc0_vpeschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_vpeschedule();
             rn = "VPESchedule";
-//         break;
+            break;
         case 6:
-//         gen_op_dmfc0_vpeschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_vpeschefback();
             rn = "VPEScheFBack";
-//         break;
+            break;
         case 7:
-//         gen_op_dmfc0_vpeopt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_vpeopt();
             rn = "VPEOpt";
-//         break;
+            break;
         default:
             goto die;
         }
@@ -2895,37 +3199,44 @@
     case 2:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_entrylo0();
-           rn = "EntryLo0";
-           break;
+            gen_op_dmfc0_entrylo0();
+            rn = "EntryLo0";
+            break;
         case 1:
-//         gen_op_dmfc0_tcstatus(); /* MT ASE */
-           rn = "TCStatus";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcstatus();
+            rn = "TCStatus";
+            break;
         case 2:
-//         gen_op_dmfc0_tcbind(); /* MT ASE */
-           rn = "TCBind";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mfc0_tcbind();
+            rn = "TCBind";
+            break;
         case 3:
-//         gen_op_dmfc0_tcrestart(); /* MT ASE */
-           rn = "TCRestart";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tcrestart();
+            rn = "TCRestart";
+            break;
         case 4:
-//         gen_op_dmfc0_tchalt(); /* MT ASE */
-           rn = "TCHalt";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tchalt();
+            rn = "TCHalt";
+            break;
         case 5:
-//         gen_op_dmfc0_tccontext(); /* MT ASE */
-           rn = "TCContext";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tccontext();
+            rn = "TCContext";
+            break;
         case 6:
-//         gen_op_dmfc0_tcschedule(); /* MT ASE */
-           rn = "TCSchedule";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tcschedule();
+            rn = "TCSchedule";
+            break;
         case 7:
-//         gen_op_dmfc0_tcschefback(); /* MT ASE */
-           rn = "TCScheFBack";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_dmfc0_tcschefback();
+            rn = "TCScheFBack";
+            break;
         default:
             goto die;
         }
@@ -2933,195 +3244,206 @@
     case 3:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_entrylo1();
-           rn = "EntryLo1";
-           break;
+            gen_op_dmfc0_entrylo1();
+            rn = "EntryLo1";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 4:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_context();
-           rn = "Context";
-           break;
+            gen_op_dmfc0_context();
+            rn = "Context";
+            break;
         case 1:
-//         gen_op_dmfc0_contextconfig(); /* SmartMIPS ASE */
-           rn = "ContextConfig";
-//         break;
+//            gen_op_dmfc0_contextconfig(); /* SmartMIPS ASE */
+            rn = "ContextConfig";
+//            break;
         default:
             goto die;
-       }
+        }
         break;
     case 5:
         switch (sel) {
         case 0:
-           gen_op_mfc0_pagemask();
-           rn = "PageMask";
-           break;
+            gen_op_mfc0_pagemask();
+            rn = "PageMask";
+            break;
         case 1:
-           gen_op_mfc0_pagegrain();
-           rn = "PageGrain";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_pagegrain();
+            rn = "PageGrain";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 6:
         switch (sel) {
         case 0:
-           gen_op_mfc0_wired();
-           rn = "Wired";
-           break;
+            gen_op_mfc0_wired();
+            rn = "Wired";
+            break;
         case 1:
-//         gen_op_dmfc0_srsconf0(); /* shadow registers */
-           rn = "SRSConf0";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf0();
+            rn = "SRSConf0";
+            break;
         case 2:
-//         gen_op_dmfc0_srsconf1(); /* shadow registers */
-           rn = "SRSConf1";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf1();
+            rn = "SRSConf1";
+            break;
         case 3:
-//         gen_op_dmfc0_srsconf2(); /* shadow registers */
-           rn = "SRSConf2";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf2();
+            rn = "SRSConf2";
+            break;
         case 4:
-//         gen_op_dmfc0_srsconf3(); /* shadow registers */
-           rn = "SRSConf3";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf3();
+            rn = "SRSConf3";
+            break;
         case 5:
-//         gen_op_dmfc0_srsconf4(); /* shadow registers */
-           rn = "SRSConf4";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsconf4();
+            rn = "SRSConf4";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 7:
         switch (sel) {
         case 0:
-           gen_op_mfc0_hwrena();
-           rn = "HWREna";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_hwrena();
+            rn = "HWREna";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 8:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_badvaddr();
-           rn = "BadVaddr";
-           break;
+            gen_op_dmfc0_badvaddr();
+            rn = "BadVaddr";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 9:
         switch (sel) {
         case 0:
-           gen_op_mfc0_count();
-           rn = "Count";
-           break;
-       /* 6,7 are implementation dependent */
+            gen_op_mfc0_count();
+            rn = "Count";
+            break;
+        /* 6,7 are implementation dependent */
         default:
             goto die;
-       }
+        }
         break;
     case 10:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_entryhi();
-           rn = "EntryHi";
-           break;
+            gen_op_dmfc0_entryhi();
+            rn = "EntryHi";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 11:
         switch (sel) {
         case 0:
-           gen_op_mfc0_compare();
-           rn = "Compare";
-           break;
-       /* 6,7 are implementation dependent */
+            gen_op_mfc0_compare();
+            rn = "Compare";
+            break;
+        /* 6,7 are implementation dependent */
         default:
             goto die;
-       }
+        }
         break;
     case 12:
         switch (sel) {
         case 0:
-           gen_op_mfc0_status();
-           rn = "Status";
-           break;
+            gen_op_mfc0_status();
+            rn = "Status";
+            break;
         case 1:
-           gen_op_mfc0_intctl();
-           rn = "IntCtl";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_intctl();
+            rn = "IntCtl";
+            break;
         case 2:
-           gen_op_mfc0_srsctl();
-           rn = "SRSCtl";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsctl();
+            rn = "SRSCtl";
+            break;
         case 3:
-           gen_op_mfc0_srsmap(); /* shadow registers */
-           rn = "SRSMap";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_srsmap();
+            rn = "SRSMap";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 13:
         switch (sel) {
         case 0:
-           gen_op_mfc0_cause();
-           rn = "Cause";
-           break;
+            gen_op_mfc0_cause();
+            rn = "Cause";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 14:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_epc();
-           rn = "EPC";
-           break;
+            gen_op_dmfc0_epc();
+            rn = "EPC";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 15:
         switch (sel) {
         case 0:
-           gen_op_mfc0_prid();
-           rn = "PRid";
-           break;
+            gen_op_mfc0_prid();
+            rn = "PRid";
+            break;
         case 1:
-           gen_op_mfc0_ebase();
-           rn = "EBase";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mfc0_ebase();
+            rn = "EBase";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 16:
         switch (sel) {
         case 0:
-           gen_op_mfc0_config0();
+            gen_op_mfc0_config0();
             rn = "Config";
             break;
         case 1:
-           gen_op_mfc0_config1();
+            gen_op_mfc0_config1();
             rn = "Config1";
             break;
         case 2:
-           gen_op_mfc0_config2();
+            gen_op_mfc0_config2();
             rn = "Config2";
             break;
         case 3:
-           gen_op_mfc0_config3();
+            gen_op_mfc0_config3();
             rn = "Config3";
             break;
        /* 6,7 are implementation dependent */
@@ -3132,85 +3454,29 @@
     case 17:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_lladdr();
-           rn = "LLAddr";
-           break;
+            gen_op_dmfc0_lladdr();
+            rn = "LLAddr";
+            break;
         default:
             goto die;
         }
         break;
     case 18:
         switch (sel) {
-        case 0:
-           gen_op_dmfc0_watchlo0();
-           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;
+        case 0 ... 7:
+            gen_op_dmfc0_watchlo(sel);
+            rn = "WatchLo";
+            break;
         default:
             goto die;
         }
         break;
     case 19:
         switch (sel) {
-        case 0:
-           gen_op_mfc0_watchhi0();
-           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;
+        case 0 ... 7:
+            gen_op_mfc0_watchhi(sel);
+            rn = "WatchHi";
+            break;
         default:
             goto die;
         }
@@ -3218,10 +3484,10 @@
     case 20:
         switch (sel) {
         case 0:
-           /* 64 bit MMU only */
-           gen_op_dmfc0_xcontext();
-           rn = "XContext";
-           break;
+            check_insn(env, ctx, ISA_MIPS3);
+            gen_op_dmfc0_xcontext();
+            rn = "XContext";
+            break;
         default:
             goto die;
         }
@@ -3230,39 +3496,39 @@
        /* Officially reserved, but sel 0 is used for R1x000 framemask */
         switch (sel) {
         case 0:
-           gen_op_mfc0_framemask();
-           rn = "Framemask";
-           break;
+            gen_op_mfc0_framemask();
+            rn = "Framemask";
+            break;
         default:
             goto die;
         }
         break;
     case 22:
-       /* ignored */
-       rn = "'Diagnostic"; /* implementation dependent */
-       break;
+        /* ignored */
+        rn = "'Diagnostic"; /* implementation dependent */
+        break;
     case 23:
         switch (sel) {
         case 0:
-           gen_op_mfc0_debug(); /* EJTAG support */
-           rn = "Debug";
-           break;
+            gen_op_mfc0_debug(); /* EJTAG support */
+            rn = "Debug";
+            break;
         case 1:
-//         gen_op_dmfc0_tracecontrol(); /* PDtrace support */
-           rn = "TraceControl";
-//         break;
+//            gen_op_dmfc0_tracecontrol(); /* PDtrace support */
+            rn = "TraceControl";
+//            break;
         case 2:
-//         gen_op_dmfc0_tracecontrol2(); /* PDtrace support */
-           rn = "TraceControl2";
-//         break;
+//            gen_op_dmfc0_tracecontrol2(); /* PDtrace support */
+            rn = "TraceControl2";
+//            break;
         case 3:
-//         gen_op_dmfc0_usertracedata(); /* PDtrace support */
-           rn = "UserTraceData";
-//         break;
+//            gen_op_dmfc0_usertracedata(); /* PDtrace support */
+            rn = "UserTraceData";
+//            break;
         case 4:
-//         gen_op_dmfc0_debug(); /* PDtrace support */
-           rn = "TraceBPC";
-//         break;
+//            gen_op_dmfc0_debug(); /* PDtrace support */
+            rn = "TraceBPC";
+//            break;
         default:
             goto die;
         }
@@ -3270,9 +3536,9 @@
     case 24:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_depc(); /* EJTAG support */
-           rn = "DEPC";
-           break;
+            gen_op_dmfc0_depc(); /* EJTAG support */
+            rn = "DEPC";
+            break;
         default:
             goto die;
         }
@@ -3280,37 +3546,37 @@
     case 25:
         switch (sel) {
         case 0:
-           gen_op_mfc0_performance0();
-           rn = "Performance0";
+            gen_op_mfc0_performance0();
+            rn = "Performance0";
             break;
         case 1:
-//         gen_op_dmfc0_performance1();
-           rn = "Performance1";
-//         break;
+//            gen_op_dmfc0_performance1();
+            rn = "Performance1";
+//            break;
         case 2:
-//         gen_op_dmfc0_performance2();
-           rn = "Performance2";
-//         break;
+//            gen_op_dmfc0_performance2();
+            rn = "Performance2";
+//            break;
         case 3:
-//         gen_op_dmfc0_performance3();
-           rn = "Performance3";
-//         break;
+//            gen_op_dmfc0_performance3();
+            rn = "Performance3";
+//            break;
         case 4:
-//         gen_op_dmfc0_performance4();
-           rn = "Performance4";
-//         break;
+//            gen_op_dmfc0_performance4();
+            rn = "Performance4";
+//            break;
         case 5:
-//         gen_op_dmfc0_performance5();
-           rn = "Performance5";
-//         break;
+//            gen_op_dmfc0_performance5();
+            rn = "Performance5";
+//            break;
         case 6:
-//         gen_op_dmfc0_performance6();
-           rn = "Performance6";
-//         break;
+//            gen_op_dmfc0_performance6();
+            rn = "Performance6";
+//            break;
         case 7:
-//         gen_op_dmfc0_performance7();
-           rn = "Performance7";
-//         break;
+//            gen_op_dmfc0_performance7();
+            rn = "Performance7";
+//            break;
         default:
             goto die;
         }
@@ -3322,8 +3588,8 @@
         switch (sel) {
         /* ignored */
         case 0 ... 3:
-           rn = "CacheErr";
-           break;
+            rn = "CacheErr";
+            break;
         default:
             goto die;
         }
@@ -3371,9 +3637,9 @@
     case 30:
         switch (sel) {
         case 0:
-           gen_op_dmfc0_errorepc();
-           rn = "ErrorEPC";
-           break;
+            gen_op_dmfc0_errorepc();
+            rn = "ErrorEPC";
+            break;
         default:
             goto die;
         }
@@ -3381,15 +3647,15 @@
     case 31:
         switch (sel) {
         case 0:
-           gen_op_mfc0_desave(); /* EJTAG support */
-           rn = "DESAVE";
-           break;
+            gen_op_mfc0_desave(); /* EJTAG support */
+            rn = "DESAVE";
+            break;
         default:
             goto die;
         }
         break;
     default:
-       goto die;
+        goto die;
     }
 #if defined MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
@@ -3409,10 +3675,13 @@
     generate_exception(ctx, EXCP_RI);
 }
 
-static void gen_dmtc0 (DisasContext *ctx, int reg, int sel)
+static void gen_dmtc0 (CPUState *env, DisasContext *ctx, int reg, int sel)
 {
     const char *rn = "invalid";
 
+    if (sel != 0)
+        check_insn(env, ctx, ISA_MIPS64);
+
     switch (reg) {
     case 0:
         switch (sel) {
@@ -3421,17 +3690,20 @@
             rn = "Index";
             break;
         case 1:
-//         gen_op_dmtc0_mvpcontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_mvpcontrol();
             rn = "MVPControl";
-//         break;
+            break;
         case 2:
-//         gen_op_dmtc0_mvpconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            /* ignored */
             rn = "MVPConf0";
-//         break;
+            break;
         case 3:
-//         gen_op_dmtc0_mvpconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            /* ignored */
             rn = "MVPConf1";
-//         break;
+            break;
         default:
             goto die;
         }
@@ -3439,37 +3711,44 @@
     case 1:
         switch (sel) {
         case 0:
-           /* ignored */
+            /* ignored */
             rn = "Random";
-           break;
+            break;
         case 1:
-//         gen_op_dmtc0_vpecontrol(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpecontrol();
             rn = "VPEControl";
-//         break;
+            break;
         case 2:
-//         gen_op_dmtc0_vpeconf0(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeconf0();
             rn = "VPEConf0";
-//         break;
+            break;
         case 3:
-//         gen_op_dmtc0_vpeconf1(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeconf1();
             rn = "VPEConf1";
-//         break;
+            break;
         case 4:
-//         gen_op_dmtc0_YQMask(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_yqmask();
             rn = "YQMask";
-//         break;
+            break;
         case 5:
-//         gen_op_dmtc0_vpeschedule(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeschedule();
             rn = "VPESchedule";
-//         break;
+            break;
         case 6:
-//         gen_op_dmtc0_vpeschefback(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeschefback();
             rn = "VPEScheFBack";
-//         break;
+            break;
         case 7:
-//         gen_op_dmtc0_vpeopt(); /* MT ASE */
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_vpeopt();
             rn = "VPEOpt";
-//         break;
+            break;
         default:
             goto die;
         }
@@ -3477,37 +3756,44 @@
     case 2:
         switch (sel) {
         case 0:
-           gen_op_dmtc0_entrylo0();
-           rn = "EntryLo0";
-           break;
+            gen_op_mtc0_entrylo0();
+            rn = "EntryLo0";
+            break;
         case 1:
-//         gen_op_dmtc0_tcstatus(); /* MT ASE */
-           rn = "TCStatus";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcstatus();
+            rn = "TCStatus";
+            break;
         case 2:
-//         gen_op_dmtc0_tcbind(); /* MT ASE */
-           rn = "TCBind";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcbind();
+            rn = "TCBind";
+            break;
         case 3:
-//         gen_op_dmtc0_tcrestart(); /* MT ASE */
-           rn = "TCRestart";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcrestart();
+            rn = "TCRestart";
+            break;
         case 4:
-//         gen_op_dmtc0_tchalt(); /* MT ASE */
-           rn = "TCHalt";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tchalt();
+            rn = "TCHalt";
+            break;
         case 5:
-//         gen_op_dmtc0_tccontext(); /* MT ASE */
-           rn = "TCContext";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tccontext();
+            rn = "TCContext";
+            break;
         case 6:
-//         gen_op_dmtc0_tcschedule(); /* MT ASE */
-           rn = "TCSchedule";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcschedule();
+            rn = "TCSchedule";
+            break;
         case 7:
-//         gen_op_dmtc0_tcschefback(); /* MT ASE */
-           rn = "TCScheFBack";
-//         break;
+            check_mips_mt(env, ctx);
+            gen_op_mtc0_tcschefback();
+            rn = "TCScheFBack";
+            break;
         default:
             goto die;
         }
@@ -3515,80 +3801,87 @@
     case 3:
         switch (sel) {
         case 0:
-           gen_op_dmtc0_entrylo1();
-           rn = "EntryLo1";
-           break;
+            gen_op_mtc0_entrylo1();
+            rn = "EntryLo1";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 4:
         switch (sel) {
         case 0:
-           gen_op_dmtc0_context();
-           rn = "Context";
-           break;
+            gen_op_mtc0_context();
+            rn = "Context";
+            break;
         case 1:
-//         gen_op_dmtc0_contextconfig(); /* SmartMIPS ASE */
-           rn = "ContextConfig";
-//         break;
+//           gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */
+            rn = "ContextConfig";
+//           break;
         default:
             goto die;
-       }
+        }
         break;
     case 5:
         switch (sel) {
         case 0:
-           gen_op_mtc0_pagemask();
-           rn = "PageMask";
-           break;
+            gen_op_mtc0_pagemask();
+            rn = "PageMask";
+            break;
         case 1:
-           gen_op_mtc0_pagegrain();
-           rn = "PageGrain";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_pagegrain();
+            rn = "PageGrain";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 6:
         switch (sel) {
         case 0:
-           gen_op_mtc0_wired();
-           rn = "Wired";
-           break;
+            gen_op_mtc0_wired();
+            rn = "Wired";
+            break;
         case 1:
-//         gen_op_dmtc0_srsconf0(); /* shadow registers */
-           rn = "SRSConf0";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf0();
+            rn = "SRSConf0";
+            break;
         case 2:
-//         gen_op_dmtc0_srsconf1(); /* shadow registers */
-           rn = "SRSConf1";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf1();
+            rn = "SRSConf1";
+            break;
         case 3:
-//         gen_op_dmtc0_srsconf2(); /* shadow registers */
-           rn = "SRSConf2";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf2();
+            rn = "SRSConf2";
+            break;
         case 4:
-//         gen_op_dmtc0_srsconf3(); /* shadow registers */
-           rn = "SRSConf3";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf3();
+            rn = "SRSConf3";
+            break;
         case 5:
-//         gen_op_dmtc0_srsconf4(); /* shadow registers */
-           rn = "SRSConf4";
-//         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsconf4();
+            rn = "SRSConf4";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 7:
         switch (sel) {
         case 0:
-           gen_op_mtc0_hwrena();
-           rn = "HWREna";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_hwrena();
+            rn = "HWREna";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 8:
         /* ignored */
@@ -3597,115 +3890,130 @@
     case 9:
         switch (sel) {
         case 0:
-           gen_op_mtc0_count();
-           rn = "Count";
-           break;
-       /* 6,7 are implementation dependent */
+            gen_op_mtc0_count();
+            rn = "Count";
+            break;
+        /* 6,7 are implementation dependent */
         default:
             goto die;
-       }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
         break;
     case 10:
         switch (sel) {
         case 0:
-           gen_op_mtc0_entryhi();
-           rn = "EntryHi";
-           break;
+            gen_op_mtc0_entryhi();
+            rn = "EntryHi";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 11:
         switch (sel) {
         case 0:
-           gen_op_mtc0_compare();
-           rn = "Compare";
-           break;
-       /* 6,7 are implementation dependent */
+            gen_op_mtc0_compare();
+            rn = "Compare";
+            break;
+        /* 6,7 are implementation dependent */
         default:
             goto die;
-       }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
         break;
     case 12:
         switch (sel) {
         case 0:
-           gen_op_mtc0_status();
-           rn = "Status";
-           break;
+            gen_op_mtc0_status();
+            /* BS_STOP isn't good enough here, hflags may have changed. */
+            gen_save_pc(ctx->pc + 4);
+            ctx->bstate = BS_EXCP;
+            rn = "Status";
+            break;
         case 1:
-           gen_op_mtc0_intctl();
-           rn = "IntCtl";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_intctl();
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "IntCtl";
+            break;
         case 2:
-           gen_op_mtc0_srsctl();
-           rn = "SRSCtl";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsctl();
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "SRSCtl";
+            break;
         case 3:
-         gen_op_mtc0_srsmap(); /* shadow registers */
-           rn = "SRSMap";
-         break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_srsmap();
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "SRSMap";
+            break;
         default:
             goto die;
-       }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        }
         break;
     case 13:
         switch (sel) {
         case 0:
-           gen_op_mtc0_cause();
-           rn = "Cause";
-           break;
+            gen_op_mtc0_cause();
+            rn = "Cause";
+            break;
         default:
             goto die;
-       }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        }
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
         break;
     case 14:
         switch (sel) {
         case 0:
-           gen_op_dmtc0_epc();
-           rn = "EPC";
-           break;
+            gen_op_mtc0_epc();
+            rn = "EPC";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 15:
         switch (sel) {
         case 0:
-           /* ignored */
-           rn = "PRid";
-           break;
+            /* ignored */
+            rn = "PRid";
+            break;
         case 1:
-           gen_op_mtc0_ebase();
-           rn = "EBase";
-           break;
+            check_insn(env, ctx, ISA_MIPS32R2);
+            gen_op_mtc0_ebase();
+            rn = "EBase";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 16:
         switch (sel) {
         case 0:
             gen_op_mtc0_config0();
             rn = "Config";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
             break;
         case 1:
-           /* ignored */
+            /* ignored */
             rn = "Config1";
             break;
         case 2:
             gen_op_mtc0_config2();
             rn = "Config2";
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
             break;
         case 3:
-           /* ignored */
+            /* ignored */
             rn = "Config3";
             break;
         /* 6,7 are implementation dependent */
@@ -3713,91 +4021,33 @@
             rn = "Invalid config selector";
             goto die;
         }
-        /* Stop translation as we may have switched the execution mode */
-        ctx->bstate = BS_STOP;
         break;
     case 17:
         switch (sel) {
         case 0:
-           /* ignored */
-           rn = "LLAddr";
-           break;
+            /* ignored */
+            rn = "LLAddr";
+            break;
         default:
             goto die;
         }
         break;
     case 18:
         switch (sel) {
-        case 0:
-           gen_op_dmtc0_watchlo0();
-           rn = "WatchLo";
-           break;
-        case 1:
-//         gen_op_dmtc0_watchlo1();
-           rn = "WatchLo1";
-//         break;
-        case 2:
-//         gen_op_dmtc0_watchlo2();
-           rn = "WatchLo2";
-//         break;
-        case 3:
-//         gen_op_dmtc0_watchlo3();
-           rn = "WatchLo3";
-//         break;
-        case 4:
-//         gen_op_dmtc0_watchlo4();
-           rn = "WatchLo4";
-//         break;
-        case 5:
-//         gen_op_dmtc0_watchlo5();
-           rn = "WatchLo5";
-//         break;
-        case 6:
-//         gen_op_dmtc0_watchlo6();
-           rn = "WatchLo6";
-//         break;
-        case 7:
-//         gen_op_dmtc0_watchlo7();
-           rn = "WatchLo7";
-//         break;
+        case 0 ... 7:
+            gen_op_mtc0_watchlo(sel);
+            rn = "WatchLo";
+            break;
         default:
             goto die;
         }
         break;
     case 19:
         switch (sel) {
-        case 0:
-           gen_op_mtc0_watchhi0();
-           rn = "WatchHi";
-           break;
-        case 1:
-//         gen_op_dmtc0_watchhi1();
-           rn = "WatchHi1";
-//         break;
-        case 2:
-//         gen_op_dmtc0_watchhi2();
-           rn = "WatchHi2";
-//         break;
-        case 3:
-//         gen_op_dmtc0_watchhi3();
-           rn = "WatchHi3";
-//         break;
-        case 4:
-//         gen_op_dmtc0_watchhi4();
-           rn = "WatchHi4";
-//         break;
-        case 5:
-//         gen_op_dmtc0_watchhi5();
-           rn = "WatchHi5";
-//         break;
-        case 6:
-//         gen_op_dmtc0_watchhi6();
-           rn = "WatchHi6";
-//         break;
-        case 7:
-//         gen_op_dmtc0_watchhi7();
-           rn = "WatchHi7";
-//         break;
+        case 0 ... 7:
+            gen_op_mtc0_watchhi(sel);
+            rn = "WatchHi";
+            break;
         default:
             goto die;
         }
@@ -3805,10 +4055,10 @@
     case 20:
         switch (sel) {
         case 0:
-           /* 64 bit MMU only */
-           gen_op_dmtc0_xcontext();
-           rn = "XContext";
-           break;
+            check_insn(env, ctx, ISA_MIPS3);
+            gen_op_mtc0_xcontext();
+            rn = "XContext";
+            break;
         default:
             goto die;
         }
@@ -3817,9 +4067,9 @@
        /* Officially reserved, but sel 0 is used for R1x000 framemask */
         switch (sel) {
         case 0:
-           gen_op_mtc0_framemask();
-           rn = "Framemask";
-           break;
+            gen_op_mtc0_framemask();
+            rn = "Framemask";
+            break;
         default:
             goto die;
         }
@@ -3827,41 +4077,50 @@
     case 22:
         /* ignored */
         rn = "Diagnostic"; /* implementation dependent */
-       break;
+        break;
     case 23:
         switch (sel) {
         case 0:
-           gen_op_mtc0_debug(); /* EJTAG support */
-           rn = "Debug";
-           break;
+            gen_op_mtc0_debug(); /* EJTAG support */
+            /* BS_STOP isn't good enough here, hflags may have changed. */
+            gen_save_pc(ctx->pc + 4);
+            ctx->bstate = BS_EXCP;
+            rn = "Debug";
+            break;
         case 1:
-//         gen_op_dmtc0_tracecontrol(); /* PDtrace support */
-           rn = "TraceControl";
-//         break;
+//            gen_op_mtc0_tracecontrol(); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "TraceControl";
+//            break;
         case 2:
-//         gen_op_dmtc0_tracecontrol2(); /* PDtrace support */
-           rn = "TraceControl2";
-//         break;
+//            gen_op_mtc0_tracecontrol2(); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "TraceControl2";
+//            break;
         case 3:
-//         gen_op_dmtc0_usertracedata(); /* PDtrace support */
-           rn = "UserTraceData";
-//         break;
+//            gen_op_mtc0_usertracedata(); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "UserTraceData";
+//            break;
         case 4:
-//         gen_op_dmtc0_debug(); /* PDtrace support */
-           rn = "TraceBPC";
-//         break;
+//            gen_op_mtc0_debug(); /* PDtrace support */
+            /* Stop translation as we may have switched the execution mode */
+            ctx->bstate = BS_STOP;
+            rn = "TraceBPC";
+//            break;
         default:
             goto die;
         }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
         break;
     case 24:
         switch (sel) {
         case 0:
-           gen_op_dmtc0_depc(); /* EJTAG support */
-           rn = "DEPC";
-           break;
+            gen_op_mtc0_depc(); /* EJTAG support */
+            rn = "DEPC";
+            break;
         default:
             goto die;
         }
@@ -3869,55 +4128,55 @@
     case 25:
         switch (sel) {
         case 0:
-           gen_op_mtc0_performance0();
-           rn = "Performance0";
-           break;
+            gen_op_mtc0_performance0();
+            rn = "Performance0";
+            break;
         case 1:
-//         gen_op_dmtc0_performance1();
-           rn = "Performance1";
-//         break;
+//            gen_op_mtc0_performance1();
+            rn = "Performance1";
+//            break;
         case 2:
-//         gen_op_dmtc0_performance2();
-           rn = "Performance2";
-//         break;
+//            gen_op_mtc0_performance2();
+            rn = "Performance2";
+//            break;
         case 3:
-//         gen_op_dmtc0_performance3();
-           rn = "Performance3";
-//         break;
+//            gen_op_mtc0_performance3();
+            rn = "Performance3";
+//            break;
         case 4:
-//         gen_op_dmtc0_performance4();
-           rn = "Performance4";
-//         break;
+//            gen_op_mtc0_performance4();
+            rn = "Performance4";
+//            break;
         case 5:
-//         gen_op_dmtc0_performance5();
-           rn = "Performance5";
-//         break;
+//            gen_op_mtc0_performance5();
+            rn = "Performance5";
+//            break;
         case 6:
-//         gen_op_dmtc0_performance6();
-           rn = "Performance6";
-//         break;
+//            gen_op_mtc0_performance6();
+            rn = "Performance6";
+//            break;
         case 7:
-//         gen_op_dmtc0_performance7();
-           rn = "Performance7";
-//         break;
+//            gen_op_mtc0_performance7();
+            rn = "Performance7";
+//            break;
         default:
             goto die;
         }
-       break;
+        break;
     case 26:
-       /* ignored */
+        /* ignored */
         rn = "ECC";
-       break;
+        break;
     case 27:
         switch (sel) {
         case 0 ... 3:
-           /* ignored */
-           rn = "CacheErr";
-           break;
+            /* ignored */
+            rn = "CacheErr";
+            break;
         default:
             goto die;
         }
-       break;
+        break;
     case 28:
         switch (sel) {
         case 0:
@@ -3931,7 +4190,7 @@
         case 3:
         case 5:
         case 7:
-           gen_op_mtc0_datalo();
+            gen_op_mtc0_datalo();
             rn = "DataLo";
             break;
         default:
@@ -3951,20 +4210,20 @@
         case 3:
         case 5:
         case 7:
-           gen_op_mtc0_datahi();
+            gen_op_mtc0_datahi();
             rn = "DataHi";
             break;
         default:
             rn = "invalid sel";
             goto die;
         }
-       break;
+        break;
     case 30:
         switch (sel) {
         case 0:
-           gen_op_dmtc0_errorepc();
-           rn = "ErrorEPC";
-           break;
+            gen_op_mtc0_errorepc();
+            rn = "ErrorEPC";
+            break;
         default:
             goto die;
         }
@@ -3972,17 +4231,17 @@
     case 31:
         switch (sel) {
         case 0:
-           gen_op_mtc0_desave(); /* EJTAG support */
-           rn = "DESAVE";
-           break;
+            gen_op_mtc0_desave(); /* EJTAG support */
+            rn = "DESAVE";
+            break;
         default:
             goto die;
         }
-       /* Stop translation as we may have switched the execution mode */
-       ctx->bstate = BS_STOP;
+        /* Stop translation as we may have switched the execution mode */
+        ctx->bstate = BS_STOP;
         break;
     default:
-       goto die;
+        goto die;
     }
 #if defined MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
@@ -4001,97 +4260,439 @@
 #endif
     generate_exception(ctx, EXCP_RI);
 }
+#endif /* TARGET_MIPSN32 || TARGET_MIPS64 */
 
-static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd)
+static void gen_mftr(CPUState *env, DisasContext *ctx, int rt,
+                     int u, int sel, int h)
 {
-    const char *opn = "unk";
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
 
-    if ((!ctx->CP0_Status & (1 << CP0St_CU0) &&
-          (ctx->hflags & MIPS_HFLAG_UM)) &&
-        !(ctx->hflags & MIPS_HFLAG_ERL) &&
-        !(ctx->hflags & MIPS_HFLAG_EXL)) {
-        if (loglevel & CPU_LOG_TB_IN_ASM) {
-            fprintf(logfile, "CP0 is not usable\n");
+    if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
+        ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) !=
+         (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE))))
+        gen_op_set_T0(-1);
+    else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
+             (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
+        gen_op_set_T0(-1);
+    else if (u == 0) {
+        switch (rt) {
+        case 2:
+            switch (sel) {
+            case 1:
+                gen_op_mftc0_tcstatus();
+                break;
+            case 2:
+                gen_op_mftc0_tcbind();
+                break;
+            case 3:
+                gen_op_mftc0_tcrestart();
+                break;
+            case 4:
+                gen_op_mftc0_tchalt();
+                break;
+            case 5:
+                gen_op_mftc0_tccontext();
+                break;
+            case 6:
+                gen_op_mftc0_tcschedule();
+                break;
+            case 7:
+                gen_op_mftc0_tcschefback();
+                break;
+            default:
+                gen_mfc0(env, ctx, rt, sel);
+                break;
+            }
+            break;
+        case 10:
+            switch (sel) {
+            case 0:
+                gen_op_mftc0_entryhi();
+                break;
+            default:
+                gen_mfc0(env, ctx, rt, sel);
+                break;
+            }
+        case 12:
+            switch (sel) {
+            case 0:
+                gen_op_mftc0_status();
+                break;
+            default:
+                gen_mfc0(env, ctx, rt, sel);
+                break;
+            }
+        case 23:
+            switch (sel) {
+            case 0:
+                gen_op_mftc0_debug();
+                break;
+            default:
+                gen_mfc0(env, ctx, rt, sel);
+                break;
+            }
+            break;
+        default:
+            gen_mfc0(env, ctx, rt, sel);
         }
-        generate_exception (ctx, EXCP_CpU);
-        return;
+    } else switch (sel) {
+    /* GPR registers. */
+    case 0:
+        gen_op_mftgpr(rt);
+        break;
+    /* Auxiliary CPU registers */
+    case 1:
+        switch (rt) {
+        case 0:
+            gen_op_mftlo(0);
+            break;
+        case 1:
+            gen_op_mfthi(0);
+            break;
+        case 2:
+            gen_op_mftacx(0);
+            break;
+        case 4:
+            gen_op_mftlo(1);
+            break;
+        case 5:
+            gen_op_mfthi(1);
+            break;
+        case 6:
+            gen_op_mftacx(1);
+            break;
+        case 8:
+            gen_op_mftlo(2);
+            break;
+        case 9:
+            gen_op_mfthi(2);
+            break;
+        case 10:
+            gen_op_mftacx(2);
+            break;
+        case 12:
+            gen_op_mftlo(3);
+            break;
+        case 13:
+            gen_op_mfthi(3);
+            break;
+        case 14:
+            gen_op_mftacx(3);
+            break;
+        case 16:
+            gen_op_mftdsp();
+            break;
+        default:
+            goto die;
+        }
+        break;
+    /* Floating point (COP1). */
+    case 2:
+        /* XXX: For now we support only a single FPU context. */
+        if (h == 0) {
+            GEN_LOAD_FREG_FTN(WT0, rt);
+            gen_op_mfc1();
+        } else {
+            GEN_LOAD_FREG_FTN(WTH0, rt);
+            gen_op_mfhc1();
+        }
+        break;
+    case 3:
+        /* XXX: For now we support only a single FPU context. */
+        gen_op_cfc1(rt);
+        break;
+    /* COP2: Not implemented. */
+    case 4:
+    case 5:
+        /* fall through */
+    default:
+        goto die;
     }
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n",
+                rt, u, sel, h);
+    }
+#endif
+    return;
+
+die:
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "mftr (reg %d u %d sel %d h %d)\n",
+                rt, u, sel, h);
+    }
+#endif
+    generate_exception(ctx, EXCP_RI);
+}
+
+static void gen_mttr(CPUState *env, DisasContext *ctx, int rd,
+                     int u, int sel, int h)
+{
+    int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC);
+
+    if ((env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) == 0 &&
+        ((env->CP0_TCBind[other_tc] & (0xf << CP0TCBd_CurVPE)) !=
+         (env->CP0_TCBind[env->current_tc] & (0xf << CP0TCBd_CurVPE))))
+        /* NOP */ ;
+    else if ((env->CP0_VPEControl & (0xff << CP0VPECo_TargTC)) >
+             (env->mvp->CP0_MVPConf0 & (0xff << CP0MVPC0_PTC)))
+        /* NOP */ ;
+    else if (u == 0) {
+        switch (rd) {
+        case 2:
+            switch (sel) {
+            case 1:
+                gen_op_mttc0_tcstatus();
+                break;
+            case 2:
+                gen_op_mttc0_tcbind();
+                break;
+            case 3:
+                gen_op_mttc0_tcrestart();
+                break;
+            case 4:
+                gen_op_mttc0_tchalt();
+                break;
+            case 5:
+                gen_op_mttc0_tccontext();
+                break;
+            case 6:
+                gen_op_mttc0_tcschedule();
+                break;
+            case 7:
+                gen_op_mttc0_tcschefback();
+                break;
+            default:
+                gen_mtc0(env, ctx, rd, sel);
+                break;
+            }
+            break;
+        case 10:
+            switch (sel) {
+            case 0:
+                gen_op_mttc0_entryhi();
+                break;
+            default:
+                gen_mtc0(env, ctx, rd, sel);
+                break;
+            }
+        case 12:
+            switch (sel) {
+            case 0:
+                gen_op_mttc0_status();
+                break;
+            default:
+                gen_mtc0(env, ctx, rd, sel);
+                break;
+            }
+        case 23:
+            switch (sel) {
+            case 0:
+                gen_op_mttc0_debug();
+                break;
+            default:
+                gen_mtc0(env, ctx, rd, sel);
+                break;
+            }
+            break;
+        default:
+            gen_mtc0(env, ctx, rd, sel);
+        }
+    } else switch (sel) {
+    /* GPR registers. */
+    case 0:
+        gen_op_mttgpr(rd);
+        break;
+    /* Auxiliary CPU registers */
+    case 1:
+        switch (rd) {
+        case 0:
+            gen_op_mttlo(0);
+            break;
+        case 1:
+            gen_op_mtthi(0);
+            break;
+        case 2:
+            gen_op_mttacx(0);
+            break;
+        case 4:
+            gen_op_mttlo(1);
+            break;
+        case 5:
+            gen_op_mtthi(1);
+            break;
+        case 6:
+            gen_op_mttacx(1);
+            break;
+        case 8:
+            gen_op_mttlo(2);
+            break;
+        case 9:
+            gen_op_mtthi(2);
+            break;
+        case 10:
+            gen_op_mttacx(2);
+            break;
+        case 12:
+            gen_op_mttlo(3);
+            break;
+        case 13:
+            gen_op_mtthi(3);
+            break;
+        case 14:
+            gen_op_mttacx(3);
+            break;
+        case 16:
+            gen_op_mttdsp();
+            break;
+        default:
+            goto die;
+        }
+        break;
+    /* Floating point (COP1). */
+    case 2:
+        /* XXX: For now we support only a single FPU context. */
+        if (h == 0) {
+            gen_op_mtc1();
+            GEN_STORE_FTN_FREG(rd, WT0);
+        } else {
+            gen_op_mthc1();
+            GEN_STORE_FTN_FREG(rd, WTH0);
+        }
+        break;
+    case 3:
+        /* XXX: For now we support only a single FPU context. */
+        gen_op_ctc1(rd);
+        break;
+    /* COP2: Not implemented. */
+    case 4:
+    case 5:
+        /* fall through */
+    default:
+        goto die;
+    }
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n",
+                rd, u, sel, h);
+    }
+#endif
+    return;
+
+die:
+#if defined MIPS_DEBUG_DISAS
+    if (loglevel & CPU_LOG_TB_IN_ASM) {
+        fprintf(logfile, "mttr (reg %d u %d sel %d h %d)\n",
+                rd, u, sel, h);
+    }
+#endif
+    generate_exception(ctx, EXCP_RI);
+}
+
+static void gen_cp0 (CPUState *env, DisasContext *ctx, uint32_t opc, int rt, int rd)
+{
+    const char *opn = "ldst";
 
     switch (opc) {
     case OPC_MFC0:
         if (rt == 0) {
-            /* Treat as NOP */
+            /* Treat as NOP. */
             return;
         }
-        gen_mfc0(ctx, rd, ctx->opcode & 0x7);
+        gen_mfc0(env, ctx, rd, ctx->opcode & 0x7);
         gen_op_store_T0_gpr(rt);
         opn = "mfc0";
         break;
     case OPC_MTC0:
-        /* If we get an exception, we want to restart at next instruction */
-        /* XXX: breaks for mtc in delay slot */
-        ctx->pc += 4;
-        save_cpu_state(ctx, 1);
-        ctx->pc -= 4;
         GEN_LOAD_REG_TN(T0, rt);
-        gen_mtc0(ctx, rd, ctx->opcode & 0x7);
+        save_cpu_state(ctx, 1);
+        gen_mtc0(env, ctx, rd, ctx->opcode & 0x7);
         opn = "mtc0";
         break;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
     case OPC_DMFC0:
+        check_insn(env, ctx, ISA_MIPS3);
         if (rt == 0) {
-            /* Treat as NOP */
+            /* Treat as NOP. */
             return;
         }
-        gen_dmfc0(ctx, rd, ctx->opcode & 0x7);
+        gen_dmfc0(env, ctx, rd, ctx->opcode & 0x7);
         gen_op_store_T0_gpr(rt);
         opn = "dmfc0";
         break;
     case OPC_DMTC0:
-        /* If we get an exception, we want to restart at next instruction */
-        /* XXX: breaks for dmtc in delay slot */
-        ctx->pc += 4;
-        save_cpu_state(ctx, 1);
-        ctx->pc -= 4;
+        check_insn(env, ctx, ISA_MIPS3);
         GEN_LOAD_REG_TN(T0, rt);
-        gen_dmtc0(ctx, rd, ctx->opcode & 0x7);
+        save_cpu_state(ctx, 1);
+        gen_dmtc0(env, ctx, rd, ctx->opcode & 0x7);
         opn = "dmtc0";
         break;
-#if defined(MIPS_USES_R4K_TLB)
+#endif
+    case OPC_MFTR:
+        check_mips_mt(env, ctx);
+        if (rd == 0) {
+            /* Treat as NOP. */
+            return;
+        }
+        gen_mftr(env, ctx, rt, (ctx->opcode >> 5) & 1,
+                 ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
+        gen_op_store_T0_gpr(rd);
+        opn = "mftr";
+        break;
+    case OPC_MTTR:
+        check_mips_mt(env, ctx);
+        GEN_LOAD_REG_TN(T0, rt);
+        gen_mttr(env, ctx, rd, (ctx->opcode >> 5) & 1,
+                 ctx->opcode & 0x7, (ctx->opcode >> 4) & 1);
+        opn = "mttr";
+        break;
     case OPC_TLBWI:
-        gen_op_tlbwi();
         opn = "tlbwi";
+        if (!env->tlb->do_tlbwi)
+            goto die;
+        gen_op_tlbwi();
         break;
     case OPC_TLBWR:
-        gen_op_tlbwr();
         opn = "tlbwr";
+        if (!env->tlb->do_tlbwr)
+            goto die;
+        gen_op_tlbwr();
         break;
     case OPC_TLBP:
-        gen_op_tlbp();
         opn = "tlbp";
+        if (!env->tlb->do_tlbp)
+            goto die;
+        gen_op_tlbp();
         break;
     case OPC_TLBR:
-        gen_op_tlbr();
         opn = "tlbr";
+        if (!env->tlb->do_tlbr)
+            goto die;
+        gen_op_tlbr();
         break;
-#endif
     case OPC_ERET:
         opn = "eret";
-        save_cpu_state(ctx, 0);
+        check_insn(env, ctx, ISA_MIPS2);
+        save_cpu_state(ctx, 1);
         gen_op_eret();
         ctx->bstate = BS_EXCP;
         break;
     case OPC_DERET:
         opn = "deret";
+        check_insn(env, ctx, ISA_MIPS32);
         if (!(ctx->hflags & MIPS_HFLAG_DM)) {
+            MIPS_INVAL(opn);
             generate_exception(ctx, EXCP_RI);
         } else {
-            save_cpu_state(ctx, 0);
+            save_cpu_state(ctx, 1);
             gen_op_deret();
             ctx->bstate = BS_EXCP;
         }
         break;
     case OPC_WAIT:
         opn = "wait";
+        check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
         /* If we get an exception, we want to restart at next instruction */
         ctx->pc += 4;
         save_cpu_state(ctx, 1);
@@ -4100,66 +4701,83 @@
         ctx->bstate = BS_EXCP;
         break;
     default:
-        if (loglevel & CPU_LOG_TB_IN_ASM) {
-            fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
-                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
-                    ((ctx->opcode >> 16) & 0x1F));
-        }
+ die:
+        MIPS_INVAL(opn);
         generate_exception(ctx, EXCP_RI);
         return;
     }
     MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
 }
 
-#ifdef MIPS_USES_FPU
-
 /* CP1 Branches (before delay slot) */
-static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
-                                 int32_t offset)
+static void gen_compute_branch1 (CPUState *env, DisasContext *ctx, uint32_t op,
+                                 int32_t cc, int32_t offset)
 {
     target_ulong btarget;
+    const char *opn = "cp1 cond branch";
+
+    if (cc != 0)
+        check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
 
     btarget = ctx->pc + 4 + offset;
 
     switch (op) {
     case OPC_BC1F:
-        gen_op_bc1f();
-        MIPS_DEBUG("bc1f " TLSZ, btarget);
+        gen_op_bc1f(cc);
+        opn = "bc1f";
         goto not_likely;
     case OPC_BC1FL:
-        gen_op_bc1f();
-        MIPS_DEBUG("bc1fl " TLSZ, btarget);
+        gen_op_bc1f(cc);
+        opn = "bc1fl";
         goto likely;
     case OPC_BC1T:
-        gen_op_bc1t();
-        MIPS_DEBUG("bc1t " TLSZ, btarget);
-    not_likely:
-        ctx->hflags |= MIPS_HFLAG_BC;
-        break;
+        gen_op_bc1t(cc);
+        opn = "bc1t";
+        goto not_likely;
     case OPC_BC1TL:
-        gen_op_bc1t();
-        MIPS_DEBUG("bc1tl " TLSZ, btarget);
+        gen_op_bc1t(cc);
+        opn = "bc1tl";
     likely:
         ctx->hflags |= MIPS_HFLAG_BL;
+        gen_op_set_bcond();
+        gen_op_save_bcond();
         break;
-    default:    
-        MIPS_INVAL("cp1 branch/jump");
-        generate_exception_err (ctx, EXCP_RI, 1);
+    case OPC_BC1FANY2:
+        gen_op_bc1any2f(cc);
+        opn = "bc1any2f";
+        goto not_likely;
+    case OPC_BC1TANY2:
+        gen_op_bc1any2t(cc);
+        opn = "bc1any2t";
+        goto not_likely;
+    case OPC_BC1FANY4:
+        gen_op_bc1any4f(cc);
+        opn = "bc1any4f";
+        goto not_likely;
+    case OPC_BC1TANY4:
+        gen_op_bc1any4t(cc);
+        opn = "bc1any4t";
+    not_likely:
+        ctx->hflags |= MIPS_HFLAG_BC;
+        gen_op_set_bcond();
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception (ctx, EXCP_RI);
         return;
     }
-    gen_op_set_bcond();
-
-    MIPS_DEBUG("enter ds: cond %02x target " TLSZ,
+    MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
                ctx->hflags, btarget);
     ctx->btarget = btarget;
-
-    return;
 }
 
 /* Coprocessor 1 (FPU) */
+
+#define FOP(func, fmt) (((fmt) << 21) | (func))
+
 static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
 {
-    const char *opn = "unk";
+    const char *opn = "cp1 move";
 
     switch (opc) {
     case OPC_MFC1:
@@ -4175,64 +4793,87 @@
         opn = "mtc1";
         break;
     case OPC_CFC1:
-        if (fs != 0 && fs != 31) {
-            MIPS_INVAL("cfc1 freg");
-            generate_exception_err (ctx, EXCP_RI, 1);
-            return;
-        }
-        GEN_LOAD_IMM_TN(T1, fs);
-        gen_op_cfc1();
+        gen_op_cfc1(fs);
         GEN_STORE_TN_REG(rt, T0);
         opn = "cfc1";
         break;
     case OPC_CTC1:
-         if (fs != 0 && fs != 31) {
-            MIPS_INVAL("ctc1 freg");
-            generate_exception_err (ctx, EXCP_RI, 1);
-            return;
-        }
-        GEN_LOAD_IMM_TN(T1, fs);
         GEN_LOAD_REG_TN(T0, rt);
-        gen_op_ctc1();
+        gen_op_ctc1(fs);
         opn = "ctc1";
         break;
     case OPC_DMFC1:
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_dmfc1();
+        GEN_STORE_TN_REG(rt, T0);
+        opn = "dmfc1";
+        break;
     case OPC_DMTC1:
-        /* Not implemented, fallthrough. */
+        GEN_LOAD_REG_TN(T0, rt);
+        gen_op_dmtc1();
+        GEN_STORE_FTN_FREG(fs, DT0);
+        opn = "dmtc1";
+        break;
+    case OPC_MFHC1:
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_mfhc1();
+        GEN_STORE_TN_REG(rt, T0);
+        opn = "mfhc1";
+        break;
+    case OPC_MTHC1:
+        GEN_LOAD_REG_TN(T0, rt);
+        gen_op_mthc1();
+        GEN_STORE_FTN_FREG(fs, WTH0);
+        opn = "mthc1";
+        break;
     default:
-        if (loglevel & CPU_LOG_TB_IN_ASM) {
-            fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n",
-                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
-                    ((ctx->opcode >> 16) & 0x1F));
-        }
-        generate_exception_err (ctx, EXCP_RI, 1);
+        MIPS_INVAL(opn);
+        generate_exception (ctx, EXCP_RI);
         return;
     }
     MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
 }
 
-/* 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.
- * 
- * Multiple float registers can be checked by calling
- * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
- */
-#define CHECK_FR(ctx, freg) do { \
-        if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
-            generate_exception_err (ctx, EXCP_RI, 1); \
-            return; \
-        } \
-    } while(0)
-
-#define FOP(func, fmt) (((fmt) << 21) | (func))
-
-static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd)
+static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
 {
-    const char *opn = "unk";
+    uint32_t ccbit;
+
+    GEN_LOAD_REG_TN(T0, rd);
+    GEN_LOAD_REG_TN(T1, rs);
+    if (cc) {
+        ccbit = 1 << (24 + cc);
+    } else
+        ccbit = 1 << 23;
+    if (!tf)
+        gen_op_movf(ccbit);
+    else
+        gen_op_movt(ccbit);
+    GEN_STORE_TN_REG(rd, T0);
+}
+
+#define GEN_MOVCF(fmt)                                                \
+static void glue(gen_movcf_, fmt) (DisasContext *ctx, int cc, int tf) \
+{                                                                     \
+    uint32_t ccbit;                                                   \
+                                                                      \
+    if (cc) {                                                         \
+        ccbit = 1 << (24 + cc);                                       \
+    } else                                                            \
+        ccbit = 1 << 23;                                              \
+    if (!tf)                                                          \
+        glue(gen_op_float_movf_, fmt)(ccbit);                         \
+    else                                                              \
+        glue(gen_op_float_movt_, fmt)(ccbit);                         \
+}
+GEN_MOVCF(d);
+GEN_MOVCF(s);
+GEN_MOVCF(ps);
+#undef GEN_MOVCF
+
+static void gen_farith (DisasContext *ctx, uint32_t op1,
+                        int ft, int fs, int fd, int cc)
+{
+    const char *opn = "farith";
     const char *condnames[] = {
             "c.f",
             "c.un",
@@ -4251,247 +4892,229 @@
             "c.le",
             "c.ngt",
     };
-    int binary = 0;
+    const char *condnames_abs[] = {
+            "cabs.f",
+            "cabs.un",
+            "cabs.eq",
+            "cabs.ueq",
+            "cabs.olt",
+            "cabs.ult",
+            "cabs.ole",
+            "cabs.ule",
+            "cabs.sf",
+            "cabs.ngle",
+            "cabs.seq",
+            "cabs.ngl",
+            "cabs.lt",
+            "cabs.nge",
+            "cabs.le",
+            "cabs.ngt",
+    };
+    enum { BINOP, CMPOP, OTHEROP } optype = OTHEROP;
     uint32_t func = ctx->opcode & 0x3f;
 
     switch (ctx->opcode & FOP(0x3f, 0x1f)) {
-    case FOP(0, 17):
-        CHECK_FR(ctx, fs | ft | fd);
-        GEN_LOAD_FREG_FTN(DT0, fs);
-        GEN_LOAD_FREG_FTN(DT1, ft);
-        gen_op_float_add_d();
-        GEN_STORE_FTN_FREG(fd, DT2);
-        opn = "add.d";
-        binary = 1;
-        break;
-    case FOP(1, 17):
-        CHECK_FR(ctx, fs | ft | fd);
-        GEN_LOAD_FREG_FTN(DT0, fs);
-        GEN_LOAD_FREG_FTN(DT1, ft);
-        gen_op_float_sub_d();
-        GEN_STORE_FTN_FREG(fd, DT2);
-        opn = "sub.d";
-        binary = 1;
-        break;
-    case FOP(2, 17):
-        CHECK_FR(ctx, fs | ft | fd);
-        GEN_LOAD_FREG_FTN(DT0, fs);
-        GEN_LOAD_FREG_FTN(DT1, ft);
-        gen_op_float_mul_d();
-        GEN_STORE_FTN_FREG(fd, DT2);
-        opn = "mul.d";
-        binary = 1;
-        break;
-    case FOP(3, 17):
-        CHECK_FR(ctx, fs | ft | fd);
-        GEN_LOAD_FREG_FTN(DT0, fs);
-        GEN_LOAD_FREG_FTN(DT1, ft);
-        gen_op_float_div_d();
-        GEN_STORE_FTN_FREG(fd, DT2);
-        opn = "div.d";
-        binary = 1;
-        break;
-    case FOP(4, 17):
-        CHECK_FR(ctx, 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_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_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_LOAD_FREG_FTN(DT0, fs);
-        gen_op_float_chs_d();
-        GEN_STORE_FTN_FREG(fd, DT2);
-        opn = "neg.d";
-        break;
-    /*  8 - round.l */
-    /*  9 - trunc.l */
-    /* 10 - ceil.l  */
-    /* 11 - floor.l */
-    case FOP(12, 17):
-        CHECK_FR(ctx, fs | fd);
-        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 | fd);
-        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 | fd);
-        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 | fd);
-        GEN_LOAD_FREG_FTN(DT0, fs);
-        gen_op_float_floorw_d();
-        GEN_STORE_FTN_FREG(fd, WT2);
-        opn = "floor.w.d";
-        break;
-    case FOP(33, 16): /* cvt.d.s */
-        CHECK_FR(ctx, fs | fd);
-        GEN_LOAD_FREG_FTN(WT0, fs);
-        gen_op_float_cvtd_s();
-        GEN_STORE_FTN_FREG(fd, DT2);
-        opn = "cvt.d.s";
-        break;
-    case FOP(33, 20): /* cvt.d.w */
-        CHECK_FR(ctx, fs | 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(48, 17):
-    case FOP(49, 17):
-    case FOP(50, 17):
-    case FOP(51, 17):
-    case FOP(52, 17):
-    case FOP(53, 17):
-    case FOP(54, 17):
-    case FOP(55, 17):
-    case FOP(56, 17):
-    case FOP(57, 17):
-    case FOP(58, 17):
-    case FOP(59, 17):
-    case FOP(60, 17):
-    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);
-        gen_cmp_d(func-48);
-        opn = condnames[func-48];
-        break;
     case FOP(0, 16):
-        CHECK_FR(ctx, fs | ft | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         gen_op_float_add_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "add.s";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(1, 16):
-        CHECK_FR(ctx, fs | ft | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         gen_op_float_sub_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "sub.s";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(2, 16):
-        CHECK_FR(ctx, fs | ft | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         gen_op_float_mul_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "mul.s";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(3, 16):
-        CHECK_FR(ctx, fs | ft | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
         gen_op_float_div_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "div.s";
-        binary = 1;
+        optype = BINOP;
         break;
     case FOP(4, 16):
-        CHECK_FR(ctx, fs | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_sqrt_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "sqrt.s";
         break;
     case FOP(5, 16):
-        CHECK_FR(ctx, fs | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_abs_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "abs.s";
         break;
     case FOP(6, 16):
-        CHECK_FR(ctx, fs | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_mov_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "mov.s";
         break;
     case FOP(7, 16):
-        CHECK_FR(ctx, fs | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_chs_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "neg.s";
         break;
+    case FOP(8, 16):
+        check_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_floorl_s();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "floor.l.s";
+        break;
     case FOP(12, 16):
-        CHECK_FR(ctx, fs | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_roundw_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "round.w.s";
         break;
     case FOP(13, 16):
-        CHECK_FR(ctx, fs | fd);
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_truncw_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "trunc.w.s";
         break;
-    case FOP(32, 17): /* cvt.s.d */
-        CHECK_FR(ctx, fs | fd);
-        GEN_LOAD_FREG_FTN(DT0, fs);
-        gen_op_float_cvts_d();
-        GEN_STORE_FTN_FREG(fd, WT2);
-        opn = "cvt.s.d";
-        break;
-    case FOP(32, 20): /* cvt.s.w */
-        CHECK_FR(ctx, fs | fd);
+    case FOP(14, 16):
         GEN_LOAD_FREG_FTN(WT0, fs);
-        gen_op_float_cvts_w();
+        gen_op_float_ceilw_s();
         GEN_STORE_FTN_FREG(fd, WT2);
-        opn = "cvt.s.w";
+        opn = "ceil.w.s";
         break;
-    case FOP(36, 16): /* cvt.w.s */
-        CHECK_FR(ctx, fs | fd);
+    case FOP(15, 16):
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_floorw_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "floor.w.s";
+        break;
+    case FOP(17, 16):
+        GEN_LOAD_REG_TN(T0, ft);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1);
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "movcf.s";
+        break;
+    case FOP(18, 16):
+        GEN_LOAD_REG_TN(T0, ft);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        gen_op_float_movz_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "movz.s";
+        break;
+    case FOP(19, 16):
+        GEN_LOAD_REG_TN(T0, ft);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT2, fd);
+        gen_op_float_movn_s();
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT2, ft);
+        gen_op_float_rsqrt2_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "rsqrt2.s";
+        break;
+    case FOP(33, 16):
+        check_cp1_registers(ctx, fd);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_cvtd_s();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "cvt.d.s";
+        break;
+    case FOP(36, 16):
         GEN_LOAD_FREG_FTN(WT0, fs);
         gen_op_float_cvtw_s();
         GEN_STORE_FTN_FREG(fd, WT2);
         opn = "cvt.w.s";
         break;
-    case FOP(36, 17): /* cvt.w.d */
-        CHECK_FR(ctx, fs | fd);
-        GEN_LOAD_FREG_FTN(DT0, fs);
-        gen_op_float_cvtw_d();
-        GEN_STORE_FTN_FREG(fd, WT2);
-        opn = "cvt.w.d";
+    case FOP(37, 16):
+        check_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT1, fs);
+        GEN_LOAD_FREG_FTN(WT0, ft);
+        gen_op_float_cvtps_s();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "cvt.ps.s";
         break;
     case FOP(48, 16):
     case FOP(49, 16):
@@ -4509,66 +5132,766 @@
     case FOP(61, 16):
     case FOP(62, 16):
     case FOP(63, 16):
-        CHECK_FR(ctx, fs | ft);
         GEN_LOAD_FREG_FTN(WT0, fs);
         GEN_LOAD_FREG_FTN(WT1, ft);
-        gen_cmp_s(func-48);
-        opn = condnames[func-48];
-        break;
-    default:    
-        if (loglevel & CPU_LOG_TB_IN_ASM) {
-            fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n",
-                    ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
-                    ((ctx->opcode >> 16) & 0x1F));
+        if (ctx->opcode & (1 << 6)) {
+            check_cp1_64bitmode(ctx);
+            gen_cmpabs_s(func-48, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_s(func-48, cc);
+            opn = condnames[func-48];
         }
-        generate_exception_err (ctx, EXCP_RI, 1);
+        break;
+    case FOP(0, 17):
+        check_cp1_registers(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_add_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "add.d";
+        optype = BINOP;
+        break;
+    case FOP(1, 17):
+        check_cp1_registers(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_sub_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "sub.d";
+        optype = BINOP;
+        break;
+    case FOP(2, 17):
+        check_cp1_registers(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_mul_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "mul.d";
+        optype = BINOP;
+        break;
+    case FOP(3, 17):
+        check_cp1_registers(ctx, fs | ft | fd);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_div_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "div.d";
+        optype = BINOP;
+        break;
+    case FOP(4, 17):
+        check_cp1_registers(ctx, 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_cp1_registers(ctx, 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_cp1_registers(ctx, 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_cp1_registers(ctx, 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_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        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_cp1_registers(ctx, 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_cp1_registers(ctx, 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_cp1_registers(ctx, 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_cp1_registers(ctx, fs);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_floorw_d();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "floor.w.d";
+        break;
+    case FOP(17, 17):
+        GEN_LOAD_REG_TN(T0, ft);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT2, fd);
+        gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1);
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "movcf.d";
+        break;
+    case FOP(18, 17):
+        GEN_LOAD_REG_TN(T0, ft);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT2, fd);
+        gen_op_float_movz_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "movz.d";
+        break;
+    case FOP(19, 17):
+        GEN_LOAD_REG_TN(T0, ft);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT2, fd);
+        gen_op_float_movn_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "movn.d";
+        break;
+    case FOP(21, 17):
+        check_cp1_registers(ctx, 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):
+        check_cp1_registers(ctx, 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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+    case FOP(51, 17):
+    case FOP(52, 17):
+    case FOP(53, 17):
+    case FOP(54, 17):
+    case FOP(55, 17):
+    case FOP(56, 17):
+    case FOP(57, 17):
+    case FOP(58, 17):
+    case FOP(59, 17):
+    case FOP(60, 17):
+    case FOP(61, 17):
+    case FOP(62, 17):
+    case FOP(63, 17):
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        if (ctx->opcode & (1 << 6)) {
+            check_cp1_64bitmode(ctx);
+            gen_cmpabs_d(func-48, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            check_cp1_registers(ctx, fs | ft);
+            gen_cmp_d(func-48, cc);
+            opn = condnames[func-48];
+        }
+        break;
+    case FOP(32, 17):
+        check_cp1_registers(ctx, 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_cp1_registers(ctx, 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_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_cvtl_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "cvt.l.d";
+        break;
+    case FOP(32, 20):
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        gen_op_float_cvts_w();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "cvt.s.w";
+        break;
+    case FOP(33, 20):
+        check_cp1_registers(ctx, 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_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        gen_op_float_cvtd_l();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "cvt.d.l";
+        break;
+    case FOP(38, 20):
+    case FOP(38, 21):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_cvtps_pw();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "cvt.ps.pw";
+        break;
+    case FOP(0, 22):
+        check_cp1_64bitmode(ctx);
+        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_float_add_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "add.ps";
+        break;
+    case FOP(1, 22):
+        check_cp1_64bitmode(ctx);
+        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_float_sub_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "sub.ps";
+        break;
+    case FOP(2, 22):
+        check_cp1_64bitmode(ctx);
+        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_float_mul_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "mul.ps";
+        break;
+    case FOP(5, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_abs_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "abs.ps";
+        break;
+    case FOP(6, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_mov_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "mov.ps";
+        break;
+    case FOP(7, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_chs_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "neg.ps";
+        break;
+    case FOP(17, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_REG_TN(T0, ft);
+        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_movcf_ps(ctx, (ft >> 2) & 0x7, ft & 0x1);
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "movcf.ps";
+        break;
+    case FOP(18, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_REG_TN(T0, ft);
+        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_movz_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "movz.ps";
+        break;
+    case FOP(19, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_REG_TN(T0, ft);
+        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_movn_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "movn.ps";
+        break;
+    case FOP(24, 22):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        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):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WT2, ft);
+        GEN_LOAD_FREG_FTN(WTH2, ft);
+        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_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        gen_op_float_cvtpw_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "cvt.pw.ps";
+        break;
+    case FOP(40, 22):
+        check_cp1_64bitmode(ctx);
+        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_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        gen_op_float_pll_ps();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "pll.ps";
+        break;
+    case FOP(45, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH1, ft);
+        gen_op_float_plu_ps();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "plu.ps";
+        break;
+    case FOP(46, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        gen_op_float_pul_ps();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "pul.ps";
+        break;
+    case FOP(47, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WTH1, ft);
+        gen_op_float_puu_ps();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "puu.ps";
+        break;
+    case FOP(48, 22):
+    case FOP(49, 22):
+    case FOP(50, 22):
+    case FOP(51, 22):
+    case FOP(52, 22):
+    case FOP(53, 22):
+    case FOP(54, 22):
+    case FOP(55, 22):
+    case FOP(56, 22):
+    case FOP(57, 22):
+    case FOP(58, 22):
+    case FOP(59, 22):
+    case FOP(60, 22):
+    case FOP(61, 22):
+    case FOP(62, 22):
+    case FOP(63, 22):
+        check_cp1_64bitmode(ctx);
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WTH0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        GEN_LOAD_FREG_FTN(WTH1, ft);
+        if (ctx->opcode & (1 << 6)) {
+            gen_cmpabs_ps(func-48, cc);
+            opn = condnames_abs[func-48];
+        } else {
+            gen_cmp_ps(func-48, cc);
+            opn = condnames[func-48];
+        }
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception (ctx, EXCP_RI);
         return;
     }
-    if (binary)
+    switch (optype) {
+    case BINOP:
         MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
-    else
+        break;
+    case CMPOP:
+        MIPS_DEBUG("%s %s,%s", opn, fregnames[fs], fregnames[ft]);
+        break;
+    default:
         MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
+        break;
+    }
 }
 
-static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
+/* Coprocessor 3 (FPU) */
+static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
+                           int fd, int fs, int base, int index)
 {
-    uint32_t ccbit;
+    const char *opn = "extended float load/store";
+    int store = 0;
 
-    if (cc)
-        ccbit = 1 << (24 + cc);
-    else
-        ccbit = 1 << 23;
-    if (!tf)
-        gen_op_movf(ccbit, rd, rs);
-    else
-       gen_op_movt(ccbit, rd, rs);
+    /* All of those work only on 64bit FPUs. */
+    check_cp1_64bitmode(ctx);
+    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(lwc1);
+        GEN_STORE_FTN_FREG(fd, WT0);
+        opn = "lwxc1";
+        break;
+    case OPC_LDXC1:
+        op_ldst(ldc1);
+        GEN_STORE_FTN_FREG(fd, DT0);
+        opn = "ldxc1";
+        break;
+    case OPC_LUXC1:
+        op_ldst(luxc1);
+        GEN_STORE_FTN_FREG(fd, DT0);
+        opn = "luxc1";
+        break;
+    case OPC_SWXC1:
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        op_ldst(swc1);
+        opn = "swxc1";
+        store = 1;
+        break;
+    case OPC_SDXC1:
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        op_ldst(sdc1);
+        opn = "sdxc1";
+        store = 1;
+        break;
+    case OPC_SUXC1:
+        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[store ? fs : fd],
+               regnames[index], regnames[base]);
 }
 
-#endif /* MIPS_USES_FPU */
+static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
+                            int fd, int fr, int fs, int ft)
+{
+    const char *opn = "flt3_arith";
+
+    /* All of those work only on 64bit FPUs. */
+    check_cp1_64bitmode(ctx);
+    switch (opc) {
+    case OPC_ALNV_PS:
+        GEN_LOAD_REG_TN(T0, fr);
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        gen_op_float_alnv_ps();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "alnv.ps";
+        break;
+    case OPC_MADD_S:
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        GEN_LOAD_FREG_FTN(WT2, fr);
+        gen_op_float_muladd_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "madd.s";
+        break;
+    case OPC_MADD_D:
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        GEN_LOAD_FREG_FTN(DT2, fr);
+        gen_op_float_muladd_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "madd.d";
+        break;
+    case OPC_MADD_PS:
+        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_LOAD_FREG_FTN(WT2, fr);
+        GEN_LOAD_FREG_FTN(WTH2, fr);
+        gen_op_float_muladd_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "madd.ps";
+        break;
+    case OPC_MSUB_S:
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        GEN_LOAD_FREG_FTN(WT2, fr);
+        gen_op_float_mulsub_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "msub.s";
+        break;
+    case OPC_MSUB_D:
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        GEN_LOAD_FREG_FTN(DT2, fr);
+        gen_op_float_mulsub_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "msub.d";
+        break;
+    case OPC_MSUB_PS:
+        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_LOAD_FREG_FTN(WT2, fr);
+        GEN_LOAD_FREG_FTN(WTH2, fr);
+        gen_op_float_mulsub_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "msub.ps";
+        break;
+    case OPC_NMADD_S:
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        GEN_LOAD_FREG_FTN(WT2, fr);
+        gen_op_float_nmuladd_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "nmadd.s";
+        break;
+    case OPC_NMADD_D:
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        GEN_LOAD_FREG_FTN(DT2, fr);
+        gen_op_float_nmuladd_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "nmadd.d";
+        break;
+    case OPC_NMADD_PS:
+        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_LOAD_FREG_FTN(WT2, fr);
+        GEN_LOAD_FREG_FTN(WTH2, fr);
+        gen_op_float_nmuladd_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "nmadd.ps";
+        break;
+    case OPC_NMSUB_S:
+        GEN_LOAD_FREG_FTN(WT0, fs);
+        GEN_LOAD_FREG_FTN(WT1, ft);
+        GEN_LOAD_FREG_FTN(WT2, fr);
+        gen_op_float_nmulsub_s();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        opn = "nmsub.s";
+        break;
+    case OPC_NMSUB_D:
+        GEN_LOAD_FREG_FTN(DT0, fs);
+        GEN_LOAD_FREG_FTN(DT1, ft);
+        GEN_LOAD_FREG_FTN(DT2, fr);
+        gen_op_float_nmulsub_d();
+        GEN_STORE_FTN_FREG(fd, DT2);
+        opn = "nmsub.d";
+        break;
+    case OPC_NMSUB_PS:
+        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_LOAD_FREG_FTN(WT2, fr);
+        GEN_LOAD_FREG_FTN(WTH2, fr);
+        gen_op_float_nmulsub_ps();
+        GEN_STORE_FTN_FREG(fd, WT2);
+        GEN_STORE_FTN_FREG(fd, WTH2);
+        opn = "nmsub.ps";
+        break;
+    default:
+        MIPS_INVAL(opn);
+        generate_exception (ctx, EXCP_RI);
+        return;
+    }
+    MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr],
+               fregnames[fs], fregnames[ft]);
+}
 
 /* ISA extensions (ASEs) */
 /* MIPS16 extension to MIPS32 */
 /* SmartMIPS extension to MIPS32 */
 
-#ifdef MIPS_HAS_MIPS64
-/* Coprocessor 3 (FPU) */
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
 
 /* MDMX extension to MIPS64 */
 /* MIPS-3D extension to MIPS64 */
 
 #endif
 
-static void gen_blikely(DisasContext *ctx)
-{
-    int l1;
-    l1 = gen_new_label();
-    gen_op_jnz_T2(l1);
-    gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
-    gen_goto_tb(ctx, 1, ctx->pc + 4);
-    gen_set_label(l1);
-}
-
-static void decode_opc (DisasContext *ctx)
+static void decode_opc (CPUState *env, DisasContext *ctx)
 {
     int32_t offset;
     int rs, rt, rd, sa;
@@ -4577,14 +5900,20 @@
 
     /* make sure instructions are on a word boundary */
     if (ctx->pc & 0x3) {
+        env->CP0_BadVAddr = ctx->pc;
         generate_exception(ctx, EXCP_AdEL);
         return;
     }
 
     if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
+        int l1;
         /* Handle blikely not taken case */
-        MIPS_DEBUG("blikely condition (" TLSZ ")", ctx->pc + 4);
-        gen_blikely(ctx);
+        MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
+        l1 = gen_new_label();
+        gen_op_jnz_T2(l1);
+        gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
+        gen_goto_tb(ctx, 1, ctx->pc + 4);
+        gen_set_label(l1);
     }
     op = MASK_OP_MAJOR(ctx->opcode);
     rs = (ctx->opcode >> 21) & 0x1f;
@@ -4598,14 +5927,15 @@
         switch (op1) {
         case OPC_SLL:          /* Arithmetic with immediate */
         case OPC_SRL ... OPC_SRA:
-            gen_arith_imm(ctx, op1, rd, rt, sa);
+            gen_arith_imm(env, ctx, op1, rd, rt, sa);
             break;
+        case OPC_MOVZ ... OPC_MOVN:
+            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
         case OPC_SLLV:         /* Arithmetic */
         case OPC_SRLV ... OPC_SRAV:
-        case OPC_MOVZ ... OPC_MOVN:
         case OPC_ADD ... OPC_NOR:
         case OPC_SLT ... OPC_SLTU:
-            gen_arith(ctx, op1, rd, rs, rt);
+            gen_arith(env, ctx, op1, rd, rs, rt);
             break;
         case OPC_MULT ... OPC_DIVU:
             gen_muldiv(ctx, op1, rs, rt);
@@ -4625,47 +5955,66 @@
         case OPC_MTLO:          /* Move to HI/LO */
             gen_HILO(ctx, op1, rs);
             break;
-        case OPC_PMON:          /* Pmon entry point */
+        case OPC_PMON:          /* Pmon entry point, also R4010 selsl */
+#ifdef MIPS_STRICT_STANDARD
+            MIPS_INVAL("PMON / selsl");
+            generate_exception(ctx, EXCP_RI);
+#else
             gen_op_pmon(sa);
+#endif
             break;
         case OPC_SYSCALL:
             generate_exception(ctx, EXCP_SYSCALL);
-            ctx->bstate = BS_EXCP;
             break;
         case OPC_BREAK:
             generate_exception(ctx, EXCP_BREAK);
             break;
-        case OPC_SPIM:        /* SPIM ? */
+        case OPC_SPIM:
+#ifdef MIPS_STRICT_STANDARD
+            MIPS_INVAL("SPIM");
+            generate_exception(ctx, EXCP_RI);
+#else
            /* Implemented as RI exception for now. */
             MIPS_INVAL("spim (unofficial)");
             generate_exception(ctx, EXCP_RI);
+#endif
             break;
         case OPC_SYNC:
-            /* Treat as a noop. */
+            /* Treat as NOP. */
             break;
 
-#ifdef MIPS_USES_FPU
         case OPC_MOVCI:
-            gen_op_cp1_enabled();
-            gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
-                      (ctx->opcode >> 16) & 1);
+            check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
+            if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+                save_cpu_state(ctx, 1);
+                check_cp1_enabled(ctx);
+                gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+                          (ctx->opcode >> 16) & 1);
+            } else {
+                generate_exception_err(ctx, EXCP_CpU, 1);
+            }
             break;
-#endif
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
        /* MIPS64 specific opcodes */
         case OPC_DSLL:
         case OPC_DSRL ... OPC_DSRA:
         case OPC_DSLL32:
         case OPC_DSRL32 ... OPC_DSRA32:
-            gen_arith_imm(ctx, op1, rd, rt, sa);
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_arith_imm(env, ctx, op1, rd, rt, sa);
             break;
         case OPC_DSLLV:
         case OPC_DSRLV ... OPC_DSRAV:
         case OPC_DADD ... OPC_DSUBU:
-            gen_arith(ctx, op1, rd, rs, rt);
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
+            gen_arith(env, ctx, op1, rd, rs, rt);
             break;
         case OPC_DMULT ... OPC_DDIVU:
+            check_insn(env, ctx, ISA_MIPS3);
+            check_mips_64(ctx);
             gen_muldiv(ctx, op1, rs, rt);
             break;
 #endif
@@ -4680,27 +6029,32 @@
         switch (op1) {
         case OPC_MADD ... OPC_MADDU: /* Multiply and add/sub */
         case OPC_MSUB ... OPC_MSUBU:
+            check_insn(env, ctx, ISA_MIPS32);
             gen_muldiv(ctx, op1, rs, rt);
             break;
         case OPC_MUL:
-            gen_arith(ctx, op1, rd, rs, rt);
+            gen_arith(env, ctx, op1, rd, rs, rt);
             break;
         case OPC_CLZ ... OPC_CLO:
+            check_insn(env, ctx, ISA_MIPS32);
             gen_cl(ctx, op1, rd, rs);
             break;
         case OPC_SDBBP:
             /* XXX: not clear which exception should be raised
              *      when in debug mode...
              */
+            check_insn(env, ctx, ISA_MIPS32);
             if (!(ctx->hflags & MIPS_HFLAG_DM)) {
                 generate_exception(ctx, EXCP_DBp);
             } else {
                 generate_exception(ctx, EXCP_DBp);
             }
-            /* Treat as a noop */
+            /* Treat as NOP. */
             break;
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
         case OPC_DCLZ ... OPC_DCLO:
+            check_insn(env, ctx, ISA_MIPS64);
+            check_mips_64(ctx);
             gen_cl(ctx, op1, rd, rs);
             break;
 #endif
@@ -4711,77 +6065,105 @@
         }
         break;
     case OPC_SPECIAL3:
-        op1 = MASK_SPECIAL3(ctx->opcode);
-        switch (op1) {
-        case OPC_EXT:
-        case OPC_INS:
-            gen_bitops(ctx, op1, rt, rs, sa, rd);
-            break;
-        case OPC_BSHFL:
-            op2 = MASK_BSHFL(ctx->opcode);
-            switch (op2) {
-            case OPC_WSBH:
-                GEN_LOAD_REG_TN(T1, rt);
-                gen_op_wsbh();
-                break;
-            case OPC_SEB:
-                GEN_LOAD_REG_TN(T1, rt);
-                gen_op_seb();
-                break;
-            case OPC_SEH:
-                GEN_LOAD_REG_TN(T1, rt);
-                gen_op_seh();
-                break;
+         op1 = MASK_SPECIAL3(ctx->opcode);
+         switch (op1) {
+         case OPC_EXT:
+         case OPC_INS:
+             check_insn(env, ctx, ISA_MIPS32R2);
+             gen_bitops(ctx, op1, rt, rs, sa, rd);
+             break;
+         case OPC_BSHFL:
+             check_insn(env, ctx, ISA_MIPS32R2);
+             op2 = MASK_BSHFL(ctx->opcode);
+             switch (op2) {
+             case OPC_WSBH:
+                 GEN_LOAD_REG_TN(T1, rt);
+                 gen_op_wsbh();
+                 break;
+             case OPC_SEB:
+                 GEN_LOAD_REG_TN(T1, rt);
+                 gen_op_seb();
+                 break;
+             case OPC_SEH:
+                 GEN_LOAD_REG_TN(T1, rt);
+                 gen_op_seh();
+                 break;
              default:            /* Invalid */
-                MIPS_INVAL("bshfl");
+                 MIPS_INVAL("bshfl");
+                 generate_exception(ctx, EXCP_RI);
+                 break;
+            }
+            GEN_STORE_TN_REG(rd, T0);
+            break;
+        case OPC_RDHWR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            switch (rd) {
+            case 0:
+                save_cpu_state(ctx, 1);
+                gen_op_rdhwr_cpunum();
+                break;
+            case 1:
+                save_cpu_state(ctx, 1);
+                gen_op_rdhwr_synci_step();
+                break;
+            case 2:
+                save_cpu_state(ctx, 1);
+                gen_op_rdhwr_cc();
+                break;
+            case 3:
+                save_cpu_state(ctx, 1);
+                gen_op_rdhwr_ccres();
+                break;
+            case 29:
+#if defined (CONFIG_USER_ONLY)
+                gen_op_tls_value();
+                break;
+#endif
+            default:            /* Invalid */
+                MIPS_INVAL("rdhwr");
                 generate_exception(ctx, EXCP_RI);
                 break;
-           }
-           GEN_STORE_TN_REG(rd, T0);
-           break;
-       case OPC_RDHWR:
-           switch (rd) {
-           case 0:
-               gen_op_rdhwr_cpunum();
-               break;
-           case 1:
-               gen_op_rdhwr_synci_step();
-               break;
-           case 2:
-               gen_op_rdhwr_cc();
-               break;
-           case 3:
-               gen_op_rdhwr_ccres();
-               break;
-           default:            /* Invalid */
-               MIPS_INVAL("rdhwr");
-               generate_exception(ctx, EXCP_RI);
-               break;
-           }
-           GEN_STORE_TN_REG(rt, T0);
-           break;
-#ifdef MIPS_HAS_MIPS64
-       case OPC_DEXTM ... OPC_DEXT:
-       case OPC_DINSM ... OPC_DINS:
-           gen_bitops(ctx, op1, rt, rs, sa, rd);
+            }
+            GEN_STORE_TN_REG(rt, T0);
             break;
-       case OPC_DBSHFL:
-           op2 = MASK_DBSHFL(ctx->opcode);
-           switch (op2) {
-           case OPC_DSBH:
-               GEN_LOAD_REG_TN(T1, rt);
-               gen_op_dsbh();
-               break;
-           case OPC_DSHD:
-               GEN_LOAD_REG_TN(T1, rt);
-               gen_op_dshd();
-               break;
+        case OPC_FORK:
+            check_mips_mt(env, ctx);
+            GEN_LOAD_REG_TN(T0, rt);
+            GEN_LOAD_REG_TN(T1, rs);
+            gen_op_fork();
+            break;
+        case OPC_YIELD:
+            check_mips_mt(env, ctx);
+            GEN_LOAD_REG_TN(T0, rs);
+            gen_op_yield();
+            GEN_STORE_TN_REG(rd, T0);
+            break;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+        case OPC_DEXTM ... OPC_DEXT:
+        case OPC_DINSM ... OPC_DINS:
+            check_insn(env, ctx, ISA_MIPS64R2);
+            check_mips_64(ctx);
+            gen_bitops(ctx, op1, rt, rs, sa, rd);
+            break;
+        case OPC_DBSHFL:
+            check_insn(env, ctx, ISA_MIPS64R2);
+            check_mips_64(ctx);
+            op2 = MASK_DBSHFL(ctx->opcode);
+            switch (op2) {
+            case OPC_DSBH:
+                GEN_LOAD_REG_TN(T1, rt);
+                gen_op_dsbh();
+                break;
+            case OPC_DSHD:
+                GEN_LOAD_REG_TN(T1, rt);
+                gen_op_dshd();
+                break;
             default:            /* Invalid */
                 MIPS_INVAL("dbshfl");
                 generate_exception(ctx, EXCP_RI);
                 break;
-           }
-           GEN_STORE_TN_REG(rd, T0);
+            }
+            GEN_STORE_TN_REG(rd, T0);
 #endif
         default:            /* Invalid */
             MIPS_INVAL("special3");
@@ -4801,58 +6183,90 @@
             gen_trap(ctx, op1, rs, -1, imm);
             break;
         case OPC_SYNCI:
-           /* treat as noop */
+            check_insn(env, ctx, ISA_MIPS32R2);
+            /* Treat as NOP. */
             break;
         default:            /* Invalid */
-            MIPS_INVAL("REGIMM");
+            MIPS_INVAL("regimm");
             generate_exception(ctx, EXCP_RI);
             break;
         }
         break;
     case OPC_CP0:
+        check_cp0_enabled(ctx);
         op1 = MASK_CP0(ctx->opcode);
         switch (op1) {
         case OPC_MFC0:
         case OPC_MTC0:
-#ifdef MIPS_HAS_MIPS64
+        case OPC_MFTR:
+        case OPC_MTTR:
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
         case OPC_DMFC0:
         case OPC_DMTC0:
 #endif
-            gen_cp0(ctx, op1, rt, rd);
+            gen_cp0(env, ctx, op1, rt, rd);
             break;
         case OPC_C0_FIRST ... OPC_C0_LAST:
-            gen_cp0(ctx, MASK_C0(ctx->opcode), rt, rd);
+            gen_cp0(env, ctx, MASK_C0(ctx->opcode), rt, rd);
             break;
         case OPC_MFMC0:
             op2 = MASK_MFMC0(ctx->opcode);
             switch (op2) {
+            case OPC_DMT:
+                check_mips_mt(env, ctx);
+                gen_op_dmt();
+                break;
+            case OPC_EMT:
+                check_mips_mt(env, ctx);
+                gen_op_emt();
+                break;
+            case OPC_DVPE:
+                check_mips_mt(env, ctx);
+                gen_op_dvpe();
+                break;
+            case OPC_EVPE:
+                check_mips_mt(env, ctx);
+                gen_op_evpe();
+                break;
             case OPC_DI:
+                check_insn(env, ctx, ISA_MIPS32R2);
+                save_cpu_state(ctx, 1);
                 gen_op_di();
                 /* Stop translation as we may have switched the execution mode */
                 ctx->bstate = BS_STOP;
                 break;
             case OPC_EI:
+                check_insn(env, ctx, ISA_MIPS32R2);
+                save_cpu_state(ctx, 1);
                 gen_op_ei();
                 /* Stop translation as we may have switched the execution mode */
                 ctx->bstate = BS_STOP;
                 break;
             default:            /* Invalid */
-                MIPS_INVAL("MFMC0");
+                MIPS_INVAL("mfmc0");
                 generate_exception(ctx, EXCP_RI);
                 break;
             }
             GEN_STORE_TN_REG(rt, T0);
             break;
-        /* Shadow registers (not implemented). */
         case OPC_RDPGPR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            GEN_LOAD_SRSREG_TN(T0, rt);
+            GEN_STORE_TN_REG(rd, T0);
+            break;
         case OPC_WRPGPR:
+            check_insn(env, ctx, ISA_MIPS32R2);
+            GEN_LOAD_REG_TN(T0, rt);
+            GEN_STORE_TN_SRSREG(rd, T0);
+            break;
         default:
+            MIPS_INVAL("cp0");
             generate_exception(ctx, EXCP_RI);
             break;
         }
         break;
     case OPC_ADDI ... OPC_LUI: /* Arithmetic with immediate opcode */
-         gen_arith_imm(ctx, op, rt, rs, imm);
+         gen_arith_imm(env, ctx, op, rt, rs, imm);
          break;
     case OPC_J ... OPC_JAL: /* Jump */
          offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
@@ -4870,58 +6284,72 @@
          gen_ldst(ctx, op, rt, rs, imm);
          break;
     case OPC_CACHE:
-         /* Treat as a noop */
-         break;
+        check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
+        /* Treat as NOP. */
+        break;
     case OPC_PREF:
-        /* Treat as a noop */
+        check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32);
+        /* Treat as NOP. */
         break;
 
-    /* Floating point.  */
+    /* Floating point (COP1). */
     case OPC_LWC1:
     case OPC_LDC1:
     case OPC_SWC1:
     case OPC_SDC1:
-#if defined(MIPS_USES_FPU)
-        save_cpu_state(ctx, 1);
-        gen_op_cp1_enabled();
-        gen_flt_ldst(ctx, op, rt, rs, imm);
-#else
-        generate_exception_err(ctx, EXCP_CpU, 1);
-#endif
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            save_cpu_state(ctx, 1);
+            check_cp1_enabled(ctx);
+            gen_flt_ldst(ctx, op, rt, rs, imm);
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
+        }
         break;
 
     case OPC_CP1:
-#if defined(MIPS_USES_FPU)
-        save_cpu_state(ctx, 1);
-        gen_op_cp1_enabled();
-        op1 = MASK_CP1(ctx->opcode);
-        switch (op1) {
-        case OPC_MFC1:
-        case OPC_CFC1:
-        case OPC_MTC1:
-        case OPC_CTC1:
-#ifdef MIPS_HAS_MIPS64
-        case OPC_DMFC1:
-        case OPC_DMTC1:
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            save_cpu_state(ctx, 1);
+            check_cp1_enabled(ctx);
+            op1 = MASK_CP1(ctx->opcode);
+            switch (op1) {
+            case OPC_MFHC1:
+            case OPC_MTHC1:
+                check_insn(env, ctx, ISA_MIPS32R2);
+            case OPC_MFC1:
+            case OPC_CFC1:
+            case OPC_MTC1:
+            case OPC_CTC1:
+                gen_cp1(ctx, op1, rt, rd);
+                break;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+            case OPC_DMFC1:
+            case OPC_DMTC1:
+                check_insn(env, ctx, ISA_MIPS3);
+                gen_cp1(ctx, op1, rt, rd);
+                break;
 #endif
-            gen_cp1(ctx, op1, rt, rd);
-            break;
-        case OPC_BC1:
-            gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2);
-            return;
-        case OPC_S_FMT:
-        case OPC_D_FMT:
-        case OPC_W_FMT:
-        case OPC_L_FMT:
-            gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa);
-            break;
-        default:
-            generate_exception_err(ctx, EXCP_RI, 1);
-            break;
+            case OPC_BC1:
+            case OPC_BC1ANY2:
+            case OPC_BC1ANY4:
+                gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
+                                    (rt >> 2) & 0x7, imm << 2);
+                return;
+            case OPC_S_FMT:
+            case OPC_D_FMT:
+            case OPC_W_FMT:
+            case OPC_L_FMT:
+            case OPC_PS_FMT:
+                gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa,
+                           (imm >> 8) & 0x7);
+                break;
+            default:
+                MIPS_INVAL("cp1");
+                generate_exception (ctx, EXCP_RI);
+                break;
+            }
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
         }
-#else
-        generate_exception_err(ctx, EXCP_CpU, 1);
-#endif
         break;
 
     /* COP2.  */
@@ -4934,20 +6362,49 @@
         generate_exception_err(ctx, EXCP_CpU, 2);
         break;
 
-#ifdef MIPS_USES_FPU
     case OPC_CP3:
-        gen_op_cp1_enabled();
-        op1 = MASK_CP3(ctx->opcode);
-        switch (op1) {
-        /* Not implemented */
-        default:
-            generate_exception_err(ctx, EXCP_RI, 1);
-            break;
+        if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+            save_cpu_state(ctx, 1);
+            check_cp1_enabled(ctx);
+            op1 = MASK_CP3(ctx->opcode);
+            switch (op1) {
+            case OPC_LWXC1:
+            case OPC_LDXC1:
+            case OPC_LUXC1:
+            case OPC_SWXC1:
+            case OPC_SDXC1:
+            case OPC_SUXC1:
+                gen_flt3_ldst(ctx, op1, sa, rd, rs, rt);
+                break;
+            case OPC_PREFX:
+                /* Treat as NOP. */
+                break;
+            case OPC_ALNV_PS:
+            case OPC_MADD_S:
+            case OPC_MADD_D:
+            case OPC_MADD_PS:
+            case OPC_MSUB_S:
+            case OPC_MSUB_D:
+            case OPC_MSUB_PS:
+            case OPC_NMADD_S:
+            case OPC_NMADD_D:
+            case OPC_NMADD_PS:
+            case OPC_NMSUB_S:
+            case OPC_NMSUB_D:
+            case OPC_NMSUB_PS:
+                gen_flt3_arith(ctx, op1, sa, rs, rd, rt);
+                break;
+            default:
+                MIPS_INVAL("cp3");
+                generate_exception (ctx, EXCP_RI);
+                break;
+            }
+        } else {
+            generate_exception_err(ctx, EXCP_CpU, 1);
         }
         break;
-#endif
 
-#ifdef MIPS_HAS_MIPS64
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
     /* MIPS64 opcodes */
     case OPC_LWU:
     case OPC_LDL ... OPC_LDR:
@@ -4956,32 +6413,34 @@
     case OPC_LD:
     case OPC_SCD:
     case OPC_SD:
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
         gen_ldst(ctx, op, rt, rs, imm);
         break;
     case OPC_DADDI ... OPC_DADDIU:
-        gen_arith_imm(ctx, op, rt, rs, imm);
+        check_insn(env, ctx, ISA_MIPS3);
+        check_mips_64(ctx);
+        gen_arith_imm(env, ctx, op, rt, rs, imm);
         break;
 #endif
-#ifdef MIPS_HAS_MIPS16
     case OPC_JALX:
+        check_insn(env, ctx, ASE_MIPS16);
         /* MIPS16: Not implemented. */
-#endif
-#ifdef MIPS_HAS_MDMX
     case OPC_MDMX:
+        check_insn(env, ctx, ASE_MDMX);
         /* MDMX: Not implemented. */
-#endif
     default:            /* Invalid */
-        MIPS_INVAL("");
+        MIPS_INVAL("major opcode");
         generate_exception(ctx, EXCP_RI);
         break;
     }
     if (ctx->hflags & MIPS_HFLAG_BMASK) {
-        int hflags = ctx->hflags;
+        int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
         /* Branches completion */
         ctx->hflags &= ~MIPS_HFLAG_BMASK;
         ctx->bstate = BS_BRANCH;
         save_cpu_state(ctx, 0);
-        switch (hflags & MIPS_HFLAG_BMASK) {
+        switch (hflags) {
         case MIPS_HFLAG_B:
             /* unconditional branch */
             MIPS_DEBUG("unconditional branch");
@@ -5008,6 +6467,8 @@
             /* unconditional branch to register */
             MIPS_DEBUG("branch to register");
             gen_op_breg();
+            gen_op_reset_T0();
+            gen_op_exit_tb();
             break;
         default:
             MIPS_DEBUG("unknown branch");
@@ -5016,10 +6477,11 @@
     }
 }
 
-int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
-                                    int search_pc)
+static inline int
+gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
+                                int search_pc)
 {
-    DisasContext ctx, *ctxp = &ctx;
+    DisasContext ctx;
     target_ulong pc_start;
     uint16_t *gen_opc_end;
     int j, lj = -1;
@@ -5037,25 +6499,13 @@
     ctx.tb = tb;
     ctx.bstate = BS_NONE;
     /* Restore delay slot state from the tb context.  */
-    ctx.hflags = tb->flags;
-    ctx.saved_hflags = ctx.hflags;
-    if (ctx.hflags & MIPS_HFLAG_BR) {
-        gen_op_restore_breg_target();
-    } else if (ctx.hflags & MIPS_HFLAG_B) {
-        ctx.btarget = env->btarget;
-    } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
-        /* If we are in the delay slot of a conditional branch,
-         * restore the branch condition from env->bcond to T2
-         */
-        ctx.btarget = env->btarget;
-        gen_op_restore_bcond();
-    }
+    ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
+    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");
@@ -5063,7 +6513,7 @@
         cpu_dump_state(env, logfile, fprintf, 0);
     }
 #endif
-#if defined MIPS_DEBUG_DISAS
+#ifdef MIPS_DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM)
         fprintf(logfile, "\ntb %p super %d cond %04x\n",
                 tb, ctx.mem_idx, ctx.hflags);
@@ -5072,9 +6522,12 @@
         if (env->nb_breakpoints > 0) {
             for(j = 0; j < env->nb_breakpoints; j++) {
                 if (env->breakpoints[j] == ctx.pc) {
-                    save_cpu_state(ctxp, 1);
+                    save_cpu_state(&ctx, 1);
                     ctx.bstate = BS_BRANCH;
                     gen_op_debug();
+                    /* Include the breakpoint location or the tb won't
+                     * be flushed when it must be.  */
+                    ctx.pc += 4;
                     goto done_generating;
                 }
             }
@@ -5092,7 +6545,7 @@
             gen_opc_instr_start[lj] = 1;
         }
         ctx.opcode = ldl_code(ctx.pc);
-        decode_opc(&ctx);
+        decode_opc(env, &ctx);
         ctx.pc += 4;
 
         if (env->singlestep_enabled)
@@ -5106,17 +6559,28 @@
 #endif
     }
     if (env->singlestep_enabled) {
-        save_cpu_state(ctxp, ctx.bstate == BS_NONE);
+        save_cpu_state(&ctx, ctx.bstate == BS_NONE);
         gen_op_debug();
-        goto done_generating;
+    } else {
+	switch (ctx.bstate) {
+        case BS_STOP:
+            gen_op_interrupt_restart();
+            gen_goto_tb(&ctx, 0, ctx.pc);
+            break;
+        case BS_NONE:
+            save_cpu_state(&ctx, 0);
+            gen_goto_tb(&ctx, 0, ctx.pc);
+            break;
+        case BS_EXCP:
+            gen_op_interrupt_restart();
+            gen_op_reset_T0();
+            gen_op_exit_tb();
+            break;
+        case BS_BRANCH:
+        default:
+            break;
+	}
     }
-    else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
-        save_cpu_state(ctxp, 0);
-        gen_goto_tb(&ctx, 0, ctx.pc);
-    }
-    gen_op_reset_T0();
-    /* Generate the return instruction */
-    gen_op_exit_tb();
 done_generating:
     *gen_opc_ptr = INDEX_op_end;
     if (search_pc) {
@@ -5124,7 +6588,6 @@
         lj++;
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
-        tb->size = 0;
     } else {
         tb->size = ctx.pc - pc_start;
     }
@@ -5135,7 +6598,7 @@
 #endif
     if (loglevel & CPU_LOG_TB_IN_ASM) {
         fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-    target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
+        target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
         fprintf(logfile, "\n");
     }
     if (loglevel & CPU_LOG_TB_OP) {
@@ -5147,7 +6610,7 @@
         fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
     }
 #endif
-    
+
     return 0;
 }
 
@@ -5161,28 +6624,39 @@
     return gen_intermediate_code_internal(env, tb, 1);
 }
 
-#ifdef MIPS_USES_FPU
-
-void fpu_dump_state(CPUState *env, FILE *f, 
+void fpu_dump_state(CPUState *env, FILE *f,
                     int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
 {
     int i;
+    int is_fpu64 = !!(env->hflags & MIPS_HFLAG_F64);
 
-#   define printfpr(fp) do { \
-        fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \
-                (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \
+#define printfpr(fp)                                                        \
+    do {                                                                    \
+        if (is_fpu64)                                                       \
+            fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu: %13g\n",   \
+                        (fp)->w[FP_ENDIAN_IDX], (fp)->d, (fp)->fd,          \
+                        (fp)->fs[FP_ENDIAN_IDX], (fp)->fs[!FP_ENDIAN_IDX]); \
+        else {                                                              \
+            fpr_t tmp;                                                      \
+            tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX];                  \
+            tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX];           \
+            fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu:%13g\n",    \
+                        tmp.w[FP_ENDIAN_IDX], tmp.d, tmp.fd,                \
+                        tmp.fs[FP_ENDIAN_IDX], tmp.fs[!FP_ENDIAN_IDX]);     \
+        }                                                                   \
     } while(0)
 
-    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d\n",
-                env->fcr0, env->fcr31,
-                (env->CP0_Status & (1 << CP0St_FR)) != 0);
-    fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
-    fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
-    fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
-    for(i = 0; i < 32; i += 2) {
-        fpu_fprintf(f, "%s: ", fregnames[i]);
-        printfpr(FPR(env, i));
+
+    fpu_fprintf(f, "CP1 FCR0 0x%08x  FCR31 0x%08x  SR.FR %d  fp_status 0x%08x(0x%02x)\n",
+                env->fpu->fcr0, env->fpu->fcr31, is_fpu64, env->fpu->fp_status,
+                get_float_exception_flags(&env->fpu->fp_status));
+    fpu_fprintf(f, "FT0: "); printfpr(&env->fpu->ft0);
+    fpu_fprintf(f, "FT1: "); printfpr(&env->fpu->ft1);
+    fpu_fprintf(f, "FT2: "); printfpr(&env->fpu->ft2);
+    for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
+        fpu_fprintf(f, "%3s: ", fregnames[i]);
+        printfpr(&env->fpu->fpr[i]);
     }
 
 #undef printfpr
@@ -5190,16 +6664,14 @@
 
 void dump_fpu (CPUState *env)
 {
-    if (loglevel) { 
-       fprintf(logfile, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n",
-               env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
+    if (loglevel) {
+       fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n",
+               env->PC[env->current_tc], env->HI[0][env->current_tc], env->LO[0][env->current_tc], env->hflags, env->btarget, env->bcond);
        fpu_dump_state(env, logfile, fprintf, 0);
     }
 }
 
-#endif /* MIPS_USES_FPU */
-
-#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
+#if (defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
 /* Debug help: The architecture requires 32bit code to maintain proper
    sign-extened values on 64bit machines.  */
 
@@ -5211,61 +6683,50 @@
 {
     int i;
 
-    if (!SIGN_EXT_P(env->PC))
-        cpu_fprintf(f, "BROKEN: pc=0x" TLSZ "\n", env->PC);
-    if (!SIGN_EXT_P(env->HI))
-        cpu_fprintf(f, "BROKEN: HI=0x" TLSZ "\n", env->HI);
-    if (!SIGN_EXT_P(env->LO))
-        cpu_fprintf(f, "BROKEN: LO=0x" TLSZ "\n", env->LO);
+    if (!SIGN_EXT_P(env->PC[env->current_tc]))
+        cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC[env->current_tc]);
+    if (!SIGN_EXT_P(env->HI[env->current_tc]))
+        cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI[env->current_tc]);
+    if (!SIGN_EXT_P(env->LO[env->current_tc]))
+        cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO[env->current_tc]);
     if (!SIGN_EXT_P(env->btarget))
-        cpu_fprintf(f, "BROKEN: btarget=0x" TLSZ "\n", env->btarget);
+        cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget);
 
     for (i = 0; i < 32; i++) {
-        if (!SIGN_EXT_P(env->gpr[i]))
-            cpu_fprintf(f, "BROKEN: %s=0x" TLSZ "\n", regnames[i], env->gpr[i]);
+        if (!SIGN_EXT_P(env->gpr[i][env->current_tc]))
+            cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i][env->current_tc]);
     }
 
     if (!SIGN_EXT_P(env->CP0_EPC))
-        cpu_fprintf(f, "BROKEN: EPC=0x" TLSZ "\n", env->CP0_EPC);
+        cpu_fprintf(f, "BROKEN: EPC=0x" TARGET_FMT_lx "\n", env->CP0_EPC);
     if (!SIGN_EXT_P(env->CP0_LLAddr))
-        cpu_fprintf(f, "BROKEN: LLAddr=0x" TLSZ "\n", env->CP0_LLAddr);
+        cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->CP0_LLAddr);
 }
 #endif
 
-void cpu_dump_state (CPUState *env, FILE *f, 
+void cpu_dump_state (CPUState *env, FILE *f,
                      int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                      int flags)
 {
-    uint32_t c0_status;
     int i;
-    
-    cpu_fprintf(f, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n",
-                env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
+
+    cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n",
+                env->PC[env->current_tc], env->HI[env->current_tc], env->LO[env->current_tc], env->hflags, env->btarget, env->bcond);
     for (i = 0; i < 32; i++) {
         if ((i & 3) == 0)
             cpu_fprintf(f, "GPR%02d:", i);
-        cpu_fprintf(f, " %s " TLSZ, regnames[i], env->gpr[i]);
+        cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i][env->current_tc]);
         if ((i & 3) == 3)
             cpu_fprintf(f, "\n");
     }
 
-    c0_status = env->CP0_Status;
-    if (env->hflags & MIPS_HFLAG_UM)
-        c0_status |= (1 << CP0St_UM);
-    if (env->hflags & MIPS_HFLAG_ERL)
-        c0_status |= (1 << CP0St_ERL);
-    if (env->hflags & MIPS_HFLAG_EXL)
-        c0_status |= (1 << CP0St_EXL);
-
-    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x" TLSZ "\n",
-                c0_status, env->CP0_Cause, env->CP0_EPC);
-    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x" TLSZ "\n",
+    cpu_fprintf(f, "CP0 Status  0x%08x Cause   0x%08x EPC    0x" TARGET_FMT_lx "\n",
+                env->CP0_Status, env->CP0_Cause, env->CP0_EPC);
+    cpu_fprintf(f, "    Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n",
                 env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
-#ifdef MIPS_USES_FPU
-    if (c0_status & (1 << CP0St_CU1))
+    if (env->hflags & MIPS_HFLAG_FPU)
         fpu_dump_state(env, f, cpu_fprintf, flags);
-#endif
-#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
+#if (defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
     cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags);
 #endif
 }
@@ -5293,39 +6754,38 @@
     if (env->hflags & MIPS_HFLAG_BMASK) {
         /* If the exception was raised from a delay slot,
          * come back to the jump.  */
-        env->CP0_ErrorEPC = env->PC - 4;
-        env->hflags &= ~MIPS_HFLAG_BMASK;
+        env->CP0_ErrorEPC = env->PC[env->current_tc] - 4;
     } else {
-        env->CP0_ErrorEPC = env->PC;
+        env->CP0_ErrorEPC = env->PC[env->current_tc];
     }
-    env->PC = (int32_t)0xBFC00000;
-#if defined (MIPS_USES_R4K_TLB)
-    env->CP0_Random = MIPS_TLB_NB - 1;
-    env->tlb_in_use = MIPS_TLB_NB;
-#endif
+    env->PC[env->current_tc] = (int32_t)0xBFC00000;
     env->CP0_Wired = 0;
     /* SMP not implemented */
     env->CP0_EBase = 0x80000000;
-    env->CP0_Config0 = MIPS_CONFIG0;
-    env->CP0_Config1 = MIPS_CONFIG1;
-    env->CP0_Config2 = MIPS_CONFIG2;
-    env->CP0_Config3 = MIPS_CONFIG3;
     env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
-    env->CP0_WatchLo = 0;
-    env->hflags = MIPS_HFLAG_ERL;
+    /* vectored interrupts not implemented, timer on int 7,
+       no performance counters. */
+    env->CP0_IntCtl = 0xe0000000;
+    {
+        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);
-    env->CP0_PRid = MIPS_CPU;
 #endif
     env->exception_index = EXCP_NONE;
 #if defined(CONFIG_USER_ONLY)
-    env->hflags |= MIPS_HFLAG_UM;
+    env->hflags = MIPS_HFLAG_UM;
     env->user_mode_only = 1;
+#else
+    env->hflags = MIPS_HFLAG_CP0;
 #endif
-#ifdef MIPS_USES_FPU
-    env->fcr0 = MIPS_FCR0;	
-#endif
-    /* XXX some guesswork here, values are CPU specific */
-    env->SYNCI_Step = 16;
-    env->CCRes = 2;
 }
+
+#include "translate_init.c"
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
new file mode 100644
index 0000000..748b9dd
--- /dev/null
+++ b/target-mips/translate_init.c
@@ -0,0 +1,448 @@
+/*
+ *  MIPS emulation for qemu: CPU initialisation routines.
+ *
+ *  Copyright (c) 2004-2005 Jocelyn Mayer
+ *  Copyright (c) 2007 Herve Poussineau
+ *
+ * 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
+ */
+
+/* CPU / CPU family specific config register values. */
+
+/* Have config1, is MIPS32R1, uses TLB, no virtual icache,
+   uncached coherency */
+#define MIPS_CONFIG0                                              \
+  ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) |      \
+   (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) |    \
+   (0x2 << CP0C0_K0))
+
+/* Have config2, no coprocessor2 attached, no MDMX support attached,
+   no performance counters, watch registers present,
+   no code compression, EJTAG present, no FPU */
+#define MIPS_CONFIG1                                              \
+((1 << CP0C1_M) |                                                 \
+ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) |            \
+ (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) |            \
+ (0 << CP0C1_FP))
+
+/* Have config3, no tertiary/secondary caches implemented */
+#define MIPS_CONFIG2                                              \
+((1 << CP0C2_M))
+
+/* No config4, no DSP ASE, no large physaddr,
+   no external interrupt controller, no vectored interupts,
+   no 1kb pages, no SmartMIPS ASE, no trace logic */
+#define MIPS_CONFIG3                                              \
+((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) |          \
+ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) |        \
+ (0 << CP0C3_SM) | (0 << CP0C3_TL))
+
+/* Define a implementation number of 1.
+   Define a major version 1, minor version 0. */
+#define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV))
+
+
+struct mips_def_t {
+    const unsigned char *name;
+    int32_t CP0_PRid;
+    int32_t CP0_Config0;
+    int32_t CP0_Config1;
+    int32_t CP0_Config2;
+    int32_t CP0_Config3;
+    int32_t CP0_Config6;
+    int32_t CP0_Config7;
+    int32_t SYNCI_Step;
+    int32_t CCRes;
+    int32_t CP0_Status_rw_bitmask;
+    int32_t CP0_TCStatus_rw_bitmask;
+    int32_t CP0_SRSCtl;
+    int32_t CP1_fcr0;
+    int32_t SEGBITS;
+    int32_t CP0_SRSConf0_rw_bitmask;
+    int32_t CP0_SRSConf0;
+    int32_t CP0_SRSConf1_rw_bitmask;
+    int32_t CP0_SRSConf1;
+    int32_t CP0_SRSConf2_rw_bitmask;
+    int32_t CP0_SRSConf2;
+    int32_t CP0_SRSConf3_rw_bitmask;
+    int32_t CP0_SRSConf3;
+    int32_t CP0_SRSConf4_rw_bitmask;
+    int32_t CP0_SRSConf4;
+    int insn_flags;
+};
+
+/*****************************************************************************/
+/* MIPS CPU definitions */
+static mips_def_t mips_defs[] =
+{
+    {
+        .name = "4Kc",
+        .CP0_PRid = 0x00018000,
+        .CP0_Config0 = MIPS_CONFIG0,
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
+        .insn_flags = CPU_MIPS32 | ASE_MIPS16,
+    },
+    {
+        .name = "4KEcR1",
+        .CP0_PRid = 0x00018400,
+        .CP0_Config0 = MIPS_CONFIG0,
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
+        .insn_flags = CPU_MIPS32 | ASE_MIPS16,
+    },
+    {
+        .name = "4KEc",
+        .CP0_PRid = 0x00019000,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x1278FF17,
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16,
+    },
+    {
+        .name = "24Kc",
+        .CP0_PRid = 0x00019300,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU) |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x1278FF1F,
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
+    },
+    {
+        .name = "24Kf",
+        .CP0_PRid = 0x00019300,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt),
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x3678FF1F,
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
+    },
+    {
+        .name = "34Kf",
+        .CP0_PRid = 0x00019500,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU) |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3 | (0 << CP0C3_VInt) | (1 << CP0C3_MT),
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        /* No DSP implemented. */
+        .CP0_Status_rw_bitmask = 0x3678FF1F,
+        /* No DSP implemented. */
+        .CP0_TCStatus_rw_bitmask = (0 << CP0TCSt_TCU3) | (0 << CP0TCSt_TCU2) |
+                    (1 << CP0TCSt_TCU1) | (1 << CP0TCSt_TCU0) |
+                    (0 << CP0TCSt_TMX) | (1 << CP0TCSt_DT) |
+                    (1 << CP0TCSt_DA) | (1 << CP0TCSt_A) |
+                    (0x3 << CP0TCSt_TKSU) | (1 << CP0TCSt_IXMT) |
+                    (0xff << CP0TCSt_TASID),
+        .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+                    (1 << FCR0_D) | (1 << FCR0_S) | (0x95 << FCR0_PRID),
+        .CP0_SRSCtl = (0xf << CP0SRSCtl_HSS),
+        .CP0_SRSConf0_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf0 = (1 << CP0SRSC0_M) | (0x3fe << CP0SRSC0_SRS3) |
+                    (0x3fe << CP0SRSC0_SRS2) | (0x3fe << CP0SRSC0_SRS1),
+        .CP0_SRSConf1_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf1 = (1 << CP0SRSC1_M) | (0x3fe << CP0SRSC1_SRS6) |
+                    (0x3fe << CP0SRSC1_SRS5) | (0x3fe << CP0SRSC1_SRS4),
+        .CP0_SRSConf2_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf2 = (1 << CP0SRSC2_M) | (0x3fe << CP0SRSC2_SRS9) |
+                    (0x3fe << CP0SRSC2_SRS8) | (0x3fe << CP0SRSC2_SRS7),
+        .CP0_SRSConf3_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf3 = (1 << CP0SRSC3_M) | (0x3fe << CP0SRSC3_SRS12) |
+                    (0x3fe << CP0SRSC3_SRS11) | (0x3fe << CP0SRSC3_SRS10),
+        .CP0_SRSConf4_rw_bitmask = 0x3fffffff,
+        .CP0_SRSConf4 = (0x3fe << CP0SRSC4_SRS15) |
+                    (0x3fe << CP0SRSC4_SRS14) | (0x3fe << CP0SRSC4_SRS13),
+        .insn_flags = CPU_MIPS32R2 | ASE_MIPS16 | ASE_DSP,
+    },
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    {
+        .name = "R4000",
+        .CP0_PRid = 0x00000400,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) |
+		    (0 << CP0C1_IS) | (3 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (0 << CP0C1_DS) | (3 << CP0C1_DL) | (1 << CP0C1_DA),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .SYNCI_Step = 16,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x3678FFFF,
+	/* The R4000 has a full 64bit FPU doesn't use the fcr0 bits. */
+        .CP1_fcr0 = (0x5 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 40,
+        .insn_flags = CPU_MIPS3,
+    },
+    {
+        .name = "5Kc",
+        .CP0_PRid = 0x00018100,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT),
+        .CP0_Config1 = MIPS_CONFIG1 | (31 << CP0C1_MMU) |
+		    (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
+		    (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x32F8FFFF,
+        .SEGBITS = 42,
+        .insn_flags = CPU_MIPS64,
+    },
+    {
+        .name = "5Kf",
+        .CP0_PRid = 0x00018100,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (31 << CP0C1_MMU) |
+		    (1 << CP0C1_IS) | (4 << CP0C1_IL) | (1 << CP0C1_IA) |
+		    (1 << CP0C1_DS) | (4 << CP0C1_DL) | (1 << CP0C1_DA) |
+		    (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x36F8FFFF,
+	/* The 5Kf has F64 / L / W but doesn't use the fcr0 bits. */
+        .CP1_fcr0 = (1 << FCR0_D) | (1 << FCR0_S) |
+                    (0x81 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 42,
+        .insn_flags = CPU_MIPS64,
+    },
+    {
+        .name = "20Kc",
+	/* We emulate a later version of the 20Kc, earlier ones had a broken
+           WAIT instruction. */
+        .CP0_PRid = 0x000182a0,
+        .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT) | (1 << CP0C0_VI),
+        .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU) |
+		    (2 << CP0C1_IS) | (4 << CP0C1_IL) | (3 << CP0C1_IA) |
+		    (2 << CP0C1_DS) | (4 << CP0C1_DL) | (3 << CP0C1_DA) |
+		    (1 << CP0C1_PC) | (1 << CP0C1_WR) | (1 << CP0C1_EP),
+        .CP0_Config2 = MIPS_CONFIG2,
+        .CP0_Config3 = MIPS_CONFIG3,
+        .SYNCI_Step = 32,
+        .CCRes = 2,
+        .CP0_Status_rw_bitmask = 0x36FBFFFF,
+	/* The 20Kc has F64 / L / W but doesn't use the fcr0 bits. */
+        .CP1_fcr0 = (1 << FCR0_3D) | (1 << FCR0_PS) |
+                    (1 << FCR0_D) | (1 << FCR0_S) |
+                    (0x82 << FCR0_PRID) | (0x0 << FCR0_REV),
+        .SEGBITS = 40,
+        .insn_flags = CPU_MIPS64 | ASE_MIPS3D,
+    },
+#endif
+};
+
+int mips_find_by_name (const unsigned char *name, mips_def_t **def)
+{
+    int i, ret;
+
+    ret = -1;
+    *def = NULL;
+    for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) {
+        if (strcasecmp(name, mips_defs[i].name) == 0) {
+            *def = &mips_defs[i];
+            ret = 0;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+    int i;
+
+    for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) {
+        (*cpu_fprintf)(f, "MIPS '%s'\n",
+                       mips_defs[i].name);
+    }
+}
+
+#ifndef CONFIG_USER_ONLY
+static void no_mmu_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->tlb->nb_tlb = 1;
+    env->tlb->map_address = &no_mmu_map_address;
+}
+
+static void fixed_mmu_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->tlb->nb_tlb = 1;
+    env->tlb->map_address = &fixed_mmu_map_address;
+}
+
+static void r4k_mmu_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->tlb->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);
+    env->tlb->map_address = &r4k_map_address;
+    env->tlb->do_tlbwi = r4k_do_tlbwi;
+    env->tlb->do_tlbwr = r4k_do_tlbwr;
+    env->tlb->do_tlbp = r4k_do_tlbp;
+    env->tlb->do_tlbr = r4k_do_tlbr;
+}
+
+static void mmu_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->tlb = qemu_mallocz(sizeof(CPUMIPSTLBContext));
+
+    /* There are more full-featured MMU variants in older MIPS CPUs,
+       R3000, R6000 and R8000 come to mind. If we ever support them,
+       this check will need to look up a different place than those
+       newfangled config registers. */
+    switch ((env->CP0_Config0 >> CP0C0_MT) & 3) {
+        case 0:
+            no_mmu_init(env, def);
+            break;
+        case 1:
+            r4k_mmu_init(env, def);
+            break;
+        case 3:
+            fixed_mmu_init(env, def);
+            break;
+        default:
+            cpu_abort(env, "MMU type not supported\n");
+    }
+    env->CP0_Random = env->tlb->nb_tlb - 1;
+    env->tlb->tlb_in_use = env->tlb->nb_tlb;
+}
+#endif /* CONFIG_USER_ONLY */
+
+static void fpu_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->fpu = qemu_mallocz(sizeof(CPUMIPSFPUContext));
+
+    env->fpu->fcr0 = def->CP1_fcr0;
+#ifdef CONFIG_USER_ONLY
+    if (env->CP0_Config1 & (1 << CP0C1_FP))
+        env->hflags |= MIPS_HFLAG_FPU;
+    if (env->fpu->fcr0 & (1 << FCR0_F64))
+        env->hflags |= MIPS_HFLAG_F64;
+#endif
+}
+
+static void mvp_init (CPUMIPSState *env, mips_def_t *def)
+{
+    env->mvp = qemu_mallocz(sizeof(CPUMIPSMVPContext));
+
+    /* MVPConf1 implemented, TLB sharable, no gating storage support,
+       programmable cache partitioning implemented, number of allocatable
+       and sharable TLB entries, MVP has allocatable TCs, 2 VPEs
+       implemented, 5 TCs implemented. */
+    env->mvp->CP0_MVPConf0 = (1 << CP0MVPC0_M) | (1 << CP0MVPC0_TLBS) |
+                             (0 << CP0MVPC0_GS) | (1 << CP0MVPC0_PCP) |
+#ifndef CONFIG_USER_ONLY
+                             /* Usermode has no TLB support */
+                             (env->tlb->nb_tlb << CP0MVPC0_PTLBE) |
+#endif
+// TODO: actually do 2 VPEs.
+//                             (1 << CP0MVPC0_TCA) | (0x1 << CP0MVPC0_PVPE) |
+//                             (0x04 << CP0MVPC0_PTC);
+                             (1 << CP0MVPC0_TCA) | (0x0 << CP0MVPC0_PVPE) |
+                             (0x04 << CP0MVPC0_PTC);
+    /* Allocatable CP1 have media extensions, allocatable CP1 have FP support,
+       no UDI implemented, no CP2 implemented, 1 CP1 implemented. */
+    env->mvp->CP0_MVPConf1 = (1 << CP0MVPC1_CIM) | (1 << CP0MVPC1_CIF) |
+                             (0x0 << CP0MVPC1_PCX) | (0x0 << CP0MVPC1_PCP2) |
+                             (0x1 << CP0MVPC1_PCP1);
+}
+
+int cpu_mips_register (CPUMIPSState *env, mips_def_t *def)
+{
+    if (!def)
+        def = env->cpu_model;
+    if (!def)
+        cpu_abort(env, "Unable to find MIPS CPU definition\n");
+    env->cpu_model = def;
+    env->CP0_PRid = def->CP0_PRid;
+    env->CP0_Config0 = def->CP0_Config0;
+#ifdef TARGET_WORDS_BIGENDIAN
+    env->CP0_Config0 |= (1 << CP0C0_BE);
+#endif
+    env->CP0_Config1 = def->CP0_Config1;
+    env->CP0_Config2 = def->CP0_Config2;
+    env->CP0_Config3 = def->CP0_Config3;
+    env->CP0_Config6 = def->CP0_Config6;
+    env->CP0_Config7 = def->CP0_Config7;
+    env->SYNCI_Step = def->SYNCI_Step;
+    env->CCRes = def->CCRes;
+    env->CP0_Status_rw_bitmask = def->CP0_Status_rw_bitmask;
+    env->CP0_TCStatus_rw_bitmask = def->CP0_TCStatus_rw_bitmask;
+    env->CP0_SRSCtl = def->CP0_SRSCtl;
+#if defined(TARGET_MIPSN32) || defined(TARGET_MIPS64)
+    if (def->insn_flags & ISA_MIPS3)
+    {
+        env->hflags |= MIPS_HFLAG_64;
+        env->SEGBITS = def->SEGBITS;
+        env->SEGMask = (3ULL << 62) | ((1ULL << def->SEGBITS) - 1);
+    } else {
+        env->SEGBITS = 32;
+        env->SEGMask = 0xFFFFFFFF;
+    }
+#endif
+    env->CP0_SRSConf0_rw_bitmask = def->CP0_SRSConf0_rw_bitmask;
+    env->CP0_SRSConf0 = def->CP0_SRSConf0;
+    env->CP0_SRSConf1_rw_bitmask = def->CP0_SRSConf1_rw_bitmask;
+    env->CP0_SRSConf1 = def->CP0_SRSConf1;
+    env->CP0_SRSConf2_rw_bitmask = def->CP0_SRSConf2_rw_bitmask;
+    env->CP0_SRSConf2 = def->CP0_SRSConf2;
+    env->CP0_SRSConf3_rw_bitmask = def->CP0_SRSConf3_rw_bitmask;
+    env->CP0_SRSConf3 = def->CP0_SRSConf3;
+    env->CP0_SRSConf4_rw_bitmask = def->CP0_SRSConf4_rw_bitmask;
+    env->CP0_SRSConf4 = def->CP0_SRSConf4;
+    env->insn_flags = def->insn_flags;
+
+#ifndef CONFIG_USER_ONLY
+    mmu_init(env, def);
+#endif
+    fpu_init(env, def);
+    mvp_init(env, def);
+    return 0;
+}
diff --git a/target-ppc/STATUS b/target-ppc/STATUS
new file mode 100644
index 0000000..b4daa97
--- /dev/null
+++ b/target-ppc/STATUS
@@ -0,0 +1,510 @@
+PowerPC emulation status.
+The goal of this file is to provide a reference status to avoid regressions.
+
+===============================================================================
+PowerPC core emulation status
+
+INSN: instruction set.
+      OK => all instructions are emulated
+      KO => some insns are missing or some should be removed
+      ?  => unchecked
+SPR:  special purpose registers set
+      OK => all SPR registered (but some may be fake)
+      KO => some SPR are missing or should be removed
+      ?  => uncheked
+MSR:  MSR bits definitions
+      OK => all MSR bits properly defined
+      KO => MSR definition is incorrect
+      ?  => unchecked
+IRQ:  input signals definitions (mostly interrupts)
+      OK => input signals are properly defined
+      KO => input signals are not implemented (system emulation does not work)
+      ?  => input signals definitions may be incorrect
+MMU:  MMU model implementation
+      OK => MMU model is implemented and Linux is able to boot
+      KO => MMU model not implemented or bugged
+      ?  => MMU model not tested
+EXCP: exceptions model implementation
+      OK => exception model is implemented and Linux is able to boot
+      KO => exception model not implemented or known to be buggy
+      ?  => exception model may be incorrect or is untested
+
+Embedded PowerPC cores
+***
+PowerPC 401:
+INSN  OK
+SPR   OK 401A1
+MSR   OK
+IRQ   KO partially implemented
+MMU   OK
+EXCP  ?
+
+PowerPC 401x2:
+INSN  OK
+SPR   OK 401B2 401C2 401D2 401E2 401F2
+MSR   OK
+IRQ   KO partially implemented
+MMU   OK
+EXCP  ?
+
+PowerPC IOP480:
+INSN  OK
+SPR   OK IOP480
+MSR   OK
+IRQ   KO partially implemented
+MMU   OK
+EXCP  ?
+
+To be checked: 401G2 401B3 Cobra
+
+***
+PowerPC 403:
+INSN  OK
+SPR   OK 403GA 403GB
+MMU   OK
+MSR   OK
+IRQ   KO not implemented
+EXCP  ?
+
+PowerPC 403GCX:
+INSN  OK
+SPR   OK 403GCX
+MMU   OK
+MSR   OK
+IRQ   KO not implemented
+EXCP  ?
+
+To be checked: 403GC
+
+***
+PowerPC 405:
+Checked: 405CRa 405CRb 405CRc 405EP 405GPa 405GPb 405GPc 405GPd 405GPe 405GPR
+         Npe405H Npe405H2 Npe405L
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+=> Linux 2.4 boots (at least 1 proprietary firmware).
+
+To be checked: 405D2 405D4 405EZ 405LP Npe4GS3 STB03 STB04 STB25
+               x2vp4 x2vp7 x2vp20 x2vp50
+
+XXX: find what is IBM e407b4
+
+***
+PowerPC 440:
+Checked: 440EPa 440EPb 440GXa 440GXb 440GXc 440GXf 440SP 440SP2
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+
+PowerPC 440GP:
+Checked: 440GPb 440GPc
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+
+PowerPC 440x4:
+Checked: 440A4 440B4 440G4 440H4
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+
+PowerPC 440x5:
+Checked: 440A5 440F5 440G5 440H6 440GRa
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+
+To be checked: 440EPx 440GRx 440SPE
+
+***
+PowerPC 460: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+PowerPC 460F: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+PowerPC e200: (not implemented)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+PowerPC e300: (not implemented)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+PowerPC e500: (not implemented)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+PowerPC e600: (not implemented)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+***
+32 bits PowerPC
+PowerPC 601: (601 601v2)
+INSN  OK
+SPR   OK is HID15 only on 601v2 ?
+MSR   OK
+IRQ   KO not implemented
+MMU   ?
+EXCP  ?
+Remarks: some instructions should have a specific behavior (not implemented)
+
+PowerPC 602: 602
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   ?
+EXCP  ? at least timer and external interrupt are OK
+Remarks: Linux crashes when entering user-mode. But it seems it does not
+         know about this CPU. As this CPU is close to 603e, it should be OK.
+
+PowerPC 603: (603)
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots and properly recognizes the CPU
+
+PowerPC 603e: (603e11)
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots and properly recognizes the CPU
+
+PowerPC G2:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots, recognizes the CPU as a 82xx.
+
+PowerPC G2le:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 does not boots. Same symptoms as 602.
+
+PowerPC 604:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots and properly recognizes the CPU.
+
+PowerPC 7x0:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots and properly recognizes the CPU.
+
+PowerPC 750fx:
+INSN  OK
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  OK
+Remarks: Linux 2.4 boots but does not properly recognizes the CPU.
+
+PowerPC 7x5:
+INSN  ?
+SPR   ?
+MSR   ?
+IRQ   OK
+MMU   ?
+EXCP  OK
+=> Linux 2.4 does not boot.
+
+PowerPC 7400:
+INSN  KO Altivec missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  ?  Altivec, ...
+=> Linux 2.4 boots and properly recognize the CPU.
+
+PowerPC 7410:
+INSN  KO Altivec missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   OK
+EXCP  ?  Altivec, ...
+=> Linux 2.4 boots and properly recognize the CPU.
+   Note that UM says tlbld & tlbli are implemented bus this may be a mistake
+   as TLB load are managed by the hardware and it does not implement the
+   needed registers.
+
+PowerPC 7441:
+INSN  KO Altivec missing + TLB load insns missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   KO not implemented
+EXCP  ?  Altivec, ...
+
+PowerPC 7450/7451:
+INSN  KO Altivec missing + TLB load insns missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   KO not implemented
+EXCP  ?  Altivec, ...
+
+PowerPC 7445/7447:
+INSN  KO Altivec missing + TLB load insns missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   KO not implemented
+EXCP  ?  Altivec, ...
+
+PowerPC 7455/7457:
+INSN  KO Altivec missing + TLB load insns missing
+SPR   OK
+MSR   OK
+IRQ   OK
+MMU   KO not implemented
+EXCP  ?  Altivec, ...
+
+64 bits PowerPC
+PowerPC 620: (disabled)
+INSN  KO
+SPR   KO
+MSR   ?
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+PowerPC 970: (disabled)
+INSN  KO Altivec missing and more
+SPR   KO
+MSR   ?
+IRQ   OK
+MMU   KO partially implemented
+EXCP  KO
+
+PowerPC 970FX: (disabled)
+INSN  KO Altivec missing and more
+SPR   KO
+MSR   ?
+IRQ   OK
+MMU   KO partially implemented
+EXCP  KO
+
+PowerPC 630: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+PowerPC 631: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER4: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER4+: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER5: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER5+: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER6: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+RS64: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+RS64-II: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+RS64-III: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+RS64-IV: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+Original POWER
+POWER: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+POWER2: (disabled: lack of detailed specifications)
+INSN  KO
+SPR   KO
+MSR   KO
+IRQ   KO
+MMU   KO
+EXCP  KO
+
+===============================================================================
+PowerPC microcontrollers emulation status
+
+Implemementation should be sufficient to boot Linux:
+- PowerPC 405CR
+- PowerPC 405EP
+
+TODO:
+- More PowerPC 40x microcontrollers emulation
+- PowerQUICC microcontrollers emulation
+
+===============================================================================
+PowerPC based platforms emulation status
+
+* PREP platform (RS/6000 7043...) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* heathrow PowerMac platform (beige PowerMac) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* mac99 platform (white and blue PowerMac, ...)
+- Gentoo Linux live CDROM 1.4 - boots, compiles linux kernel
+- Debian Linux woody - boots from CDROM and HDD
+- Mandrake Linux 9 - boots from CDROM, freezes during install
+- Knoppix 2003-07-13_4 boots from CDROM, pb with X configuration
+  distribution bug: X runs with a properly hand-coded configuration.
+- rock Linux 2.0 runs from CDROM
+
+* Linux 2.6 support seems deadly broken (used to boot...).
+
+* PowerPC 405EP reference boards:
+- can boot Linux 2.4 & 2.6.
+  Need to provide a flash image ready to boot for reproductible tests.
+
+TODO:
+- MCA based RS/6000 emulation
+- CHRP emulation (not PowerMac)
+- PPAR emulation
+- ePPAR emulation
+- misc PowerPC reference boards emulation
+
+===============================================================================
+(to be completed)
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index b294e31..c4ae414 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation cpu definitions for qemu.
- * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -21,18 +21,66 @@
 #define __CPU_PPC_H__
 
 #include "config.h"
+#include <inttypes.h>
 
+#if defined (TARGET_PPC64)
+typedef uint64_t ppc_gpr_t;
+#define TARGET_GPR_BITS  64
+#define TARGET_LONG_BITS 64
+#define REGX "%016" PRIx64
+#define TARGET_PAGE_BITS 12
+#elif defined(TARGET_PPCEMB)
+/* BookE have 36 bits physical address space */
+#define TARGET_PHYS_ADDR_BITS 64
+/* GPR are 64 bits: used by vector extension */
+typedef uint64_t ppc_gpr_t;
+#define TARGET_GPR_BITS  64
 #define TARGET_LONG_BITS 32
+#define REGX "%016" PRIx64
+#if defined(CONFIG_USER_ONLY)
+/* It looks like a lot of Linux programs assume page size
+ * is 4kB long. This is evil, but we have to deal with it...
+ */
+#define TARGET_PAGE_BITS 12
+#else
+/* Pages can be 1 kB small */
+#define TARGET_PAGE_BITS 10
+#endif
+#else
+#if (HOST_LONG_BITS >= 64)
+/* When using 64 bits temporary registers,
+ * we can use 64 bits GPR with no extra cost
+ * It's even an optimization as it will prevent
+ * the compiler to do unuseful masking in the micro-ops.
+ */
+typedef uint64_t ppc_gpr_t;
+#define TARGET_GPR_BITS  64
+#define REGX "%08" PRIx64
+#else
+typedef uint32_t ppc_gpr_t;
+#define TARGET_GPR_BITS  32
+#define REGX "%08" PRIx32
+#endif
+#define TARGET_LONG_BITS 32
+#define TARGET_PAGE_BITS 12
+#endif
 
 #include "cpu-defs.h"
 
+#define ADDRX TARGET_FMT_lx
+#define PADDRX TARGET_FMT_plx
+
 #include <setjmp.h>
 
 #include "softfloat.h"
 
 #define TARGET_HAS_ICE 1
 
-#define ELF_MACHINE	EM_PPC
+#if defined (TARGET_PPC64)
+#define ELF_MACHINE     EM_PPC64
+#else
+#define ELF_MACHINE     EM_PPC
+#endif
 
 /* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC
  *                              have different cache line sizes
@@ -40,321 +88,230 @@
 #define ICACHE_LINE_SIZE 32
 #define DCACHE_LINE_SIZE 32
 
-/* XXX: put this in a common place */
-#define likely(x)   __builtin_expect(!!(x), 1)
-
 /*****************************************************************************/
-/* PVR definitions for most known PowerPC */
+/* MMU model                                                                 */
 enum {
-    /* PowerPC 401 cores */
-    CPU_PPC_401A1     = 0x00210000,
-    CPU_PPC_401B2     = 0x00220000,
-    CPU_PPC_401C2     = 0x00230000,
-    CPU_PPC_401D2     = 0x00240000,
-    CPU_PPC_401E2     = 0x00250000,
-    CPU_PPC_401F2     = 0x00260000,
-    CPU_PPC_401G2     = 0x00270000,
-    CPU_PPC_IOP480    = 0x40100000,
-    /* PowerPC 403 cores */
-    CPU_PPC_403GA     = 0x00200000,
-    CPU_PPC_403GB     = 0x00200100,
-    CPU_PPC_403GC     = 0x00200200,
-    CPU_PPC_403GCX    = 0x00201400,
-    /* PowerPC 405 cores */
-    CPU_PPC_405       = 0x40110000,
-    CPU_PPC_405EP     = 0x51210000,
-    CPU_PPC_405GPR    = 0x50910000,
-    CPU_PPC_405D2     = 0x20010000,
-    CPU_PPC_405D4     = 0x41810000,
-    CPU_PPC_NPE405H   = 0x41410000,
-    CPU_PPC_NPE405L   = 0x41610000,
-#if 0
-    CPU_PPC_STB02     = xxx,
-#endif
-    CPU_PPC_STB03     = 0x40310000,
-#if 0
-    CPU_PPC_STB04     = xxx,
-#endif
-    CPU_PPC_STB25     = 0x51510000,
-#if 0
-    CPU_PPC_STB130    = xxx,
-#endif
-    /* PowerPC 440 cores */
-    CPU_PPC_440EP     = 0x42220000,
-    CPU_PPC_440GP     = 0x40120400,
-    CPU_PPC_440GX     = 0x51B20000,
-    /* PowerPC MPC 8xx cores */
-    CPU_PPC_8540      = 0x80200000,
-    CPU_PPC_8xx       = 0x00500000,
-    CPU_PPC_8240      = 0x00810100,
-    CPU_PPC_8245      = 0x00811014,
-    /* PowerPC 6xx cores */
-    CPU_PPC_601       = 0x00010000,
-    CPU_PPC_602       = 0x00050000,
-    CPU_PPC_603       = 0x00030000,
-    CPU_PPC_603E      = 0x00060000,
-    CPU_PPC_603EV     = 0x00070000,
-    CPU_PPC_603R      = 0x00071000,
-    CPU_PPC_G2        = 0x80810000,
-    CPU_PPC_G2LE      = 0x80820000,
-    CPU_PPC_604       = 0x00040000,
-    CPU_PPC_604E      = 0x00090000,
-    CPU_PPC_604R      = 0x000a0000,
-    /* PowerPC 74x/75x cores (aka G3) */
-    CPU_PPC_74x       = 0x00080000,
-    CPU_PPC_755       = 0x00083000,
-    CPU_PPC_74xP      = 0x10080000,
-    CPU_PPC_750CXE22  = 0x00082202,
-    CPU_PPC_750CXE24  = 0x00082214,
-    CPU_PPC_750CXE24b = 0x00083214,
-    CPU_PPC_750CXE31  = 0x00083211,
-    CPU_PPC_750CXE31b = 0x00083311,
-#define CPU_PPC_750CXE CPU_PPC_750CXE31b
-    CPU_PPC_750FX     = 0x70000000,
-    CPU_PPC_750GX     = 0x70020000,
-    /* PowerPC 74xx cores (aka G4) */
-    CPU_PPC_7400      = 0x000C0000,
-    CPU_PPC_7410      = 0x800C0000,
-    CPU_PPC_7441      = 0x80000200,
-    CPU_PPC_7450      = 0x80000000,
-    CPU_PPC_7451      = 0x80000203,
-    CPU_PPC_7455      = 0x80010000,
-    CPU_PPC_7457      = 0x80020000,
-    CPU_PPC_7457A     = 0x80030000,
-    /* 64 bits PowerPC */
-    CPU_PPC_620       = 0x00140000,
-    CPU_PPC_630       = 0x00400000,
-    CPU_PPC_631       = 0x00410000,
-    CPU_PPC_POWER4    = 0x00350000,
-    CPU_PPC_POWER4P   = 0x00380000,
-    CPU_PPC_POWER5    = 0x003A0000,
-    CPU_PPC_POWER5P   = 0x003B0000,
-    CPU_PPC_970       = 0x00390000,
-    CPU_PPC_970FX     = 0x003C0000,
-    CPU_PPC_RS64      = 0x00330000,
-    CPU_PPC_RS64II    = 0x00340000,
-    CPU_PPC_RS64III   = 0x00360000,
-    CPU_PPC_RS64IV    = 0x00370000,
-    /* Original POWER */
-    /* XXX: should be POWER (RIOS), RSC3308, RSC4608,
-     * POWER2 (RIOS2) & RSC2 (P2SC) here
-     */
-#if 0
-    CPU_POWER         = xxx,
-#endif
-#if 0
-    CPU_POWER2        = xxx,
-#endif
-};
-
-/* System version register (used on MPC 8xx) */
-enum {
-    PPC_SVR_8540      = 0x80300000,
-    PPC_SVR_8541E     = 0x807A0000,
-    PPC_SVR_8555E     = 0x80790000,
-    PPC_SVR_8560      = 0x80700000,
+    POWERPC_MMU_UNKNOWN    = 0,
+    /* Standard 32 bits PowerPC MMU                            */
+    POWERPC_MMU_32B,
+    /* Standard 64 bits PowerPC MMU                            */
+    POWERPC_MMU_64B,
+    /* PowerPC 601 MMU                                         */
+    POWERPC_MMU_601,
+    /* PowerPC 6xx MMU with software TLB                       */
+    POWERPC_MMU_SOFT_6xx,
+    /* PowerPC 74xx MMU with software TLB                      */
+    POWERPC_MMU_SOFT_74xx,
+    /* PowerPC 4xx MMU with software TLB                       */
+    POWERPC_MMU_SOFT_4xx,
+    /* PowerPC 4xx MMU with software TLB and zones protections */
+    POWERPC_MMU_SOFT_4xx_Z,
+    /* PowerPC 4xx MMU in real mode only                       */
+    POWERPC_MMU_REAL_4xx,
+    /* BookE MMU model                                         */
+    POWERPC_MMU_BOOKE,
+    /* BookE FSL MMU model                                     */
+    POWERPC_MMU_BOOKE_FSL,
+    /* 64 bits "bridge" PowerPC MMU                            */
+    POWERPC_MMU_64BRIDGE,
 };
 
 /*****************************************************************************/
-/* Instruction types */
+/* Exception model                                                           */
 enum {
-    PPC_NONE        = 0x00000000,
-    /* integer operations instructions             */
-    /* flow control instructions                   */
-    /* virtual memory instructions                 */
-    /* ld/st with reservation instructions         */
-    /* cache control instructions                  */
-    /* spr/msr access instructions                 */
-    PPC_INSNS_BASE  = 0x00000001,
-#define PPC_INTEGER PPC_INSNS_BASE
-#define PPC_FLOW    PPC_INSNS_BASE
-#define PPC_MEM     PPC_INSNS_BASE
-#define PPC_RES     PPC_INSNS_BASE
-#define PPC_CACHE   PPC_INSNS_BASE
-#define PPC_MISC    PPC_INSNS_BASE
-    /* floating point operations instructions      */
-    PPC_FLOAT       = 0x00000002,
-    /* more floating point operations instructions */
-    PPC_FLOAT_EXT   = 0x00000004,
-    /* external control instructions               */
-    PPC_EXTERN      = 0x00000008,
-    /* segment register access instructions        */
-    PPC_SEGMENT     = 0x00000010,
-    /* Optional cache control instructions         */
-    PPC_CACHE_OPT   = 0x00000020,
-    /* Optional floating point op instructions     */
-    PPC_FLOAT_OPT   = 0x00000040,
-    /* Optional memory control instructions        */
-    PPC_MEM_TLBIA   = 0x00000080,
-    PPC_MEM_TLBIE   = 0x00000100,
-    PPC_MEM_TLBSYNC = 0x00000200,
-    /* eieio & sync                                */
-    PPC_MEM_SYNC    = 0x00000400,
-    /* PowerPC 6xx TLB management instructions     */
-    PPC_6xx_TLB     = 0x00000800,
-    /* Altivec support                             */
-    PPC_ALTIVEC     = 0x00001000,
-    /* Time base support                           */
-    PPC_TB          = 0x00002000,
-    /* Embedded PowerPC dedicated instructions     */
-    PPC_4xx_COMMON  = 0x00004000,
-    /* PowerPC 40x exception model                 */
-    PPC_40x_EXCP    = 0x00008000,
-    /* PowerPC 40x specific instructions           */
-    PPC_40x_SPEC    = 0x00010000,
-    /* PowerPC 405 Mac instructions                */
-    PPC_405_MAC     = 0x00020000,
-    /* PowerPC 440 specific instructions           */
-    PPC_440_SPEC    = 0x00040000,
-    /* Specific extensions */
-    /* Power-to-PowerPC bridge (601)               */
-    PPC_POWER_BR    = 0x00080000,
-    /* PowerPC 602 specific */
-    PPC_602_SPEC    = 0x00100000,
-    /* Deprecated instructions                     */
-    /* Original POWER instruction set              */
-    PPC_POWER       = 0x00200000,
-    /* POWER2 instruction set extension            */
-    PPC_POWER2      = 0x00400000,
-    /* Power RTC support */
-    PPC_POWER_RTC   = 0x00800000,
-    /* 64 bits PowerPC instructions                */
-    /* 64 bits PowerPC instruction set             */
-    PPC_64B         = 0x01000000,
-    /* 64 bits hypervisor extensions               */
-    PPC_64H         = 0x02000000,
-    /* 64 bits PowerPC "bridge" features           */
-    PPC_64_BRIDGE   = 0x04000000,
-};
-
-/* CPU run-time flags (MMU and exception model) */
-enum {
-    /* MMU model */
-#define PPC_FLAGS_MMU_MASK (0x0000000F)
-    /* Standard 32 bits PowerPC MMU */
-    PPC_FLAGS_MMU_32B      = 0x00000000,
-    /* Standard 64 bits PowerPC MMU */
-    PPC_FLAGS_MMU_64B      = 0x00000001,
-    /* PowerPC 601 MMU */
-    PPC_FLAGS_MMU_601      = 0x00000002,
-    /* PowerPC 6xx MMU with software TLB */
-    PPC_FLAGS_MMU_SOFT_6xx = 0x00000003,
-    /* PowerPC 4xx MMU with software TLB */
-    PPC_FLAGS_MMU_SOFT_4xx = 0x00000004,
-    /* PowerPC 403 MMU */
-    PPC_FLAGS_MMU_403      = 0x00000005,
-    /* Exception model */
-#define PPC_FLAGS_EXCP_MASK (0x000000F0)
+    POWERPC_EXCP_UNKNOWN   = 0,
     /* Standard PowerPC exception model */
-    PPC_FLAGS_EXCP_STD     = 0x00000000,
-    /* PowerPC 40x exception model */
-    PPC_FLAGS_EXCP_40x     = 0x00000010,
-    /* PowerPC 601 exception model */
-    PPC_FLAGS_EXCP_601     = 0x00000020,
-    /* PowerPC 602 exception model */
-    PPC_FLAGS_EXCP_602     = 0x00000030,
-    /* PowerPC 603 exception model */
-    PPC_FLAGS_EXCP_603     = 0x00000040,
-    /* PowerPC 604 exception model */
-    PPC_FLAGS_EXCP_604     = 0x00000050,
-    /* PowerPC 7x0 exception model */
-    PPC_FLAGS_EXCP_7x0     = 0x00000060,
-    /* PowerPC 7x5 exception model */
-    PPC_FLAGS_EXCP_7x5     = 0x00000070,
-    /* PowerPC 74xx exception model */
-    PPC_FLAGS_EXCP_74xx    = 0x00000080,
-    /* PowerPC 970 exception model */
-    PPC_FLAGS_EXCP_970     = 0x00000090,
+    POWERPC_EXCP_STD,
+    /* PowerPC 40x exception model      */
+    POWERPC_EXCP_40x,
+    /* PowerPC 601 exception model      */
+    POWERPC_EXCP_601,
+    /* PowerPC 602 exception model      */
+    POWERPC_EXCP_602,
+    /* PowerPC 603 exception model      */
+    POWERPC_EXCP_603,
+    /* PowerPC 603e exception model     */
+    POWERPC_EXCP_603E,
+    /* PowerPC G2 exception model       */
+    POWERPC_EXCP_G2,
+    /* PowerPC 604 exception model      */
+    POWERPC_EXCP_604,
+    /* PowerPC 7x0 exception model      */
+    POWERPC_EXCP_7x0,
+    /* PowerPC 7x5 exception model      */
+    POWERPC_EXCP_7x5,
+    /* PowerPC 74xx exception model     */
+    POWERPC_EXCP_74xx,
+    /* PowerPC 970 exception model      */
+    POWERPC_EXCP_970,
+    /* BookE exception model            */
+    POWERPC_EXCP_BOOKE,
 };
 
-#define PPC_MMU(env) (env->flags & PPC_FLAGS_MMU_MASK)
-#define PPC_EXCP(env) (env->flags & PPC_FLAGS_EXCP_MASK)
+/*****************************************************************************/
+/* Exception vectors definitions                                             */
+enum {
+    POWERPC_EXCP_NONE    = -1,
+    /* The 64 first entries are used by the PowerPC embedded specification   */
+    POWERPC_EXCP_CRITICAL = 0,  /* Critical input                            */
+    POWERPC_EXCP_MCHECK   = 1,  /* Machine check exception                   */
+    POWERPC_EXCP_DSI      = 2,  /* Data storage exception                    */
+    POWERPC_EXCP_ISI      = 3,  /* Instruction storage exception             */
+    POWERPC_EXCP_EXTERNAL = 4,  /* External input                            */
+    POWERPC_EXCP_ALIGN    = 5,  /* Alignment exception                       */
+    POWERPC_EXCP_PROGRAM  = 6,  /* Program exception                         */
+    POWERPC_EXCP_FPU      = 7,  /* Floating-point unavailable exception      */
+    POWERPC_EXCP_SYSCALL  = 8,  /* System call exception                     */
+    POWERPC_EXCP_APU      = 9,  /* Auxiliary processor unavailable           */
+    POWERPC_EXCP_DECR     = 10, /* Decrementer exception                     */
+    POWERPC_EXCP_FIT      = 11, /* Fixed-interval timer interrupt            */
+    POWERPC_EXCP_WDT      = 12, /* Watchdog timer interrupt                  */
+    POWERPC_EXCP_DTLB     = 13, /* Data TLB error                            */
+    POWERPC_EXCP_ITLB     = 14, /* Instruction TLB error                     */
+    POWERPC_EXCP_DEBUG    = 15, /* Debug interrupt                           */
+    /* Vectors 16 to 31 are reserved                                         */
+#if defined(TARGET_PPCEMB)
+    POWERPC_EXCP_SPEU     = 32, /* SPE/embedded floating-point unavailable   */
+    POWERPC_EXCP_EFPDI    = 33, /* Embedded floating-point data interrupt    */
+    POWERPC_EXCP_EFPRI    = 34, /* Embedded floating-point round interrupt   */
+    POWERPC_EXCP_EPERFM   = 35, /* Embedded performance monitor interrupt    */
+    POWERPC_EXCP_DOORI    = 36, /* Embedded doorbell interrupt               */
+    POWERPC_EXCP_DOORCI   = 37, /* Embedded doorbell critical interrupt      */
+#endif /* defined(TARGET_PPCEMB) */
+    /* Vectors 38 to 63 are reserved                                         */
+    /* Exceptions defined in the PowerPC server specification                */
+    POWERPC_EXCP_RESET    = 64, /* System reset exception                    */
+#if defined(TARGET_PPC64) /* PowerPC 64 */
+    POWERPC_EXCP_DSEG     = 65, /* Data segment exception                    */
+    POWERPC_EXCP_ISEG     = 66, /* Instruction segment exception             */
+#endif /* defined(TARGET_PPC64) */
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+    POWERPC_EXCP_HDECR    = 67, /* Hypervisor decrementer exception          */
+#endif /* defined(TARGET_PPC64H) */
+    POWERPC_EXCP_TRACE    = 68, /* Trace exception                           */
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+    POWERPC_EXCP_HDSI     = 69, /* Hypervisor data storage exception         */
+    POWERPC_EXCP_HISI     = 70, /* Hypervisor instruction storage exception  */
+    POWERPC_EXCP_HDSEG    = 71, /* Hypervisor data segment exception         */
+    POWERPC_EXCP_HISEG    = 72, /* Hypervisor instruction segment exception  */
+#endif /* defined(TARGET_PPC64H) */
+    POWERPC_EXCP_VPU      = 73, /* Vector unavailable exception              */
+    /* 40x specific exceptions                                               */
+    POWERPC_EXCP_PIT      = 74, /* Programmable interval timer interrupt     */
+    /* 601 specific exceptions                                               */
+    POWERPC_EXCP_IO       = 75, /* IO error exception                        */
+    POWERPC_EXCP_RUNM     = 76, /* Run mode exception                        */
+    /* 602 specific exceptions                                               */
+    POWERPC_EXCP_EMUL     = 77, /* Emulation trap exception                  */
+    /* 602/603 specific exceptions                                           */
+    POWERPC_EXCP_IFTLB    = 78, /* Instruction fetch TLB error               */
+    POWERPC_EXCP_DLTLB    = 79, /* Data load TLB miss                        */
+    POWERPC_EXCP_DSTLB    = 80, /* Data store TLB miss                       */
+    /* Exceptions available on most PowerPC                                  */
+    POWERPC_EXCP_FPA      = 81, /* Floating-point assist exception           */
+    POWERPC_EXCP_IABR     = 82, /* Instruction address breakpoint            */
+    POWERPC_EXCP_SMI      = 83, /* System management interrupt               */
+    POWERPC_EXCP_PERFM    = 84, /* Embedded performance monitor interrupt    */
+    /* 7xx/74xx specific exceptions                                          */
+    POWERPC_EXCP_THERM    = 85, /* Thermal interrupt                         */
+    /* 74xx specific exceptions                                              */
+    POWERPC_EXCP_VPUA     = 86, /* Vector assist exception                   */
+    /* 970FX specific exceptions                                             */
+    POWERPC_EXCP_SOFTP    = 87, /* Soft patch exception                      */
+    POWERPC_EXCP_MAINT    = 88, /* Maintenance exception                     */
+    /* EOL                                                                   */
+    POWERPC_EXCP_NB       = 96,
+    /* Qemu exceptions: used internally during code translation              */
+    POWERPC_EXCP_STOP         = 0x200, /* stop translation                   */
+    POWERPC_EXCP_BRANCH       = 0x201, /* branch instruction                 */
+    /* Qemu exceptions: special cases we want to stop translation            */
+    POWERPC_EXCP_SYNC         = 0x202, /* context synchronizing instruction  */
+    POWERPC_EXCP_SYSCALL_USER = 0x203, /* System call in user mode only      */
+};
+
+
+/* Exceptions error codes                                                    */
+enum {
+    /* Exception subtypes for POWERPC_EXCP_ALIGN                             */
+    POWERPC_EXCP_ALIGN_FP      = 0x01,  /* FP alignment exception            */
+    POWERPC_EXCP_ALIGN_LST     = 0x02,  /* Unaligned mult/extern load/store  */
+    POWERPC_EXCP_ALIGN_LE      = 0x03,  /* Multiple little-endian access     */
+    POWERPC_EXCP_ALIGN_PROT    = 0x04,  /* Access cross protection boundary  */
+    POWERPC_EXCP_ALIGN_BAT     = 0x05,  /* Access cross a BAT/seg boundary   */
+    POWERPC_EXCP_ALIGN_CACHE   = 0x06,  /* Impossible dcbz access            */
+    /* Exception subtypes for POWERPC_EXCP_PROGRAM                           */
+    /* FP exceptions                                                         */
+    POWERPC_EXCP_FP            = 0x10,
+    POWERPC_EXCP_FP_OX         = 0x01,  /* FP overflow                       */
+    POWERPC_EXCP_FP_UX         = 0x02,  /* FP underflow                      */
+    POWERPC_EXCP_FP_ZX         = 0x03,  /* FP divide by zero                 */
+    POWERPC_EXCP_FP_XX         = 0x04,  /* FP inexact                        */
+    POWERPC_EXCP_FP_VXNAN      = 0x05,  /* FP invalid SNaN op                */
+    POWERPC_EXCP_FP_VXISI      = 0x06,  /* FP invalid infinite subtraction   */
+    POWERPC_EXCP_FP_VXIDI      = 0x07,  /* FP invalid infinite divide        */
+    POWERPC_EXCP_FP_VXZDZ      = 0x08,  /* FP invalid zero divide            */
+    POWERPC_EXCP_FP_VXIMZ      = 0x09,  /* FP invalid infinite * zero        */
+    POWERPC_EXCP_FP_VXVC       = 0x0A,  /* FP invalid compare                */
+    POWERPC_EXCP_FP_VXSOFT     = 0x0B,  /* FP invalid operation              */
+    POWERPC_EXCP_FP_VXSQRT     = 0x0C,  /* FP invalid square root            */
+    POWERPC_EXCP_FP_VXCVI      = 0x0D,  /* FP invalid integer conversion     */
+    /* Invalid instruction                                                   */
+    POWERPC_EXCP_INVAL         = 0x20,
+    POWERPC_EXCP_INVAL_INVAL   = 0x01,  /* Invalid instruction               */
+    POWERPC_EXCP_INVAL_LSWX    = 0x02,  /* Invalid lswx instruction          */
+    POWERPC_EXCP_INVAL_SPR     = 0x03,  /* Invalid SPR access                */
+    POWERPC_EXCP_INVAL_FP      = 0x04,  /* Unimplemented mandatory fp instr  */
+    /* Privileged instruction                                                */
+    POWERPC_EXCP_PRIV          = 0x30,
+    POWERPC_EXCP_PRIV_OPC      = 0x01,  /* Privileged operation exception    */
+    POWERPC_EXCP_PRIV_REG      = 0x02,  /* Privileged register exception     */
+    /* Trap                                                                  */
+    POWERPC_EXCP_TRAP          = 0x40,
+};
 
 /*****************************************************************************/
-/* Supported instruction set definitions */
-/* This generates an empty opcode table... */
-#define PPC_INSNS_TODO (PPC_NONE)
-#define PPC_FLAGS_TODO (0x00000000)
+/* Input pins model                                                          */
+enum {
+    PPC_FLAGS_INPUT_UNKNOWN = 0,
+    /* PowerPC 6xx bus                  */
+    PPC_FLAGS_INPUT_6xx,
+    /* BookE bus                        */
+    PPC_FLAGS_INPUT_BookE,
+    /* PowerPC 405 bus                  */
+    PPC_FLAGS_INPUT_405,
+    /* PowerPC 970 bus                  */
+    PPC_FLAGS_INPUT_970,
+    /* PowerPC 401 bus                  */
+    PPC_FLAGS_INPUT_401,
+};
 
-/* PowerPC 40x instruction set */
-#define PPC_INSNS_4xx (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_4xx_COMMON)
-/* PowerPC 401 */
-#define PPC_INSNS_401 (PPC_INSNS_TODO)
-#define PPC_FLAGS_401 (PPC_FLAGS_TODO)
-/* PowerPC 403 */
-#define PPC_INSNS_403 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_MEM_TLBIA |         \
-                       PPC_40x_EXCP | PPC_40x_SPEC)
-#define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x)
-/* PowerPC 405 */
-#define PPC_INSNS_405 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_CACHE_OPT |         \
-                       PPC_MEM_TLBIA | PPC_TB | PPC_40x_SPEC | PPC_40x_EXCP | \
-                       PPC_405_MAC)
-#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x)
-/* PowerPC 440 */
-#define PPC_INSNS_440 (PPC_INSNS_4xx | PPC_CACHE_OPT | PPC_405_MAC |          \
-                       PPC_440_SPEC)
-#define PPC_FLAGS_440 (PPC_FLAGS_TODO)
-/* Non-embedded PowerPC */
-#define PPC_INSNS_COMMON  (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC |        \
-                           PPC_SEGMENT | PPC_MEM_TLBIE)
-/* PowerPC 601 */
-#define PPC_INSNS_601 (PPC_INSNS_COMMON | PPC_EXTERN | PPC_POWER_BR)
-#define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601)
-/* PowerPC 602 */
-#define PPC_INSNS_602 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB |       \
-                       PPC_MEM_TLBSYNC | PPC_TB)
-#define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602)
-/* PowerPC 603 */
-#define PPC_INSNS_603 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB |       \
-                       PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB)
-#define PPC_FLAGS_603 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603)
-/* PowerPC G2 */
-#define PPC_INSNS_G2 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB |        \
-                      PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB)
-#define PPC_FLAGS_G2 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603)
-/* PowerPC 604 */
-#define PPC_INSNS_604 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN |        \
-                       PPC_MEM_TLBSYNC | PPC_TB)
-#define PPC_FLAGS_604 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_604)
-/* PowerPC 740/750 (aka G3) */
-#define PPC_INSNS_7x0 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN |        \
-                       PPC_MEM_TLBSYNC | PPC_TB)
-#define PPC_FLAGS_7x0 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_7x0)
-/* PowerPC 745/755 */
-#define PPC_INSNS_7x5 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN |        \
-                       PPC_MEM_TLBSYNC | PPC_TB | PPC_6xx_TLB)
-#define PPC_FLAGS_7x5 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_7x5)
-/* PowerPC 74xx (aka G4) */
-#define PPC_INSNS_74xx (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_ALTIVEC |      \
-                        PPC_MEM_TLBSYNC | PPC_TB)
-#define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx)
+#define PPC_INPUT(env) (env->bus_model)
 
-/* Default PowerPC will be 604/970 */
-#define PPC_INSNS_PPC32 PPC_INSNS_604
-#define PPC_FLAGS_PPC32 PPC_FLAGS_604
-#if 0
-#define PPC_INSNS_PPC64 PPC_INSNS_970
-#define PPC_FLAGS_PPC64 PPC_FLAGS_970
-#endif
-#define PPC_INSNS_DEFAULT PPC_INSNS_604
-#define PPC_FLAGS_DEFAULT PPC_FLAGS_604
+/*****************************************************************************/
 typedef struct ppc_def_t ppc_def_t;
+typedef struct opc_handler_t opc_handler_t;
 
 /*****************************************************************************/
 /* Types used to describe some PowerPC registers */
 typedef struct CPUPPCState CPUPPCState;
-typedef struct opc_handler_t opc_handler_t;
 typedef struct ppc_tb_t ppc_tb_t;
 typedef struct ppc_spr_t ppc_spr_t;
 typedef struct ppc_dcr_t ppc_dcr_t;
 typedef struct ppc_avr_t ppc_avr_t;
+typedef union ppc_tlb_t ppc_tlb_t;
 
 /* SPR access micro-ops generations callbacks */
 struct ppc_spr_t {
     void (*uea_read)(void *opaque, int spr_num);
     void (*uea_write)(void *opaque, int spr_num);
+#if !defined(CONFIG_USER_ONLY)
     void (*oea_read)(void *opaque, int spr_num);
     void (*oea_write)(void *opaque, int spr_num);
+#if defined(TARGET_PPC64H)
+    void (*hea_read)(void *opaque, int spr_num);
+    void (*hea_write)(void *opaque, int spr_num);
+#endif
+#endif
     const unsigned char *name;
 };
 
@@ -364,46 +321,58 @@
 };
 
 /* Software TLB cache */
-typedef struct ppc_tlb_t ppc_tlb_t;
-struct ppc_tlb_t {
-    /* Physical page number */
+typedef struct ppc6xx_tlb_t ppc6xx_tlb_t;
+struct ppc6xx_tlb_t {
+    target_ulong pte0;
+    target_ulong pte1;
+    target_ulong EPN;
+};
+
+typedef struct ppcemb_tlb_t ppcemb_tlb_t;
+struct ppcemb_tlb_t {
     target_phys_addr_t RPN;
-    /* Virtual page number */
-    target_ulong VPN;
-    /* Page size */
+    target_ulong EPN;
+    target_ulong PID;
     target_ulong size;
-    /* Protection bits */
-    int prot;
-    int is_user;
-    uint32_t private;
-    uint32_t flags;
+    uint32_t prot;
+    uint32_t attr; /* Storage attributes */
+};
+
+union ppc_tlb_t {
+    ppc6xx_tlb_t tlb6;
+    ppcemb_tlb_t tlbe;
 };
 
 /*****************************************************************************/
 /* Machine state register bits definition                                    */
-#define MSR_SF   63 /* Sixty-four-bit mode                                   */
+#define MSR_SF   63 /* Sixty-four-bit mode                            hflags */
 #define MSR_ISF  61 /* Sixty-four-bit interrupt mode on 630                  */
-#define MSR_HV   60 /* hypervisor state                                      */
-#define MSR_VR   25 /* altivec available                                     */
-#define MSR_AP   23 /* Access privilege state on 602                         */
-#define MSR_SA   22 /* Supervisor access mode on 602                         */
+#define MSR_HV   60 /* hypervisor state                               hflags */
+#define MSR_CM   31 /* Computation mode for BookE                     hflags */
+#define MSR_ICM  30 /* Interrupt computation mode for BookE                  */
+#define MSR_UCLE 26 /* User-mode cache lock enable for BookE                 */
+#define MSR_VR   25 /* altivec available                              hflags */
+#define MSR_SPE  25 /* SPE enable for BookE                           hflags */
+#define MSR_AP   23 /* Access privilege state on 602                  hflags */
+#define MSR_SA   22 /* Supervisor access mode on 602                  hflags */
 #define MSR_KEY  19 /* key bit on 603e                                       */
 #define MSR_POW  18 /* Power management                                      */
 #define MSR_WE   18 /* Wait state enable on embedded PowerPC                 */
 #define MSR_TGPR 17 /* TGPR usage on 602/603                                 */
-#define MSR_TLB  17 /* TLB on ?                                              */
+#define MSR_TLB  17 /* TLB update on ?                                       */
 #define MSR_CE   17 /* Critical interrupt enable on embedded PowerPC         */
 #define MSR_ILE  16 /* Interrupt little-endian mode                          */
 #define MSR_EE   15 /* External interrupt enable                             */
-#define MSR_PR   14 /* Problem state                                         */
-#define MSR_FP   13 /* Floating point available                              */
+#define MSR_PR   14 /* Problem state                                  hflags */
+#define MSR_FP   13 /* Floating point available                       hflags */
 #define MSR_ME   12 /* Machine check interrupt enable                        */
-#define MSR_FE0  11 /* Floating point exception mode 0                       */
-#define MSR_SE   10 /* Single-step trace enable                              */
+#define MSR_FE0  11 /* Floating point exception mode 0                hflags */
+#define MSR_SE   10 /* Single-step trace enable                       hflags */
 #define MSR_DWE  10 /* Debug wait enable on 405                              */
-#define MSR_BE   9  /* Branch trace enable                                   */
+#define MSR_UBLE 10 /* User BTB lock enable on e500                          */
+#define MSR_BE   9  /* Branch trace enable                            hflags */
 #define MSR_DE   9  /* Debug interrupts enable on embedded PowerPC           */
-#define MSR_FE1  8  /* Floating point exception mode 1                       */
+#define MSR_FE1  8  /* Floating point exception mode 1                hflags */
 #define MSR_AL   7  /* AL bit on POWER                                       */
 #define MSR_IP   6  /* Interrupt prefix                                      */
 #define MSR_IR   5  /* Instruction relocate                                  */
@@ -415,42 +384,47 @@
 #define MSR_PX   2  /* Protection exclusive on 403                           */
 #define MSR_PMM  2  /* Performance monitor mark on POWER                     */
 #define MSR_RI   1  /* Recoverable interrupt                                 */
-#define MSR_LE   0  /* Little-endian mode                                    */
+#define MSR_LE   0  /* Little-endian mode                             hflags */
 #define msr_sf   env->msr[MSR_SF]
 #define msr_isf  env->msr[MSR_ISF]
 #define msr_hv   env->msr[MSR_HV]
+#define msr_cm   env->msr[MSR_CM]
+#define msr_icm  env->msr[MSR_ICM]
+#define msr_ucle env->msr[MSR_UCLE]
 #define msr_vr   env->msr[MSR_VR]
+#define msr_spe  env->msr[MSR_SPE]
 #define msr_ap   env->msr[MSR_AP]
 #define msr_sa   env->msr[MSR_SA]
 #define msr_key  env->msr[MSR_KEY]
-#define msr_pow env->msr[MSR_POW]
+#define msr_pow  env->msr[MSR_POW]
 #define msr_we   env->msr[MSR_WE]
 #define msr_tgpr env->msr[MSR_TGPR]
 #define msr_tlb  env->msr[MSR_TLB]
 #define msr_ce   env->msr[MSR_CE]
-#define msr_ile env->msr[MSR_ILE]
-#define msr_ee  env->msr[MSR_EE]
-#define msr_pr  env->msr[MSR_PR]
-#define msr_fp  env->msr[MSR_FP]
-#define msr_me  env->msr[MSR_ME]
-#define msr_fe0 env->msr[MSR_FE0]
-#define msr_se  env->msr[MSR_SE]
+#define msr_ile  env->msr[MSR_ILE]
+#define msr_ee   env->msr[MSR_EE]
+#define msr_pr   env->msr[MSR_PR]
+#define msr_fp   env->msr[MSR_FP]
+#define msr_me   env->msr[MSR_ME]
+#define msr_fe0  env->msr[MSR_FE0]
+#define msr_se   env->msr[MSR_SE]
 #define msr_dwe  env->msr[MSR_DWE]
-#define msr_be  env->msr[MSR_BE]
+#define msr_uble env->msr[MSR_UBLE]
+#define msr_be   env->msr[MSR_BE]
 #define msr_de   env->msr[MSR_DE]
-#define msr_fe1 env->msr[MSR_FE1]
+#define msr_fe1  env->msr[MSR_FE1]
 #define msr_al   env->msr[MSR_AL]
-#define msr_ip  env->msr[MSR_IP]
-#define msr_ir  env->msr[MSR_IR]
+#define msr_ip   env->msr[MSR_IP]
+#define msr_ir   env->msr[MSR_IR]
 #define msr_is   env->msr[MSR_IS]
-#define msr_dr  env->msr[MSR_DR]
+#define msr_dr   env->msr[MSR_DR]
 #define msr_ds   env->msr[MSR_DS]
 #define msr_pe   env->msr[MSR_PE]
 #define msr_ep   env->msr[MSR_EP]
 #define msr_px   env->msr[MSR_PX]
 #define msr_pmm  env->msr[MSR_PMM]
-#define msr_ri  env->msr[MSR_RI]
-#define msr_le  env->msr[MSR_LE]
+#define msr_ri   env->msr[MSR_RI]
+#define msr_le   env->msr[MSR_LE]
 
 /*****************************************************************************/
 /* The whole PowerPC CPU context */
@@ -458,14 +432,16 @@
     /* First are the most commonly used resources
      * during translated code execution
      */
-#if TARGET_LONG_BITS > HOST_LONG_BITS
+#if TARGET_GPR_BITS > HOST_LONG_BITS
     /* temporary fixed-point registers
      * used to emulate 64 bits target on 32 bits hosts
      */
-    target_ulong t0, t1, t2;
+    ppc_gpr_t t0, t1, t2;
 #endif
+    ppc_avr_t t0_avr, t1_avr, t2_avr;
+
     /* general purpose registers */
-    target_ulong gpr[32];
+    ppc_gpr_t gpr[32];
     /* LR */
     target_ulong lr;
     /* CTR */
@@ -482,10 +458,10 @@
     /* machine state register */
     uint8_t msr[64];
     /* temporary general purpose registers */
-    target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */
+    ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */
 
     /* Floating point execution context */
-     /* temporary float registers */
+    /* temporary float registers */
     float64 ft0;
     float64 ft1;
     float64 ft2;
@@ -519,34 +495,54 @@
     /* Altivec registers */
     ppc_avr_t avr[32];
     uint32_t vscr;
+    /* SPE registers */
+    ppc_gpr_t spe_acc;
+    float_status spe_status;
+    uint32_t spe_fscr;
 
     /* Internal devices resources */
     /* Time base and decrementer */
     ppc_tb_t *tb_env;
     /* Device control registers */
-    int (*dcr_read)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong *val);
-    int (*dcr_write)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong val);
     ppc_dcr_t *dcr_env;
 
     /* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
-    int nb_tlb;
-    int nb_ways, last_way;
-    ppc_tlb_t tlb[128];
-    /* Callbacks for specific checks on some implementations */
-    int (*tlb_check_more)(CPUPPCState *env, struct ppc_tlb_t *tlb, int *prot,
-                          target_ulong vaddr, int rw, int acc_type,
-                          int is_user);
+    int nb_tlb;      /* Total number of TLB                                  */
+    int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
+    int nb_ways;     /* Number of ways in the TLB set                        */
+    int last_way;    /* Last used way used to allocate TLB in a LRU way      */
+    int id_tlbs;     /* If 1, MMU has separated TLBs for instructions & data */
+    int nb_pids;     /* Number of available PID registers                    */
+    ppc_tlb_t *tlb;  /* TLB is optional. Allocate them only if needed        */
     /* 403 dedicated access protection registers */
     target_ulong pb[4];
 
     /* Those resources are used during exception processing */
     /* CPU model definition */
-    uint64_t msr_mask;
+    target_ulong msr_mask;
+    uint8_t mmu_model;
+    uint8_t excp_model;
+    uint8_t bus_model;
+    uint8_t pad;
+    int bfd_mach;
     uint32_t flags;
 
     int exception_index;
     int error_code;
     int interrupt_request;
+    uint32_t pending_interrupts;
+#if !defined(CONFIG_USER_ONLY)
+    /* This is the IRQ controller, which is implementation dependant
+     * and only relevant when emulating a complete machine.
+     */
+    uint32_t irq_input_state;
+    void **irq_inputs;
+    /* Exception vectors */
+    target_ulong excp_vectors[POWERPC_EXCP_NB];
+    target_ulong excp_prefix;
+    target_ulong ivor_mask;
+    target_ulong ivpr_mask;
+#endif
 
     /* Those resources are used only during code translation */
     /* Next instruction pointer */
@@ -559,7 +555,7 @@
     /* Those resources are used only in Qemu core */
     jmp_buf jmp_env;
     int user_mode_only; /* user mode only simulation */
-    uint32_t hflags;
+    target_ulong hflags; /* hflags is a MSR & HFLAGS_MASK */
 
     /* Power management */
     int power_mode;
@@ -568,21 +564,33 @@
     int (*osi_call)(struct CPUPPCState *env);
 };
 
+/* Context used internally during MMU translations */
+typedef struct mmu_ctx_t mmu_ctx_t;
+struct mmu_ctx_t {
+    target_phys_addr_t raddr;      /* Real address              */
+    int prot;                      /* Protection bits           */
+    target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
+    target_ulong ptem;             /* Virtual segment ID | API  */
+    int key;                       /* Access key                */
+};
+
 /*****************************************************************************/
-CPUPPCState *cpu_ppc_init(void);
-int cpu_ppc_exec(CPUPPCState *s);
-void cpu_ppc_close(CPUPPCState *s);
+CPUPPCState *cpu_ppc_init (void);
+int cpu_ppc_exec (CPUPPCState *s);
+void cpu_ppc_close (CPUPPCState *s);
 /* 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.  */
-int cpu_ppc_signal_handler(int host_signum, void *pinfo, 
-                           void *puc);
+int cpu_ppc_signal_handler (int host_signum, void *pinfo,
+                            void *puc);
 
 void do_interrupt (CPUPPCState *env);
-void cpu_loop_exit(void);
+void ppc_hw_interrupt (CPUPPCState *env);
+void cpu_loop_exit (void);
 
 void dump_stack (CPUPPCState *env);
 
+#if !defined(CONFIG_USER_ONLY)
 target_ulong do_load_ibatu (CPUPPCState *env, int nr);
 target_ulong do_load_ibatl (CPUPPCState *env, int nr);
 void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value);
@@ -591,25 +599,27 @@
 target_ulong do_load_dbatl (CPUPPCState *env, int nr);
 void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value);
 void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value);
-
-target_ulong do_load_nip (CPUPPCState *env);
-void do_store_nip (CPUPPCState *env, target_ulong value);
 target_ulong do_load_sdr1 (CPUPPCState *env);
 void do_store_sdr1 (CPUPPCState *env, target_ulong value);
-target_ulong do_load_asr (CPUPPCState *env);
-void do_store_asr (CPUPPCState *env, target_ulong value);
+#if defined(TARGET_PPC64)
+target_ulong ppc_load_asr (CPUPPCState *env);
+void ppc_store_asr (CPUPPCState *env, target_ulong value);
+#endif
 target_ulong do_load_sr (CPUPPCState *env, int srnum);
 void do_store_sr (CPUPPCState *env, int srnum, target_ulong value);
-uint32_t do_load_cr (CPUPPCState *env);
-void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask);
-uint32_t do_load_xer (CPUPPCState *env);
-void do_store_xer (CPUPPCState *env, uint32_t value);
+#endif
+target_ulong ppc_load_xer (CPUPPCState *env);
+void ppc_store_xer (CPUPPCState *env, target_ulong value);
 target_ulong do_load_msr (CPUPPCState *env);
 void do_store_msr (CPUPPCState *env, target_ulong value);
-float64 do_load_fpscr (CPUPPCState *env);
-void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask);
+#if defined(TARGET_PPC64)
+void ppc_store_msr_32 (CPUPPCState *env, uint32_t value);
+#endif
 
 void do_compute_hflags (CPUPPCState *env);
+void cpu_ppc_reset (void *opaque);
+CPUPPCState *cpu_ppc_init (void);
+void cpu_ppc_close(CPUPPCState *env);
 
 int ppc_find_by_name (const unsigned char *name, ppc_def_t **def);
 int ppc_find_by_pvr (uint32_t apvr, ppc_def_t **def);
@@ -622,284 +632,454 @@
 uint32_t cpu_ppc_load_tbu (CPUPPCState *env);
 void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value);
 void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value);
+uint32_t cpu_ppc_load_atbl (CPUPPCState *env);
+uint32_t cpu_ppc_load_atbu (CPUPPCState *env);
+void cpu_ppc_store_atbl (CPUPPCState *env, uint32_t value);
+void cpu_ppc_store_atbu (CPUPPCState *env, uint32_t value);
 uint32_t cpu_ppc_load_decr (CPUPPCState *env);
 void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
+#if defined(TARGET_PPC64H)
+uint32_t cpu_ppc_load_hdecr (CPUPPCState *env);
+void cpu_ppc_store_hdecr (CPUPPCState *env, uint32_t value);
+uint64_t cpu_ppc_load_purr (CPUPPCState *env);
+void cpu_ppc_store_purr (CPUPPCState *env, uint64_t value);
+#endif
+uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env);
+uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env);
+#if !defined(CONFIG_USER_ONLY)
+void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value);
+void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value);
+target_ulong load_40x_pit (CPUPPCState *env);
+void store_40x_pit (CPUPPCState *env, target_ulong val);
+void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
+void store_40x_sler (CPUPPCState *env, uint32_t val);
+void store_booke_tcr (CPUPPCState *env, target_ulong val);
+void store_booke_tsr (CPUPPCState *env, target_ulong val);
+void ppc_tlb_invalidate_all (CPUPPCState *env);
+void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr);
+#if defined(TARGET_PPC64)
+void ppc_slb_invalidate_all (CPUPPCState *env);
+void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0);
+#endif
+int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid);
+#endif
 #endif
 
-#define TARGET_PAGE_BITS 12
+/* Device control registers */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp);
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val);
+
+#define CPUState CPUPPCState
+#define cpu_init cpu_ppc_init
+#define cpu_exec cpu_ppc_exec
+#define cpu_gen_code cpu_ppc_gen_code
+#define cpu_signal_handler cpu_ppc_signal_handler
+
 #include "cpu-all.h"
 
 /*****************************************************************************/
 /* Registers definitions */
-#define ugpr(n) (env->gpr[n])
-
 #define XER_SO 31
 #define XER_OV 30
 #define XER_CA 29
 #define XER_CMP 8
-#define XER_BC 0
+#define XER_BC  0
 #define xer_so  env->xer[4]
 #define xer_ov  env->xer[6]
 #define xer_ca  env->xer[2]
 #define xer_cmp env->xer[1]
-#define xer_bc env->xer[0]
+#define xer_bc  env->xer[0]
 
 /* SPR definitions */
-#define SPR_MQ         (0x000)
-#define SPR_XER        (0x001)
-#define SPR_601_VRTCU  (0x004)
-#define SPR_601_VRTCL  (0x005)
-#define SPR_601_UDECR  (0x006)
-#define SPR_LR         (0x008)
-#define SPR_CTR        (0x009)
-#define SPR_DSISR      (0x012)
-#define SPR_DAR        (0x013)
-#define SPR_601_RTCU   (0x014)
-#define SPR_601_RTCL   (0x015)
-#define SPR_DECR       (0x016)
-#define SPR_SDR1       (0x019)
-#define SPR_SRR0       (0x01A)
-#define SPR_SRR1       (0x01B)
-#define SPR_440_PID    (0x030)
-#define SPR_440_DECAR  (0x036)
-#define SPR_CSRR0      (0x03A)
-#define SPR_CSRR1      (0x03B)
-#define SPR_440_DEAR   (0x03D)
-#define SPR_440_ESR    (0x03E)
-#define SPR_440_IVPR   (0x03F)
-#define SPR_8xx_EIE    (0x050)
-#define SPR_8xx_EID    (0x051)
-#define SPR_8xx_NRE    (0x052)
-#define SPR_58x_CMPA   (0x090)
-#define SPR_58x_CMPB   (0x091)
-#define SPR_58x_CMPC   (0x092)
-#define SPR_58x_CMPD   (0x093)
-#define SPR_58x_ICR    (0x094)
-#define SPR_58x_DER    (0x094)
-#define SPR_58x_COUNTA (0x096)
-#define SPR_58x_COUNTB (0x097)
-#define SPR_58x_CMPE   (0x098)
-#define SPR_58x_CMPF   (0x099)
-#define SPR_58x_CMPG   (0x09A)
-#define SPR_58x_CMPH   (0x09B)
-#define SPR_58x_LCTRL1 (0x09C)
-#define SPR_58x_LCTRL2 (0x09D)
-#define SPR_58x_ICTRL  (0x09E)
-#define SPR_58x_BAR    (0x09F)
-#define SPR_VRSAVE     (0x100)
-#define SPR_USPRG0     (0x100)
-#define SPR_USPRG4     (0x104)
-#define SPR_USPRG5     (0x105)
-#define SPR_USPRG6     (0x106)
-#define SPR_USPRG7     (0x107)
-#define SPR_VTBL       (0x10C)
-#define SPR_VTBU       (0x10D)
-#define SPR_SPRG0      (0x110)
-#define SPR_SPRG1      (0x111)
-#define SPR_SPRG2      (0x112)
-#define SPR_SPRG3      (0x113)
-#define SPR_SPRG4      (0x114)
-#define SPR_SCOMC      (0x114)
-#define SPR_SPRG5      (0x115)
-#define SPR_SCOMD      (0x115)
-#define SPR_SPRG6      (0x116)
-#define SPR_SPRG7      (0x117)
-#define SPR_ASR        (0x118)
-#define SPR_EAR        (0x11A)
-#define SPR_TBL        (0x11C)
-#define SPR_TBU        (0x11D)
-#define SPR_SVR        (0x11E)
-#define SPR_440_PIR    (0x11E)
-#define SPR_PVR        (0x11F)
-#define SPR_HSPRG0     (0x130)
-#define SPR_440_DBSR   (0x130)
-#define SPR_HSPRG1     (0x131)
-#define SPR_440_DBCR0  (0x134)
-#define SPR_IBCR       (0x135)
-#define SPR_440_DBCR1  (0x135)
-#define SPR_DBCR       (0x136)
-#define SPR_HDEC       (0x136)
-#define SPR_440_DBCR2  (0x136)
-#define SPR_HIOR       (0x137)
-#define SPR_MBAR       (0x137)
-#define SPR_RMOR       (0x138)
-#define SPR_440_IAC1   (0x138)
-#define SPR_HRMOR      (0x139)
-#define SPR_440_IAC2   (0x139)
-#define SPR_HSSR0      (0x13A)
-#define SPR_440_IAC3   (0x13A)
-#define SPR_HSSR1      (0x13B)
-#define SPR_440_IAC4   (0x13B)
-#define SPR_LPCR       (0x13C)
-#define SPR_440_DAC1   (0x13C)
-#define SPR_LPIDR      (0x13D)
-#define SPR_DABR2      (0x13D)
-#define SPR_440_DAC2   (0x13D)
-#define SPR_440_DVC1   (0x13E)
-#define SPR_440_DVC2   (0x13F)
-#define SPR_440_TSR    (0x150)
-#define SPR_440_TCR    (0x154)
-#define SPR_440_IVOR0  (0x190)
-#define SPR_440_IVOR1  (0x191)
-#define SPR_440_IVOR2  (0x192)
-#define SPR_440_IVOR3  (0x193)
-#define SPR_440_IVOR4  (0x194)
-#define SPR_440_IVOR5  (0x195)
-#define SPR_440_IVOR6  (0x196)
-#define SPR_440_IVOR7  (0x197)
-#define SPR_440_IVOR8  (0x198)
-#define SPR_440_IVOR9  (0x199)
-#define SPR_440_IVOR10 (0x19A)
-#define SPR_440_IVOR11 (0x19B)
-#define SPR_440_IVOR12 (0x19C)
-#define SPR_440_IVOR13 (0x19D)
-#define SPR_440_IVOR14 (0x19E)
-#define SPR_440_IVOR15 (0x19F)
-#define SPR_IBAT0U     (0x210)
-#define SPR_IBAT0L     (0x211)
-#define SPR_IBAT1U     (0x212)
-#define SPR_IBAT1L     (0x213)
-#define SPR_IBAT2U     (0x214)
-#define SPR_IBAT2L     (0x215)
-#define SPR_IBAT3U     (0x216)
-#define SPR_IBAT3L     (0x217)
-#define SPR_DBAT0U     (0x218)
-#define SPR_DBAT0L     (0x219)
-#define SPR_DBAT1U     (0x21A)
-#define SPR_DBAT1L     (0x21B)
-#define SPR_DBAT2U     (0x21C)
-#define SPR_DBAT2L     (0x21D)
-#define SPR_DBAT3U     (0x21E)
-#define SPR_DBAT3L     (0x21F)
-#define SPR_IBAT4U     (0x230)
-#define SPR_IBAT4L     (0x231)
-#define SPR_IBAT5U     (0x232)
-#define SPR_IBAT5L     (0x233)
-#define SPR_IBAT6U     (0x234)
-#define SPR_IBAT6L     (0x235)
-#define SPR_IBAT7U     (0x236)
-#define SPR_IBAT7L     (0x237)
-#define SPR_DBAT4U     (0x238)
-#define SPR_DBAT4L     (0x239)
-#define SPR_DBAT5U     (0x23A)
-#define SPR_DBAT5L     (0x23B)
-#define SPR_DBAT6U     (0x23C)
-#define SPR_DBAT6L     (0x23D)
-#define SPR_DBAT7U     (0x23E)
-#define SPR_DBAT7L     (0x23F)
-#define SPR_440_INV0   (0x370)
-#define SPR_440_INV1   (0x371)
-#define SPR_440_INV2   (0x372)
-#define SPR_440_INV3   (0x373)
-#define SPR_440_IVT0   (0x374)
-#define SPR_440_IVT1   (0x375)
-#define SPR_440_IVT2   (0x376)
-#define SPR_440_IVT3   (0x377)
-#define SPR_440_DNV0   (0x390)
-#define SPR_440_DNV1   (0x391)
-#define SPR_440_DNV2   (0x392)
-#define SPR_440_DNV3   (0x393)
-#define SPR_440_DVT0   (0x394)
-#define SPR_440_DVT1   (0x395)
-#define SPR_440_DVT2   (0x396)
-#define SPR_440_DVT3   (0x397)
-#define SPR_440_DVLIM  (0x398)
-#define SPR_440_IVLIM  (0x399)
-#define SPR_440_RSTCFG (0x39B)
-#define SPR_440_DCBTRL (0x39C)
-#define SPR_440_DCBTRH (0x39D)
-#define SPR_440_ICBTRL (0x39E)
-#define SPR_440_ICBTRH (0x39F)
-#define SPR_UMMCR0     (0x3A8)
-#define SPR_UPMC1      (0x3A9)
-#define SPR_UPMC2      (0x3AA)
-#define SPR_USIA       (0x3AB)
-#define SPR_UMMCR1     (0x3AC)
-#define SPR_UPMC3      (0x3AD)
-#define SPR_UPMC4      (0x3AE)
-#define SPR_USDA       (0x3AF)
-#define SPR_40x_ZPR    (0x3B0)
-#define SPR_40x_PID    (0x3B1)
-#define SPR_440_MMUCR  (0x3B2)
-#define SPR_4xx_CCR0   (0x3B3)
-#define SPR_405_IAC3   (0x3B4)
-#define SPR_405_IAC4   (0x3B5)
-#define SPR_405_DVC1   (0x3B6)
-#define SPR_405_DVC2   (0x3B7)
-#define SPR_MMCR0      (0x3B8)
-#define SPR_PMC1       (0x3B9)
-#define SPR_40x_SGR    (0x3B9)
-#define SPR_PMC2       (0x3BA)
-#define SPR_40x_DCWR   (0x3BA)
-#define SPR_SIA        (0x3BB)
-#define SPR_405_SLER   (0x3BB)
-#define SPR_MMCR1      (0x3BC)
-#define SPR_405_SU0R   (0x3BC)
-#define SPR_PMC3       (0x3BD)
-#define SPR_405_DBCR1  (0x3BD)
-#define SPR_PMC4       (0x3BE)
-#define SPR_SDA        (0x3BF)
-#define SPR_403_VTBL   (0x3CC)
-#define SPR_403_VTBU   (0x3CD)
-#define SPR_DMISS      (0x3D0)
-#define SPR_DCMP       (0x3D1)
-#define SPR_DHASH1     (0x3D2)
-#define SPR_DHASH2     (0x3D3)
-#define SPR_4xx_ICDBDR (0x3D3)
-#define SPR_IMISS      (0x3D4)
-#define SPR_40x_ESR    (0x3D4)
-#define SPR_ICMP       (0x3D5)
-#define SPR_40x_DEAR   (0x3D5)
-#define SPR_RPA        (0x3D6)
-#define SPR_40x_EVPR   (0x3D6)
-#define SPR_403_CDBCR  (0x3D7)
-#define SPR_TCR        (0x3D8)
-#define SPR_40x_TSR    (0x3D8)
-#define SPR_IBR        (0x3DA)
-#define SPR_40x_TCR    (0x3DA)
-#define SPR_ESASR      (0x3DB)
-#define SPR_40x_PIT    (0x3DB)
-#define SPR_403_TBL    (0x3DC)
-#define SPR_403_TBU    (0x3DD)
-#define SPR_SEBR       (0x3DE)
-#define SPR_40x_SRR2   (0x3DE)
-#define SPR_SER        (0x3DF)
-#define SPR_40x_SRR3   (0x3DF)
-#define SPR_HID0       (0x3F0)
-#define SPR_40x_DBSR   (0x3F0)
-#define SPR_HID1       (0x3F1)
-#define SPR_IABR       (0x3F2)
-#define SPR_40x_DBCR0  (0x3F2)
-#define SPR_601_HID2   (0x3F2)
-#define SPR_HID2       (0x3F3)
-#define SPR_440_DBDR   (0x3F3)
-#define SPR_40x_IAC1   (0x3F4)
-#define SPR_DABR       (0x3F5)
+#define SPR_MQ           (0x000)
+#define SPR_XER          (0x001)
+#define SPR_601_VRTCU    (0x004)
+#define SPR_601_VRTCL    (0x005)
+#define SPR_601_UDECR    (0x006)
+#define SPR_LR           (0x008)
+#define SPR_CTR          (0x009)
+#define SPR_DSISR        (0x012)
+#define SPR_DAR          (0x013) /* DAE for PowerPC 601 */
+#define SPR_601_RTCU     (0x014)
+#define SPR_601_RTCL     (0x015)
+#define SPR_DECR         (0x016)
+#define SPR_SDR1         (0x019)
+#define SPR_SRR0         (0x01A)
+#define SPR_SRR1         (0x01B)
+#define SPR_AMR          (0x01D)
+#define SPR_BOOKE_PID    (0x030)
+#define SPR_BOOKE_DECAR  (0x036)
+#define SPR_BOOKE_CSRR0  (0x03A)
+#define SPR_BOOKE_CSRR1  (0x03B)
+#define SPR_BOOKE_DEAR   (0x03D)
+#define SPR_BOOKE_ESR    (0x03E)
+#define SPR_BOOKE_IVPR   (0x03F)
+#define SPR_8xx_EIE      (0x050)
+#define SPR_8xx_EID      (0x051)
+#define SPR_8xx_NRE      (0x052)
+#define SPR_CTRL         (0x088)
+#define SPR_58x_CMPA     (0x090)
+#define SPR_58x_CMPB     (0x091)
+#define SPR_58x_CMPC     (0x092)
+#define SPR_58x_CMPD     (0x093)
+#define SPR_58x_ICR      (0x094)
+#define SPR_58x_DER      (0x094)
+#define SPR_58x_COUNTA   (0x096)
+#define SPR_58x_COUNTB   (0x097)
+#define SPR_UCTRL        (0x098)
+#define SPR_58x_CMPE     (0x098)
+#define SPR_58x_CMPF     (0x099)
+#define SPR_58x_CMPG     (0x09A)
+#define SPR_58x_CMPH     (0x09B)
+#define SPR_58x_LCTRL1   (0x09C)
+#define SPR_58x_LCTRL2   (0x09D)
+#define SPR_58x_ICTRL    (0x09E)
+#define SPR_58x_BAR      (0x09F)
+#define SPR_VRSAVE       (0x100)
+#define SPR_USPRG0       (0x100)
+#define SPR_USPRG1       (0x101)
+#define SPR_USPRG2       (0x102)
+#define SPR_USPRG3       (0x103)
+#define SPR_USPRG4       (0x104)
+#define SPR_USPRG5       (0x105)
+#define SPR_USPRG6       (0x106)
+#define SPR_USPRG7       (0x107)
+#define SPR_VTBL         (0x10C)
+#define SPR_VTBU         (0x10D)
+#define SPR_SPRG0        (0x110)
+#define SPR_SPRG1        (0x111)
+#define SPR_SPRG2        (0x112)
+#define SPR_SPRG3        (0x113)
+#define SPR_SPRG4        (0x114)
+#define SPR_SCOMC        (0x114)
+#define SPR_SPRG5        (0x115)
+#define SPR_SCOMD        (0x115)
+#define SPR_SPRG6        (0x116)
+#define SPR_SPRG7        (0x117)
+#define SPR_ASR          (0x118)
+#define SPR_EAR          (0x11A)
+#define SPR_TBL          (0x11C)
+#define SPR_TBU          (0x11D)
+#define SPR_TBU40        (0x11E)
+#define SPR_SVR          (0x11E)
+#define SPR_BOOKE_PIR    (0x11E)
+#define SPR_PVR          (0x11F)
+#define SPR_HSPRG0       (0x130)
+#define SPR_BOOKE_DBSR   (0x130)
+#define SPR_HSPRG1       (0x131)
+#define SPR_HDSISR       (0x132)
+#define SPR_HDAR         (0x133)
+#define SPR_BOOKE_DBCR0  (0x134)
+#define SPR_IBCR         (0x135)
+#define SPR_PURR         (0x135)
+#define SPR_BOOKE_DBCR1  (0x135)
+#define SPR_DBCR         (0x136)
+#define SPR_HDEC         (0x136)
+#define SPR_BOOKE_DBCR2  (0x136)
+#define SPR_HIOR         (0x137)
+#define SPR_MBAR         (0x137)
+#define SPR_RMOR         (0x138)
+#define SPR_BOOKE_IAC1   (0x138)
+#define SPR_HRMOR        (0x139)
+#define SPR_BOOKE_IAC2   (0x139)
+#define SPR_HSRR0        (0x13A)
+#define SPR_BOOKE_IAC3   (0x13A)
+#define SPR_HSRR1        (0x13B)
+#define SPR_BOOKE_IAC4   (0x13B)
+#define SPR_LPCR         (0x13C)
+#define SPR_BOOKE_DAC1   (0x13C)
+#define SPR_LPIDR        (0x13D)
+#define SPR_DABR2        (0x13D)
+#define SPR_BOOKE_DAC2   (0x13D)
+#define SPR_BOOKE_DVC1   (0x13E)
+#define SPR_BOOKE_DVC2   (0x13F)
+#define SPR_BOOKE_TSR    (0x150)
+#define SPR_BOOKE_TCR    (0x154)
+#define SPR_BOOKE_IVOR0  (0x190)
+#define SPR_BOOKE_IVOR1  (0x191)
+#define SPR_BOOKE_IVOR2  (0x192)
+#define SPR_BOOKE_IVOR3  (0x193)
+#define SPR_BOOKE_IVOR4  (0x194)
+#define SPR_BOOKE_IVOR5  (0x195)
+#define SPR_BOOKE_IVOR6  (0x196)
+#define SPR_BOOKE_IVOR7  (0x197)
+#define SPR_BOOKE_IVOR8  (0x198)
+#define SPR_BOOKE_IVOR9  (0x199)
+#define SPR_BOOKE_IVOR10 (0x19A)
+#define SPR_BOOKE_IVOR11 (0x19B)
+#define SPR_BOOKE_IVOR12 (0x19C)
+#define SPR_BOOKE_IVOR13 (0x19D)
+#define SPR_BOOKE_IVOR14 (0x19E)
+#define SPR_BOOKE_IVOR15 (0x19F)
+#define SPR_BOOKE_SPEFSCR (0x200)
+#define SPR_E500_BBEAR   (0x201)
+#define SPR_E500_BBTAR   (0x202)
+#define SPR_ATBL         (0x20E)
+#define SPR_ATBU         (0x20F)
+#define SPR_IBAT0U       (0x210)
+#define SPR_BOOKE_IVOR32 (0x210)
+#define SPR_IBAT0L       (0x211)
+#define SPR_BOOKE_IVOR33 (0x211)
+#define SPR_IBAT1U       (0x212)
+#define SPR_BOOKE_IVOR34 (0x212)
+#define SPR_IBAT1L       (0x213)
+#define SPR_BOOKE_IVOR35 (0x213)
+#define SPR_IBAT2U       (0x214)
+#define SPR_BOOKE_IVOR36 (0x214)
+#define SPR_IBAT2L       (0x215)
+#define SPR_E500_L1CFG0  (0x215)
+#define SPR_BOOKE_IVOR37 (0x215)
+#define SPR_IBAT3U       (0x216)
+#define SPR_E500_L1CFG1  (0x216)
+#define SPR_IBAT3L       (0x217)
+#define SPR_DBAT0U       (0x218)
+#define SPR_DBAT0L       (0x219)
+#define SPR_DBAT1U       (0x21A)
+#define SPR_DBAT1L       (0x21B)
+#define SPR_DBAT2U       (0x21C)
+#define SPR_DBAT2L       (0x21D)
+#define SPR_DBAT3U       (0x21E)
+#define SPR_DBAT3L       (0x21F)
+#define SPR_IBAT4U       (0x230)
+#define SPR_IBAT4L       (0x231)
+#define SPR_IBAT5U       (0x232)
+#define SPR_IBAT5L       (0x233)
+#define SPR_IBAT6U       (0x234)
+#define SPR_IBAT6L       (0x235)
+#define SPR_IBAT7U       (0x236)
+#define SPR_IBAT7L       (0x237)
+#define SPR_DBAT4U       (0x238)
+#define SPR_DBAT4L       (0x239)
+#define SPR_DBAT5U       (0x23A)
+#define SPR_BOOKE_MCSRR0 (0x23A)
+#define SPR_DBAT5L       (0x23B)
+#define SPR_BOOKE_MCSRR1 (0x23B)
+#define SPR_DBAT6U       (0x23C)
+#define SPR_BOOKE_MCSR   (0x23C)
+#define SPR_DBAT6L       (0x23D)
+#define SPR_E500_MCAR    (0x23D)
+#define SPR_DBAT7U       (0x23E)
+#define SPR_BOOKE_DSRR0  (0x23E)
+#define SPR_DBAT7L       (0x23F)
+#define SPR_BOOKE_DSRR1  (0x23F)
+#define SPR_BOOKE_SPRG8  (0x25C)
+#define SPR_BOOKE_SPRG9  (0x25D)
+#define SPR_BOOKE_MAS0   (0x270)
+#define SPR_BOOKE_MAS1   (0x271)
+#define SPR_BOOKE_MAS2   (0x272)
+#define SPR_BOOKE_MAS3   (0x273)
+#define SPR_BOOKE_MAS4   (0x274)
+#define SPR_BOOKE_MAS6   (0x276)
+#define SPR_BOOKE_PID1   (0x279)
+#define SPR_BOOKE_PID2   (0x27A)
+#define SPR_BOOKE_TLB0CFG (0x2B0)
+#define SPR_BOOKE_TLB1CFG (0x2B1)
+#define SPR_BOOKE_TLB2CFG (0x2B2)
+#define SPR_BOOKE_TLB3CFG (0x2B3)
+#define SPR_BOOKE_EPR    (0x2BE)
+#define SPR_PERF0        (0x300)
+#define SPR_PERF1        (0x301)
+#define SPR_PERF2        (0x302)
+#define SPR_PERF3        (0x303)
+#define SPR_PERF4        (0x304)
+#define SPR_PERF5        (0x305)
+#define SPR_PERF6        (0x306)
+#define SPR_PERF7        (0x307)
+#define SPR_PERF8        (0x308)
+#define SPR_PERF9        (0x309)
+#define SPR_PERFA        (0x30A)
+#define SPR_PERFB        (0x30B)
+#define SPR_PERFC        (0x30C)
+#define SPR_PERFD        (0x30D)
+#define SPR_PERFE        (0x30E)
+#define SPR_PERFF        (0x30F)
+#define SPR_UPERF0       (0x310)
+#define SPR_UPERF1       (0x311)
+#define SPR_UPERF2       (0x312)
+#define SPR_UPERF3       (0x313)
+#define SPR_UPERF4       (0x314)
+#define SPR_UPERF5       (0x315)
+#define SPR_UPERF6       (0x316)
+#define SPR_UPERF7       (0x317)
+#define SPR_UPERF8       (0x318)
+#define SPR_UPERF9       (0x319)
+#define SPR_UPERFA       (0x31A)
+#define SPR_UPERFB       (0x31B)
+#define SPR_UPERFC       (0x31C)
+#define SPR_UPERFD       (0x31D)
+#define SPR_UPERFE       (0x31E)
+#define SPR_UPERFF       (0x31F)
+#define SPR_440_INV0     (0x370)
+#define SPR_440_INV1     (0x371)
+#define SPR_440_INV2     (0x372)
+#define SPR_440_INV3     (0x373)
+#define SPR_440_ITV0     (0x374)
+#define SPR_440_ITV1     (0x375)
+#define SPR_440_ITV2     (0x376)
+#define SPR_440_ITV3     (0x377)
+#define SPR_440_CCR1     (0x378)
+#define SPR_DCRIPR       (0x37B)
+#define SPR_PPR          (0x380)
+#define SPR_440_DNV0     (0x390)
+#define SPR_440_DNV1     (0x391)
+#define SPR_440_DNV2     (0x392)
+#define SPR_440_DNV3     (0x393)
+#define SPR_440_DTV0     (0x394)
+#define SPR_440_DTV1     (0x395)
+#define SPR_440_DTV2     (0x396)
+#define SPR_440_DTV3     (0x397)
+#define SPR_440_DVLIM    (0x398)
+#define SPR_440_IVLIM    (0x399)
+#define SPR_440_RSTCFG   (0x39B)
+#define SPR_BOOKE_DCDBTRL (0x39C)
+#define SPR_BOOKE_DCDBTRH (0x39D)
+#define SPR_BOOKE_ICDBTRL (0x39E)
+#define SPR_BOOKE_ICDBTRH (0x39F)
+#define SPR_UMMCR2       (0x3A0)
+#define SPR_UPMC5        (0x3A1)
+#define SPR_UPMC6        (0x3A2)
+#define SPR_UBAMR        (0x3A7)
+#define SPR_UMMCR0       (0x3A8)
+#define SPR_UPMC1        (0x3A9)
+#define SPR_UPMC2        (0x3AA)
+#define SPR_USIAR        (0x3AB)
+#define SPR_UMMCR1       (0x3AC)
+#define SPR_UPMC3        (0x3AD)
+#define SPR_UPMC4        (0x3AE)
+#define SPR_USDA         (0x3AF)
+#define SPR_40x_ZPR      (0x3B0)
+#define SPR_BOOKE_MAS7   (0x3B0)
+#define SPR_620_PMR0     (0x3B0)
+#define SPR_MMCR2        (0x3B0)
+#define SPR_PMC5         (0x3B1)
+#define SPR_40x_PID      (0x3B1)
+#define SPR_620_PMR1     (0x3B1)
+#define SPR_PMC6         (0x3B2)
+#define SPR_440_MMUCR    (0x3B2)
+#define SPR_620_PMR2     (0x3B2)
+#define SPR_4xx_CCR0     (0x3B3)
+#define SPR_BOOKE_EPLC   (0x3B3)
+#define SPR_620_PMR3     (0x3B3)
+#define SPR_405_IAC3     (0x3B4)
+#define SPR_BOOKE_EPSC   (0x3B4)
+#define SPR_620_PMR4     (0x3B4)
+#define SPR_405_IAC4     (0x3B5)
+#define SPR_620_PMR5     (0x3B5)
+#define SPR_405_DVC1     (0x3B6)
+#define SPR_620_PMR6     (0x3B6)
+#define SPR_405_DVC2     (0x3B7)
+#define SPR_620_PMR7     (0x3B7)
+#define SPR_BAMR         (0x3B7)
+#define SPR_MMCR0        (0x3B8)
+#define SPR_620_PMR8     (0x3B8)
+#define SPR_PMC1         (0x3B9)
+#define SPR_40x_SGR      (0x3B9)
+#define SPR_620_PMR9     (0x3B9)
+#define SPR_PMC2         (0x3BA)
+#define SPR_40x_DCWR     (0x3BA)
+#define SPR_620_PMRA     (0x3BA)
+#define SPR_SIAR         (0x3BB)
+#define SPR_405_SLER     (0x3BB)
+#define SPR_620_PMRB     (0x3BB)
+#define SPR_MMCR1        (0x3BC)
+#define SPR_405_SU0R     (0x3BC)
+#define SPR_620_PMRC     (0x3BC)
+#define SPR_401_SKR      (0x3BC)
+#define SPR_PMC3         (0x3BD)
+#define SPR_405_DBCR1    (0x3BD)
+#define SPR_620_PMRD     (0x3BD)
+#define SPR_PMC4         (0x3BE)
+#define SPR_620_PMRE     (0x3BE)
+#define SPR_SDA          (0x3BF)
+#define SPR_620_PMRF     (0x3BF)
+#define SPR_403_VTBL     (0x3CC)
+#define SPR_403_VTBU     (0x3CD)
+#define SPR_DMISS        (0x3D0)
+#define SPR_DCMP         (0x3D1)
+#define SPR_HASH1        (0x3D2)
+#define SPR_HASH2        (0x3D3)
+#define SPR_BOOKE_ICDBDR (0x3D3)
+#define SPR_TLBMISS      (0x3D4)
+#define SPR_IMISS        (0x3D4)
+#define SPR_40x_ESR      (0x3D4)
+#define SPR_PTEHI        (0x3D5)
+#define SPR_ICMP         (0x3D5)
+#define SPR_40x_DEAR     (0x3D5)
+#define SPR_PTELO        (0x3D6)
+#define SPR_RPA          (0x3D6)
+#define SPR_40x_EVPR     (0x3D6)
+#define SPR_L3PM         (0x3D7)
+#define SPR_403_CDBCR    (0x3D7)
+#define SPR_L3OHCR       (0x3D8)
+#define SPR_TCR          (0x3D8)
+#define SPR_40x_TSR      (0x3D8)
+#define SPR_IBR          (0x3DA)
+#define SPR_40x_TCR      (0x3DA)
+#define SPR_ESASRR       (0x3DB)
+#define SPR_40x_PIT      (0x3DB)
+#define SPR_403_TBL      (0x3DC)
+#define SPR_403_TBU      (0x3DD)
+#define SPR_SEBR         (0x3DE)
+#define SPR_40x_SRR2     (0x3DE)
+#define SPR_SER          (0x3DF)
+#define SPR_40x_SRR3     (0x3DF)
+#define SPR_L3ITCR0      (0x3E8)
+#define SPR_L3ITCR1      (0x3E9)
+#define SPR_L3ITCR2      (0x3EA)
+#define SPR_L3ITCR3      (0x3EB)
+#define SPR_HID0         (0x3F0)
+#define SPR_40x_DBSR     (0x3F0)
+#define SPR_HID1         (0x3F1)
+#define SPR_IABR         (0x3F2)
+#define SPR_40x_DBCR0    (0x3F2)
+#define SPR_601_HID2     (0x3F2)
+#define SPR_E500_L1CSR0  (0x3F2)
+#define SPR_ICTRL        (0x3F3)
+#define SPR_HID2         (0x3F3)
+#define SPR_E500_L1CSR1  (0x3F3)
+#define SPR_440_DBDR     (0x3F3)
+#define SPR_LDSTDB       (0x3F4)
+#define SPR_40x_IAC1     (0x3F4)
+#define SPR_BOOKE_MMUCSR0 (0x3F4)
+#define SPR_DABR         (0x3F5)
 #define DABR_MASK (~(target_ulong)0x7)
-#define SPR_40x_IAC2   (0x3F5)
-#define SPR_601_HID5   (0x3F5)
-#define SPR_40x_DAC1   (0x3F6)
-#define SPR_40x_DAC2   (0x3F7)
-#define SPR_L2PM       (0x3F8)
-#define SPR_750_HID2   (0x3F8)
-#define SPR_L2CR       (0x3F9)
-#define SPR_IABR2      (0x3FA)
-#define SPR_40x_DCCR   (0x3FA)
-#define SPR_ICTC       (0x3FB)
-#define SPR_40x_ICCR   (0x3FB)
-#define SPR_THRM1      (0x3FC)
-#define SPR_403_PBL1   (0x3FC)
-#define SPR_SP         (0x3FD)
-#define SPR_THRM2      (0x3FD)
-#define SPR_403_PBU1   (0x3FD)
-#define SPR_LT         (0x3FE)
-#define SPR_THRM3      (0x3FE)
-#define SPR_FPECR      (0x3FE)
-#define SPR_403_PBL2   (0x3FE)
-#define SPR_PIR        (0x3FF)
-#define SPR_403_PBU2   (0x3FF)
-#define SPR_601_HID15  (0x3FF)
+#define SPR_E500_BUCSR   (0x3F5)
+#define SPR_40x_IAC2     (0x3F5)
+#define SPR_601_HID5     (0x3F5)
+#define SPR_40x_DAC1     (0x3F6)
+#define SPR_MSSCR0       (0x3F6)
+#define SPR_MSSSR0       (0x3F7)
+#define SPR_DABRX        (0x3F7)
+#define SPR_40x_DAC2     (0x3F7)
+#define SPR_BOOKE_MMUCFG (0x3F7)
+#define SPR_LDSTCR       (0x3F8)
+#define SPR_L2PMCR       (0x3F8)
+#define SPR_750_HID2     (0x3F8)
+#define SPR_620_HID8     (0x3F8)
+#define SPR_L2CR         (0x3F9)
+#define SPR_620_HID9     (0x3F9)
+#define SPR_L3CR         (0x3FA)
+#define SPR_IABR2        (0x3FA)
+#define SPR_40x_DCCR     (0x3FA)
+#define SPR_ICTC         (0x3FB)
+#define SPR_40x_ICCR     (0x3FB)
+#define SPR_THRM1        (0x3FC)
+#define SPR_403_PBL1     (0x3FC)
+#define SPR_SP           (0x3FD)
+#define SPR_THRM2        (0x3FD)
+#define SPR_403_PBU1     (0x3FD)
+#define SPR_604_HID13    (0x3FD)
+#define SPR_LT           (0x3FE)
+#define SPR_THRM3        (0x3FE)
+#define SPR_FPECR        (0x3FE)
+#define SPR_403_PBL2     (0x3FE)
+#define SPR_PIR          (0x3FF)
+#define SPR_403_PBU2     (0x3FF)
+#define SPR_601_HID15    (0x3FF)
+#define SPR_604_HID15    (0x3FF)
+#define SPR_E500_SVR     (0x3FF)
 
+/*****************************************************************************/
 /* Memory access type :
  * may be needed for precise access rights control and precise exceptions.
  */
@@ -916,109 +1096,85 @@
     ACCESS_CACHE = 0x60, /* Cache manipulation               */
 };
 
-/*****************************************************************************/
-/* Exceptions */
-#define EXCP_NONE          -1
-/* PowerPC hardware exceptions : exception vectors defined in PowerPC book 3 */
-#define EXCP_RESET         0x0100 /* System reset                            */
-#define EXCP_MACHINE_CHECK 0x0200 /* Machine check exception                 */
-#define EXCP_DSI           0x0300 /* Data storage exception                  */
-#define EXCP_DSEG          0x0380 /* Data segment exception                  */
-#define EXCP_ISI           0x0400 /* Instruction storage exception           */
-#define EXCP_ISEG          0x0480 /* Instruction segment exception           */
-#define EXCP_EXTERNAL      0x0500 /* External interruption                   */
-#define EXCP_ALIGN         0x0600 /* Alignment exception                     */
-#define EXCP_PROGRAM       0x0700 /* Program exception                       */
-#define EXCP_NO_FP         0x0800 /* Floating point unavailable exception    */
-#define EXCP_DECR          0x0900 /* Decrementer exception                   */
-#define EXCP_HDECR         0x0980 /* Hypervisor decrementer exception        */
-#define EXCP_SYSCALL       0x0C00 /* System call                             */
-#define EXCP_TRACE         0x0D00 /* Trace exception                         */
-#define EXCP_PERF          0x0F00 /* Performance monitor exception           */
-/* Exceptions defined in PowerPC 32 bits programming environment manual      */
-#define EXCP_FP_ASSIST     0x0E00 /* Floating-point assist                   */
-/* Implementation specific exceptions                                        */
-/* 40x exceptions                                                            */
-#define EXCP_40x_PIT       0x1000 /* Programmable interval timer interrupt   */
-#define EXCP_40x_FIT       0x1010 /* Fixed interval timer interrupt          */
-#define EXCP_40x_WATCHDOG  0x1020 /* Watchdog timer exception                */
-#define EXCP_40x_DTLBMISS  0x1100 /* Data TLB miss exception                 */
-#define EXCP_40x_ITLBMISS  0x1200 /* Instruction TLB miss exception          */
-#define EXCP_40x_DEBUG     0x2000 /* Debug exception                         */
-/* 405 specific exceptions                                                   */
-#define EXCP_405_APU       0x0F20 /* APU unavailable exception               */
-/* TLB assist exceptions (602/603)                                           */
-#define EXCP_I_TLBMISS     0x1000 /* Instruction TLB miss                    */
-#define EXCP_DL_TLBMISS    0x1100 /* Data load TLB miss                      */
-#define EXCP_DS_TLBMISS    0x1200 /* Data store TLB miss                     */
-/* Breakpoint exceptions (602/603/604/620/740/745/750/755...)                */
-#define EXCP_IABR          0x1300 /* Instruction address breakpoint          */
-#define EXCP_SMI           0x1400 /* System management interrupt             */
-/* Altivec related exceptions                                                */
-#define EXCP_VPU           0x0F20 /* VPU unavailable exception               */
-/* 601 specific exceptions                                                   */
-#define EXCP_601_IO        0x0600 /* IO error exception                      */
-#define EXCP_601_RUNM      0x2000 /* Run mode exception                      */
-/* 602 specific exceptions                                                   */
-#define EXCP_602_WATCHDOG  0x1500 /* Watchdog exception                      */
-#define EXCP_602_EMUL      0x1600 /* Emulation trap exception                */
-/* G2 specific exceptions                                                    */
-#define EXCP_G2_CRIT       0x0A00 /* Critical interrupt                      */
-/* MPC740/745/750 & IBM 750 specific exceptions                              */
-#define EXCP_THRM          0x1700 /* Thermal management interrupt            */
-/* 74xx specific exceptions                                                  */
-#define EXCP_74xx_VPUA     0x1600 /* VPU assist exception                    */
-/* 970FX specific exceptions                                                 */
-#define EXCP_970_SOFTP     0x1500 /* Soft patch exception                    */
-#define EXCP_970_MAINT     0x1600 /* Maintenance exception                   */
-#define EXCP_970_THRM      0x1800 /* Thermal exception                       */
-#define EXCP_970_VPUA      0x1700 /* VPU assist exception                    */
-/* End of exception vectors area                                             */
-#define EXCP_PPC_MAX       0x4000
-/* Qemu exceptions: special cases we want to stop translation                */
-#define EXCP_MTMSR         0x11000 /* mtmsr instruction:                     */
-                                /* may change privilege level       */
-#define EXCP_BRANCH        0x11001 /* branch instruction                     */
-#define EXCP_SYSCALL_USER  0x12000 /* System call in user mode only          */
-#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ                      */
-
-/* Error codes */
+/* Hardware interruption sources:
+ * all those exception can be raised simulteaneously
+ */
+/* Input pins definitions */
 enum {
-    /* Exception subtypes for EXCP_ALIGN                            */
-    EXCP_ALIGN_FP      = 0x01,  /* FP alignment exception           */
-    EXCP_ALIGN_LST     = 0x02,  /* Unaligned mult/extern load/store */
-    EXCP_ALIGN_LE      = 0x03,  /* Multiple little-endian access    */
-    EXCP_ALIGN_PROT    = 0x04,  /* Access cross protection boundary */
-    EXCP_ALIGN_BAT     = 0x05,  /* Access cross a BAT/seg boundary  */
-    EXCP_ALIGN_CACHE   = 0x06,  /* Impossible dcbz access           */
-    /* Exception subtypes for EXCP_PROGRAM                          */
-    /* FP exceptions */
-    EXCP_FP            = 0x10,
-    EXCP_FP_OX         = 0x01,  /* FP overflow                      */
-    EXCP_FP_UX         = 0x02,  /* FP underflow                     */
-    EXCP_FP_ZX         = 0x03,  /* FP divide by zero                */
-    EXCP_FP_XX         = 0x04,  /* FP inexact                       */
-    EXCP_FP_VXNAN      = 0x05,  /* FP invalid SNaN op               */
-    EXCP_FP_VXISI      = 0x06,  /* FP invalid infinite substraction */
-    EXCP_FP_VXIDI      = 0x07,  /* FP invalid infinite divide       */
-    EXCP_FP_VXZDZ      = 0x08,  /* FP invalid zero divide           */
-    EXCP_FP_VXIMZ      = 0x09,  /* FP invalid infinite * zero       */
-    EXCP_FP_VXVC       = 0x0A,  /* FP invalid compare               */
-    EXCP_FP_VXSOFT     = 0x0B,  /* FP invalid operation             */
-    EXCP_FP_VXSQRT     = 0x0C,  /* FP invalid square root           */
-    EXCP_FP_VXCVI      = 0x0D,  /* FP invalid integer conversion    */
-    /* Invalid instruction */
-    EXCP_INVAL         = 0x20,
-    EXCP_INVAL_INVAL   = 0x01,  /* Invalid instruction              */
-    EXCP_INVAL_LSWX    = 0x02,  /* Invalid lswx instruction         */
-    EXCP_INVAL_SPR     = 0x03,  /* Invalid SPR access               */
-    EXCP_INVAL_FP      = 0x04,  /* Unimplemented mandatory fp instr */
-    /* Privileged instruction */
-    EXCP_PRIV          = 0x30,
-    EXCP_PRIV_OPC      = 0x01,
-    EXCP_PRIV_REG      = 0x02,
-    /* Trap */
-    EXCP_TRAP          = 0x40,
+    /* 6xx bus input pins */
+    PPC6xx_INPUT_HRESET     = 0,
+    PPC6xx_INPUT_SRESET     = 1,
+    PPC6xx_INPUT_CKSTP_IN   = 2,
+    PPC6xx_INPUT_MCP        = 3,
+    PPC6xx_INPUT_SMI        = 4,
+    PPC6xx_INPUT_INT        = 5,
+};
+
+enum {
+    /* Embedded PowerPC input pins */
+    PPCBookE_INPUT_HRESET     = 0,
+    PPCBookE_INPUT_SRESET     = 1,
+    PPCBookE_INPUT_CKSTP_IN   = 2,
+    PPCBookE_INPUT_MCP        = 3,
+    PPCBookE_INPUT_SMI        = 4,
+    PPCBookE_INPUT_INT        = 5,
+    PPCBookE_INPUT_CINT       = 6,
+};
+
+enum {
+    /* PowerPC 40x input pins */
+    PPC40x_INPUT_RESET_CORE = 0,
+    PPC40x_INPUT_RESET_CHIP = 1,
+    PPC40x_INPUT_RESET_SYS  = 2,
+    PPC40x_INPUT_CINT       = 3,
+    PPC40x_INPUT_INT        = 4,
+    PPC40x_INPUT_HALT       = 5,
+    PPC40x_INPUT_DEBUG      = 6,
+    PPC40x_INPUT_NB,
+};
+
+enum {
+    /* PowerPC 620 (and probably others) input pins */
+    PPC620_INPUT_HRESET     = 0,
+    PPC620_INPUT_SRESET     = 1,
+    PPC620_INPUT_CKSTP      = 2,
+    PPC620_INPUT_TBEN       = 3,
+    PPC620_INPUT_WAKEUP     = 4,
+    PPC620_INPUT_MCP        = 5,
+    PPC620_INPUT_SMI        = 6,
+    PPC620_INPUT_INT        = 7,
+};
+
+enum {
+    /* PowerPC 970 input pins */
+    PPC970_INPUT_HRESET     = 0,
+    PPC970_INPUT_SRESET     = 1,
+    PPC970_INPUT_CKSTP      = 2,
+    PPC970_INPUT_TBEN       = 3,
+    PPC970_INPUT_MCP        = 4,
+    PPC970_INPUT_INT        = 5,
+    PPC970_INPUT_THINT      = 6,
+};
+
+/* Hardware exceptions definitions */
+enum {
+    /* External hardware exception sources */
+    PPC_INTERRUPT_RESET     = 0,  /* Reset exception                      */
+    PPC_INTERRUPT_MCK       = 1,  /* Machine check exception              */
+    PPC_INTERRUPT_EXT       = 2,  /* External interrupt                   */
+    PPC_INTERRUPT_SMI       = 3,  /* System management interrupt          */
+    PPC_INTERRUPT_CEXT      = 4,  /* Critical external interrupt          */
+    PPC_INTERRUPT_DEBUG     = 5,  /* External debug exception             */
+    PPC_INTERRUPT_THERM     = 6,  /* Thermal exception                    */
+    /* Internal hardware exception sources */
+    PPC_INTERRUPT_DECR      = 7,  /* Decrementer exception                */
+    PPC_INTERRUPT_HDECR     = 8,  /* Hypervisor decrementer exception     */
+    PPC_INTERRUPT_PIT       = 9,  /* Programmable inteval timer interrupt */
+    PPC_INTERRUPT_FIT       = 10, /* Fixed interval timer interrupt       */
+    PPC_INTERRUPT_WDT       = 11, /* Watchdog timer interrupt             */
+    PPC_INTERRUPT_CDOORBELL = 12, /* Critical doorbell interrupt          */
+    PPC_INTERRUPT_DOORBELL  = 13, /* Doorbell interrupt                   */
+    PPC_INTERRUPT_PERFM     = 14, /* Performance monitor interrupt        */
 };
 
 /*****************************************************************************/
diff --git a/target-ppc/exec.h b/target-ppc/exec.h
index 89171f9..8a54258 100644
--- a/target-ppc/exec.h
+++ b/target-ppc/exec.h
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation definitions for qemu.
- * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -24,15 +24,40 @@
 
 #include "dyngen-exec.h"
 
-#define TARGET_LONG_BITS 32
+#include "cpu.h"
+#include "exec-all.h"
+
+/* For normal operations, precise emulation should not be needed */
+//#define USE_PRECISE_EMULATION 1
+#define USE_PRECISE_EMULATION 0
 
 register struct CPUPPCState *env asm(AREG0);
-register uint32_t T0 asm(AREG1);
-register uint32_t T1 asm(AREG2);
-register uint32_t T2 asm(AREG3);
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+/* no registers can be used */
+#define T0 (env->t0)
+#define T1 (env->t1)
+#define T2 (env->t2)
+#else
+register unsigned long T0 asm(AREG1);
+register unsigned long T1 asm(AREG2);
+register unsigned long T2 asm(AREG3);
+#endif
+/* We may, sometime, need 64 bits registers on 32 bits target */
+#if TARGET_GPR_BITS > HOST_LONG_BITS
+/* no registers can be used */
+#define T0_64 (env->t0)
+#define T1_64 (env->t1)
+#define T2_64 (env->t2)
+#else
+#define T0_64 T0
+#define T1_64 T1
+#define T2_64 T2
+#endif
+/* Provision for Altivec */
+#define T0_avr (env->t0_avr)
+#define T1_avr (env->t1_avr)
+#define T2_avr (env->t2_avr)
 
-#define PARAM(n) ((uint32_t)PARAM##n)
-#define SPARAM(n) ((int32_t)PARAM##n)
 #define FT0 (env->ft0)
 #define FT1 (env->ft1)
 #define FT2 (env->ft2)
@@ -43,14 +68,28 @@
 # define RETURN() __asm__ __volatile__("" : : : "memory");
 #endif
 
-#include "cpu.h"
-#include "exec-all.h"
-
-static inline uint32_t rotl (uint32_t i, int n)
+static inline target_ulong rotl8 (target_ulong i, int n)
 {
-    return ((i << n) | (i >> (32 - n)));
+    return (((uint8_t)i << n) | ((uint8_t)i >> (8 - n)));
 }
 
+static inline target_ulong rotl16 (target_ulong i, int n)
+{
+    return (((uint16_t)i << n) | ((uint16_t)i >> (16 - n)));
+}
+
+static inline target_ulong rotl32 (target_ulong i, int n)
+{
+    return (((uint32_t)i << n) | ((uint32_t)i >> (32 - n)));
+}
+
+#if defined(TARGET_PPC64)
+static inline target_ulong rotl64 (target_ulong i, int n)
+{
+    return (((uint64_t)i << n) | ((uint64_t)i >> (64 - n)));
+}
+#endif
+
 #if !defined(CONFIG_USER_ONLY)
 #include "softmmu_exec.h"
 #endif /* !defined(CONFIG_USER_ONLY) */
@@ -58,33 +97,32 @@
 void do_raise_exception_err (uint32_t exception, int error_code);
 void do_raise_exception (uint32_t exception);
 
-void do_sraw(void);
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr,
+                          int rw, int access_type, int check_BATs);
 
-void do_fctiw (void);
-void do_fctiwz (void);
-void do_fnmadd (void);
-void do_fnmsub (void);
-void do_fsqrt (void);
-void do_fres (void);
-void do_frsqrte (void);
-void do_fsel (void);
-void do_fcmpu (void);
-void do_fcmpo (void);
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+                       target_ulong pte0, target_ulong pte1);
 
-void do_check_reservation (void);
-void do_icbi (void);
-void do_tlbia (void);
-void do_tlbie (void);
-
-static inline void env_to_regs(void)
+static inline void env_to_regs (void)
 {
 }
 
-static inline void regs_to_env(void)
+static inline void regs_to_env (void)
 {
 }
 
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu);
 
+static inline int cpu_halted (CPUState *env)
+{
+    if (!env->halted)
+        return 0;
+    if (env->msr[MSR_EE] && (env->interrupt_request & CPU_INTERRUPT_HARD)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
 #endif /* !defined (__PPC_H__) */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
index 70b0a49..5b0fd09 100644
--- a/target-ppc/helper.c
+++ b/target-ppc/helper.c
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation helpers for qemu.
- * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -30,23 +30,24 @@
 
 //#define DEBUG_MMU
 //#define DEBUG_BATS
+//#define DEBUG_SOFTWARE_TLB
 //#define DEBUG_EXCEPTIONS
 //#define FLUSH_ALL_TLBS
 
 /*****************************************************************************/
 /* PowerPC MMU emulation */
 
-#if defined(CONFIG_USER_ONLY) 
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+#if defined(CONFIG_USER_ONLY)
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu)
 {
     int exception, error_code;
-    
+
     if (rw == 2) {
-        exception = EXCP_ISI;
+        exception = POWERPC_EXCP_ISI;
         error_code = 0;
     } else {
-        exception = EXCP_DSI;
+        exception = POWERPC_EXCP_DSI;
         error_code = 0;
         if (rw)
             error_code |= 0x02000000;
@@ -55,26 +56,354 @@
     }
     env->exception_index = exception;
     env->error_code = error_code;
+
     return 1;
 }
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
 {
     return addr;
 }
+
 #else
-/* Perform BAT hit & translation */
-static int get_bat (CPUState *env, uint32_t *real, int *prot,
-                    uint32_t virtual, int rw, int type)
+/* Common routines used by software and hardware TLBs emulation */
+static inline int pte_is_valid (target_ulong pte0)
 {
-    uint32_t *BATlt, *BATut, *BATu, *BATl;
-    uint32_t base, BEPIl, BEPIu, bl;
+    return pte0 & 0x80000000 ? 1 : 0;
+}
+
+static inline void pte_invalidate (target_ulong *pte0)
+{
+    *pte0 &= ~0x80000000;
+}
+
+#if defined(TARGET_PPC64)
+static inline int pte64_is_valid (target_ulong pte0)
+{
+    return pte0 & 0x0000000000000001ULL ? 1 : 0;
+}
+
+static inline void pte64_invalidate (target_ulong *pte0)
+{
+    *pte0 &= ~0x0000000000000001ULL;
+}
+#endif
+
+#define PTE_PTEM_MASK 0x7FFFFFBF
+#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+#if defined(TARGET_PPC64)
+#define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
+#define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
+#endif
+
+static inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
+                              target_ulong pte0, target_ulong pte1,
+                              int h, int rw)
+{
+    target_ulong ptem, mmask;
+    int access, ret, pteh, ptev;
+
+    access = 0;
+    ret = -1;
+    /* Check validity and table match */
+#if defined(TARGET_PPC64)
+    if (is_64b) {
+        ptev = pte64_is_valid(pte0);
+        pteh = (pte0 >> 1) & 1;
+    } else
+#endif
+    {
+        ptev = pte_is_valid(pte0);
+        pteh = (pte0 >> 6) & 1;
+    }
+    if (ptev && h == pteh) {
+        /* Check vsid & api */
+#if defined(TARGET_PPC64)
+        if (is_64b) {
+            ptem = pte0 & PTE64_PTEM_MASK;
+            mmask = PTE64_CHECK_MASK;
+        } else
+#endif
+        {
+            ptem = pte0 & PTE_PTEM_MASK;
+            mmask = PTE_CHECK_MASK;
+        }
+        if (ptem == ctx->ptem) {
+            if (ctx->raddr != (target_ulong)-1) {
+                /* all matches should have equal RPN, WIMG & PP */
+                if ((ctx->raddr & mmask) != (pte1 & mmask)) {
+                    if (loglevel != 0)
+                        fprintf(logfile, "Bad RPN/WIMG/PP\n");
+                    return -3;
+                }
+            }
+            /* Compute access rights */
+            if (ctx->key == 0) {
+                access = PAGE_READ;
+                if ((pte1 & 0x00000003) != 0x3)
+                    access |= PAGE_WRITE;
+            } else {
+                switch (pte1 & 0x00000003) {
+                case 0x0:
+                    access = 0;
+                    break;
+                case 0x1:
+                case 0x3:
+                    access = PAGE_READ;
+                    break;
+                case 0x2:
+                    access = PAGE_READ | PAGE_WRITE;
+                    break;
+                }
+            }
+            /* Keep the matching PTE informations */
+            ctx->raddr = pte1;
+            ctx->prot = access;
+            if ((rw == 0 && (access & PAGE_READ)) ||
+                (rw == 1 && (access & PAGE_WRITE))) {
+                /* Access granted */
+#if defined (DEBUG_MMU)
+                if (loglevel != 0)
+                    fprintf(logfile, "PTE access granted !\n");
+#endif
+                ret = 0;
+            } else {
+                /* Access right violation */
+#if defined (DEBUG_MMU)
+                if (loglevel != 0)
+                    fprintf(logfile, "PTE access rejected\n");
+#endif
+                ret = -2;
+            }
+        }
+    }
+
+    return ret;
+}
+
+static int pte32_check (mmu_ctx_t *ctx,
+                        target_ulong pte0, target_ulong pte1, int h, int rw)
+{
+    return _pte_check(ctx, 0, pte0, pte1, h, rw);
+}
+
+#if defined(TARGET_PPC64)
+static int pte64_check (mmu_ctx_t *ctx,
+                        target_ulong pte0, target_ulong pte1, int h, int rw)
+{
+    return _pte_check(ctx, 1, pte0, pte1, h, rw);
+}
+#endif
+
+static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
+                             int ret, int rw)
+{
+    int store = 0;
+
+    /* Update page flags */
+    if (!(*pte1p & 0x00000100)) {
+        /* Update accessed flag */
+        *pte1p |= 0x00000100;
+        store = 1;
+    }
+    if (!(*pte1p & 0x00000080)) {
+        if (rw == 1 && ret == 0) {
+            /* Update changed flag */
+            *pte1p |= 0x00000080;
+            store = 1;
+        } else {
+            /* Force page fault for first write access */
+            ctx->prot &= ~PAGE_WRITE;
+        }
+    }
+
+    return store;
+}
+
+/* Software driven TLB helpers */
+static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
+                              int way, int is_code)
+{
+    int nr;
+
+    /* Select TLB num in a way from address */
+    nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
+    /* Select TLB way */
+    nr += env->tlb_per_way * way;
+    /* 6xx have separate TLBs for instructions and data */
+    if (is_code && env->id_tlbs == 1)
+        nr += env->nb_tlb;
+
+    return nr;
+}
+
+static void ppc6xx_tlb_invalidate_all (CPUState *env)
+{
+    ppc6xx_tlb_t *tlb;
+    int nr, max;
+
+#if defined (DEBUG_SOFTWARE_TLB) && 0
+    if (loglevel != 0) {
+        fprintf(logfile, "Invalidate all TLBs\n");
+    }
+#endif
+    /* Invalidate all defined software TLB */
+    max = env->nb_tlb;
+    if (env->id_tlbs == 1)
+        max *= 2;
+    for (nr = 0; nr < max; nr++) {
+        tlb = &env->tlb[nr].tlb6;
+        pte_invalidate(&tlb->pte0);
+    }
+    tlb_flush(env, 1);
+}
+
+static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
+                                                 target_ulong eaddr,
+                                                 int is_code, int match_epn)
+{
+#if !defined(FLUSH_ALL_TLBS)
+    ppc6xx_tlb_t *tlb;
+    int way, nr;
+
+    /* Invalidate ITLB + DTLB, all ways */
+    for (way = 0; way < env->nb_ways; way++) {
+        nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
+        tlb = &env->tlb[nr].tlb6;
+        if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (loglevel != 0) {
+                fprintf(logfile, "TLB invalidate %d/%d " ADDRX "\n",
+                        nr, env->nb_tlb, eaddr);
+            }
+#endif
+            pte_invalidate(&tlb->pte0);
+            tlb_flush_page(env, tlb->EPN);
+        }
+    }
+#else
+    /* XXX: PowerPC specification say this is valid as well */
+    ppc6xx_tlb_invalidate_all(env);
+#endif
+}
+
+static void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+                                        int is_code)
+{
+    __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
+}
+
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+                       target_ulong pte0, target_ulong pte1)
+{
+    ppc6xx_tlb_t *tlb;
+    int nr;
+
+    nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
+    tlb = &env->tlb[nr].tlb6;
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX
+                " PTE1 " ADDRX "\n", nr, env->nb_tlb, EPN, pte0, pte1);
+    }
+#endif
+    /* Invalidate any pending reference in Qemu for this virtual address */
+    __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
+    tlb->pte0 = pte0;
+    tlb->pte1 = pte1;
+    tlb->EPN = EPN;
+    /* Store last way for LRU mechanism */
+    env->last_way = way;
+}
+
+static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
+                             target_ulong eaddr, int rw, int access_type)
+{
+    ppc6xx_tlb_t *tlb;
+    int nr, best, way;
+    int ret;
+
+    best = -1;
+    ret = -1; /* No TLB found */
+    for (way = 0; way < env->nb_ways; way++) {
+        nr = ppc6xx_tlb_getnum(env, eaddr, way,
+                               access_type == ACCESS_CODE ? 1 : 0);
+        tlb = &env->tlb[nr].tlb6;
+        /* This test "emulates" the PTE index match for hardware TLBs */
+        if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (loglevel != 0) {
+                fprintf(logfile, "TLB %d/%d %s [" ADDRX " " ADDRX
+                        "] <> " ADDRX "\n",
+                        nr, env->nb_tlb,
+                        pte_is_valid(tlb->pte0) ? "valid" : "inval",
+                        tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
+            }
+#endif
+            continue;
+        }
+#if defined (DEBUG_SOFTWARE_TLB)
+        if (loglevel != 0) {
+            fprintf(logfile, "TLB %d/%d %s " ADDRX " <> " ADDRX " " ADDRX
+                    " %c %c\n",
+                    nr, env->nb_tlb,
+                    pte_is_valid(tlb->pte0) ? "valid" : "inval",
+                    tlb->EPN, eaddr, tlb->pte1,
+                    rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
+        }
+#endif
+        switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) {
+        case -3:
+            /* TLB inconsistency */
+            return -1;
+        case -2:
+            /* Access violation */
+            ret = -2;
+            best = nr;
+            break;
+        case -1:
+        default:
+            /* No match */
+            break;
+        case 0:
+            /* access granted */
+            /* XXX: we should go on looping to check all TLBs consistency
+             *      but we can speed-up the whole thing as the
+             *      result would be undefined if TLBs are not consistent.
+             */
+            ret = 0;
+            best = nr;
+            goto done;
+        }
+    }
+    if (best != -1) {
+    done:
+#if defined (DEBUG_SOFTWARE_TLB)
+        if (loglevel != 0) {
+            fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n",
+                    ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+        }
+#endif
+        /* Update page flags */
+        pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
+    }
+
+    return ret;
+}
+
+/* Perform BAT hit & translation */
+static int get_bat (CPUState *env, mmu_ctx_t *ctx,
+                    target_ulong virtual, int rw, int type)
+{
+    target_ulong *BATlt, *BATut, *BATu, *BATl;
+    target_ulong base, BEPIl, BEPIu, bl;
     int i;
     int ret = -1;
 
 #if defined (DEBUG_BATS)
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__,
-               type == ACCESS_CODE ? 'I' : 'D', virtual);
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: %cBAT v 0x" ADDRX "\n", __func__,
+                type == ACCESS_CODE ? 'I' : 'D', virtual);
     }
 #endif
     switch (type) {
@@ -88,9 +417,9 @@
         break;
     }
 #if defined (DEBUG_BATS)
-    if (loglevel > 0) {
-        fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__,
-               type == ACCESS_CODE ? 'I' : 'D', virtual);
+    if (loglevel != 0) {
+        fprintf(logfile, "%s...: %cBAT v 0x" ADDRX "\n", __func__,
+                type == ACCESS_CODE ? 'I' : 'D', virtual);
     }
 #endif
     base = virtual & 0xFFFC0000;
@@ -101,8 +430,9 @@
         BEPIl = *BATu & 0x0FFE0000;
         bl = (*BATu & 0x00001FFC) << 15;
 #if defined (DEBUG_BATS)
-        if (loglevel > 0) {
-            fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n",
+        if (loglevel != 0) {
+            fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
+                    " BATl 0x" ADDRX "\n",
                     __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
                     *BATu, *BATl);
         }
@@ -113,18 +443,19 @@
             if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
                 (msr_pr == 1 && (*BATu & 0x00000001))) {
                 /* Get physical address */
-                *real = (*BATl & 0xF0000000) |
+                ctx->raddr = (*BATl & 0xF0000000) |
                     ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
                     (virtual & 0x0001F000);
                 if (*BATl & 0x00000001)
-                    *prot = PAGE_READ;
+                    ctx->prot = PAGE_READ;
                 if (*BATl & 0x00000002)
-                    *prot = PAGE_WRITE | PAGE_READ;
+                    ctx->prot = PAGE_WRITE | PAGE_READ;
 #if defined (DEBUG_BATS)
-                if (loglevel > 0) {
-                    fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n",
-                            i, *real, *prot & PAGE_READ ? 'R' : '-',
-                            *prot & PAGE_WRITE ? 'W' : '-');
+                if (loglevel != 0) {
+                    fprintf(logfile, "BAT %d match: r 0x" PADDRX
+                            " prot=%c%c\n",
+                            i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
+                            ctx->prot & PAGE_WRITE ? 'W' : '-');
                 }
 #endif
                 ret = 0;
@@ -134,17 +465,20 @@
     }
     if (ret < 0) {
 #if defined (DEBUG_BATS)
-        printf("no BAT match for 0x%08x:\n", virtual);
-        for (i = 0; i < 4; i++) {
-            BATu = &BATut[i];
-            BATl = &BATlt[i];
-            BEPIu = *BATu & 0xF0000000;
-            BEPIl = *BATu & 0x0FFE0000;
-            bl = (*BATu & 0x00001FFC) << 15;
-            printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x \n\t"
-                   "0x%08x 0x%08x 0x%08x\n",
-                   __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
-                   *BATu, *BATl, BEPIu, BEPIl, bl);
+        if (loglevel != 0) {
+            fprintf(logfile, "no BAT match for 0x" ADDRX ":\n", virtual);
+            for (i = 0; i < 4; i++) {
+                BATu = &BATut[i];
+                BATl = &BATlt[i];
+                BEPIu = *BATu & 0xF0000000;
+                BEPIl = *BATu & 0x0FFE0000;
+                bl = (*BATu & 0x00001FFC) << 15;
+                fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
+                        " BATl 0x" ADDRX " \n\t"
+                        "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n",
+                        __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
+                        *BATu, *BATl, BEPIu, BEPIl, bl);
+            }
         }
 #endif
     }
@@ -153,189 +487,292 @@
 }
 
 /* PTE table lookup */
-static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va,
-                     int h, int key, int rw)
+static inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h, int rw)
 {
-    uint32_t pte0, pte1, keep = 0, access = 0;
-    int i, good = -1, store = 0;
-    int ret = -1; /* No entry found */
+    target_ulong base, pte0, pte1;
+    int i, good = -1;
+    int ret, r;
 
+    ret = -1; /* No entry found */
+    base = ctx->pg_addr[h];
     for (i = 0; i < 8; i++) {
-        pte0 = ldl_phys(base + (i * 8));
-        pte1 =  ldl_phys(base + (i * 8) + 4);
-#if defined (DEBUG_MMU)
-        if (loglevel > 0) {
-	    fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x "
-		    "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1,
-		    pte0 >> 31, h, (pte0 >> 6) & 1, va);
-	}
+#if defined(TARGET_PPC64)
+        if (is_64b) {
+            pte0 = ldq_phys(base + (i * 16));
+            pte1 =  ldq_phys(base + (i * 16) + 8);
+            r = pte64_check(ctx, pte0, pte1, h, rw);
+        } else
 #endif
-        /* Check validity and table match */
-        if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) {
-            /* Check vsid & api */
-            if ((pte0 & 0x7FFFFFBF) == va) {
-                if (good == -1) {
-                    good = i;
-                    keep = pte1;
-                } else {
-                    /* All matches should have equal RPN, WIMG & PP */
-                    if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) {
-			if (loglevel > 0)
-			    fprintf(logfile, "Bad RPN/WIMG/PP\n");
-                        return -1;
-                    }
-                }
-                /* Check access rights */
-                if (key == 0) {
-                    access = PAGE_READ;
-                    if ((pte1 & 0x00000003) != 0x3)
-                        access |= PAGE_WRITE;
-                } else {
-                    switch (pte1 & 0x00000003) {
-                    case 0x0:
-                        access = 0;
-                        break;
-                    case 0x1:
-                    case 0x3:
-                        access = PAGE_READ;
-                        break;
-                    case 0x2:
-                        access = PAGE_READ | PAGE_WRITE;
-                        break;
-                    }
-                }
-                if (ret < 0) {
-		    if ((rw == 0 && (access & PAGE_READ)) ||
-			(rw == 1 && (access & PAGE_WRITE))) {
+        {
+            pte0 = ldl_phys(base + (i * 8));
+            pte1 =  ldl_phys(base + (i * 8) + 4);
+            r = pte32_check(ctx, pte0, pte1, h, rw);
+        }
 #if defined (DEBUG_MMU)
-			if (loglevel > 0)
-			    fprintf(logfile, "PTE access granted !\n");
+        if (loglevel != 0) {
+            fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
+                    " 0x" ADDRX " %d %d %d 0x" ADDRX "\n",
+                    base + (i * 8), pte0, pte1,
+                    (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1), ctx->ptem);
+        }
 #endif
-                        good = i;
-                        keep = pte1;
-                        ret = 0;
-		    } else {
-			/* Access right violation */
-                        ret = -2;
-#if defined (DEBUG_MMU)
-			if (loglevel > 0)
-			    fprintf(logfile, "PTE access rejected\n");
-#endif
-                    }
-		    *prot = access;
-		}
-            }
+        switch (r) {
+        case -3:
+            /* PTE inconsistency */
+            return -1;
+        case -2:
+            /* Access violation */
+            ret = -2;
+            good = i;
+            break;
+        case -1:
+        default:
+            /* No PTE match */
+            break;
+        case 0:
+            /* access granted */
+            /* XXX: we should go on looping to check all PTEs consistency
+             *      but if we can speed-up the whole thing as the
+             *      result would be undefined if PTEs are not consistent.
+             */
+            ret = 0;
+            good = i;
+            goto done;
         }
     }
     if (good != -1) {
-        *RPN = keep & 0xFFFFF000;
+    done:
 #if defined (DEBUG_MMU)
-        if (loglevel > 0) {
-	    fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
-               *RPN, *prot, ret);
-	}
+        if (loglevel != 0) {
+            fprintf(logfile, "found PTE at addr 0x" PADDRX " prot=0x%01x "
+                    "ret=%d\n",
+                    ctx->raddr, ctx->prot, ret);
+        }
 #endif
         /* Update page flags */
-        if (!(keep & 0x00000100)) {
-	    /* Access flag */
-            keep |= 0x00000100;
-            store = 1;
-        }
-        if (!(keep & 0x00000080)) {
-	    if (rw && ret == 0) {
-		/* Change flag */
-                keep |= 0x00000080;
-                store = 1;
-	    } else {
-		/* Force page fault for first write access */
-		*prot &= ~PAGE_WRITE;
+        pte1 = ctx->raddr;
+        if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
+#if defined(TARGET_PPC64)
+            if (is_64b) {
+                stq_phys_notdirty(base + (good * 16) + 8, pte1);
+            } else
+#endif
+            {
+                stl_phys_notdirty(base + (good * 8) + 4, pte1);
             }
         }
-        if (store) {
-	    stl_phys_notdirty(base + (good * 8) + 4, keep);
-	}
     }
 
     return ret;
 }
 
-static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask)
+static int find_pte32 (mmu_ctx_t *ctx, int h, int rw)
 {
-    return (sdr1 & 0xFFFF0000) | (hash & mask);
+    return _find_pte(ctx, 0, h, rw);
 }
 
-/* Perform segment based translation */
-static int get_segment (CPUState *env, uint32_t *real, int *prot,
-                        uint32_t virtual, int rw, int type)
+#if defined(TARGET_PPC64)
+static int find_pte64 (mmu_ctx_t *ctx, int h, int rw)
 {
-    uint32_t pg_addr, sdr, ptem, vsid, pgidx;
-    uint32_t hash, mask;
-    uint32_t sr;
-    int key;
-    int ret = -1, ret2;
+    return _find_pte(ctx, 1, h, rw);
+}
+#endif
 
-    sr = env->sr[virtual >> 28];
-#if defined (DEBUG_MMU)
-    if (loglevel > 0) {
-	fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x "
-		"lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n",
-		virtual, virtual >> 28, sr, env->nip,
-		env->lr, msr_ir, msr_dr, msr_pr, rw, type);
+static inline int find_pte (CPUState *env, mmu_ctx_t *ctx, int h, int rw)
+{
+#if defined(TARGET_PPC64)
+    if (env->mmu_model == POWERPC_MMU_64B ||
+        env->mmu_model == POWERPC_MMU_64BRIDGE)
+        return find_pte64(ctx, h, rw);
+#endif
+
+    return find_pte32(ctx, h, rw);
+}
+
+static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
+                                             int sdr_sh,
+                                             target_phys_addr_t hash,
+                                             target_phys_addr_t mask)
+{
+    return (sdr1 & ((target_ulong)(-1ULL) << sdr_sh)) | (hash & mask);
+}
+
+#if defined(TARGET_PPC64)
+static int slb_lookup (CPUState *env, target_ulong eaddr,
+                       target_ulong *vsid, target_ulong *page_mask, int *attr)
+{
+    target_phys_addr_t sr_base;
+    target_ulong mask;
+    uint64_t tmp64;
+    uint32_t tmp;
+    int n, ret;
+    int slb_nr;
+
+    ret = -5;
+    sr_base = env->spr[SPR_ASR];
+    mask = 0x0000000000000000ULL; /* Avoid gcc warning */
+#if 0 /* XXX: Fix this */
+    slb_nr = env->slb_nr;
+#else
+    slb_nr = 32;
+#endif
+    for (n = 0; n < slb_nr; n++) {
+        tmp64 = ldq_phys(sr_base);
+        if (tmp64 & 0x0000000008000000ULL) {
+            /* SLB entry is valid */
+            switch (tmp64 & 0x0000000006000000ULL) {
+            case 0x0000000000000000ULL:
+                /* 256 MB segment */
+                mask = 0xFFFFFFFFF0000000ULL;
+                break;
+            case 0x0000000002000000ULL:
+                /* 1 TB segment */
+                mask = 0xFFFF000000000000ULL;
+                break;
+            case 0x0000000004000000ULL:
+            case 0x0000000006000000ULL:
+                /* Reserved => segment is invalid */
+                continue;
+            }
+            if ((eaddr & mask) == (tmp64 & mask)) {
+                /* SLB match */
+                tmp = ldl_phys(sr_base + 8);
+                *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
+                *page_mask = ~mask;
+                *attr = tmp & 0xFF;
+                ret = 0;
+                break;
+            }
+        }
+        sr_base += 12;
     }
+
+    return ret;
+}
+#endif /* defined(TARGET_PPC64) */
+
+/* Perform segment based translation */
+static int get_segment (CPUState *env, mmu_ctx_t *ctx,
+                        target_ulong eaddr, int rw, int type)
+{
+    target_phys_addr_t sdr, hash, mask, sdr_mask;
+    target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
+#if defined(TARGET_PPC64)
+    int attr;
 #endif
-    key = (((sr & 0x20000000) && msr_pr == 1) ||
-        ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
-    if ((sr & 0x80000000) == 0) {
+    int ds, nx, vsid_sh, sdr_sh;
+    int ret, ret2;
+
+#if defined(TARGET_PPC64)
+    if (env->mmu_model == POWERPC_MMU_64B ||
+        env->mmu_model == POWERPC_MMU_64BRIDGE) {
+        ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr);
+        if (ret < 0)
+            return ret;
+        ctx->key = ((attr & 0x40) && msr_pr == 1) ||
+            ((attr & 0x80) && msr_pr == 0) ? 1 : 0;
+        ds = 0;
+        nx = attr & 0x20 ? 1 : 0;
+        vsid_mask = 0x00003FFFFFFFFF80ULL;
+        vsid_sh = 7;
+        sdr_sh = 18;
+        sdr_mask = 0x3FF80;
+    } else
+#endif /* defined(TARGET_PPC64) */
+    {
+        sr = env->sr[eaddr >> 28];
+        page_mask = 0x0FFFFFFF;
+        ctx->key = (((sr & 0x20000000) && msr_pr == 1) ||
+                    ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
+        ds = sr & 0x80000000 ? 1 : 0;
+        nx = sr & 0x10000000 ? 1 : 0;
+        vsid = sr & 0x00FFFFFF;
+        vsid_mask = 0x01FFFFC0;
+        vsid_sh = 6;
+        sdr_sh = 16;
+        sdr_mask = 0xFFC0;
 #if defined (DEBUG_MMU)
-    if (loglevel > 0) 
-	    fprintf(logfile, "pte segment: key=%d n=0x%08x\n",
-		    key, sr & 0x10000000);
+        if (loglevel != 0) {
+            fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX
+                    " nip=0x" ADDRX " lr=0x" ADDRX
+                    " ir=%d dr=%d pr=%d %d t=%d\n",
+                    eaddr, (int)(eaddr >> 28), sr, env->nip,
+                    env->lr, msr_ir, msr_dr, msr_pr, rw, type);
+        }
+        if (!ds && loglevel != 0) {
+            fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n",
+                    ctx->key, sr & 0x10000000);
+        }
 #endif
+    }
+    ret = -1;
+    if (!ds) {
         /* Check if instruction fetch is allowed, if needed */
-        if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
+        if (type != ACCESS_CODE || nx == 0) {
             /* Page address translation */
-            vsid = sr & 0x00FFFFFF;
-            pgidx = (virtual >> 12) & 0xFFFF;
+            pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS;
+            hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
+            /* Primary table address */
             sdr = env->sdr1;
-            hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6;
-            mask = ((sdr & 0x000001FF) << 16) | 0xFFC0;
-            pg_addr = get_pgaddr(sdr, hash, mask);
-            ptem = (vsid << 7) | (pgidx >> 10);
-#if defined (DEBUG_MMU)
-	    if (loglevel > 0) {
-		fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x "
-			"hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash,
-			pg_addr);
-	    }
+            mask = ((sdr & 0x000001FF) << sdr_sh) | sdr_mask;
+            ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask);
+            /* Secondary table address */
+            hash = (~hash) & vsid_mask;
+            ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask);
+#if defined(TARGET_PPC64)
+            if (env->mmu_model == POWERPC_MMU_64B ||
+                env->mmu_model == POWERPC_MMU_64BRIDGE) {
+                /* Only 5 bits of the page index are used in the AVPN */
+                ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80);
+            } else
 #endif
-            /* Primary table lookup */
-            ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw);
-            if (ret < 0) {
-                /* Secondary table lookup */
-                hash = (~hash) & 0x01FFFFC0;
-                pg_addr = get_pgaddr(sdr, hash, mask);
+            {
+                ctx->ptem = (vsid << 7) | (pgidx >> 10);
+            }
+            /* Initialize real address with an invalid value */
+            ctx->raddr = (target_ulong)-1;
+            if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
+                         env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
+                /* Software TLB search */
+                ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
+            } else {
 #if defined (DEBUG_MMU)
-		if (virtual != 0xEFFFFFFF && loglevel > 0) {
-		    fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x "
-			    "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx,
-			    hash, pg_addr);
-		}
+                if (loglevel != 0) {
+                    fprintf(logfile, "0 sdr1=0x" PADDRX " vsid=0x%06x "
+                            "api=0x%04x hash=0x%07x pg_addr=0x" PADDRX "\n",
+                            sdr, (uint32_t)vsid, (uint32_t)pgidx,
+                            (uint32_t)hash, ctx->pg_addr[0]);
+                }
 #endif
-                ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw);
-                if (ret2 != -1)
-                    ret = ret2;
+                /* Primary table lookup */
+                ret = find_pte(env, ctx, 0, rw);
+                if (ret < 0) {
+                    /* Secondary table lookup */
+#if defined (DEBUG_MMU)
+                    if (eaddr != 0xEFFFFFFF && loglevel != 0) {
+                        fprintf(logfile,
+                                "1 sdr1=0x" PADDRX " vsid=0x%06x api=0x%04x "
+                                "hash=0x%05x pg_addr=0x" PADDRX "\n",
+                                sdr, (uint32_t)vsid, (uint32_t)pgidx,
+                                (uint32_t)hash, ctx->pg_addr[1]);
+                    }
+#endif
+                    ret2 = find_pte(env, ctx, 1, rw);
+                    if (ret2 != -1)
+                        ret = ret2;
+                }
             }
         } else {
 #if defined (DEBUG_MMU)
-	    if (loglevel > 0)
-		fprintf(logfile, "No access allowed\n");
+            if (loglevel != 0)
+                fprintf(logfile, "No access allowed\n");
 #endif
-	    ret = -3;
+            ret = -3;
         }
     } else {
 #if defined (DEBUG_MMU)
-        if (loglevel > 0)
-	    fprintf(logfile, "direct store...\n");
+        if (loglevel != 0)
+            fprintf(logfile, "direct store...\n");
 #endif
         /* Direct-store segment : absolutely *BUGGY* for now */
         switch (type) {
@@ -356,7 +793,7 @@
             /* Should make the instruction do no-op.
              * As it already do no-op, it's quite easy :-)
              */
-            *real = virtual;
+            ctx->raddr = eaddr;
             return 0;
         case ACCESS_EXT:
             /* eciwx or ecowx */
@@ -366,12 +803,10 @@
                 fprintf(logfile, "ERROR: instruction should not need "
                         "address translation\n");
             }
-            printf("ERROR: instruction should not need "
-                   "address translation\n");
             return -4;
         }
-        if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) {
-            *real = virtual;
+        if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+            ctx->raddr = eaddr;
             ret = 2;
         } else {
             ret = -2;
@@ -381,54 +816,417 @@
     return ret;
 }
 
-static int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
-                                 uint32_t address, int rw, int access_type)
+/* Generic TLB check function for embedded PowerPC implementations */
+static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb,
+                             target_phys_addr_t *raddrp,
+                             target_ulong address,
+                             uint32_t pid, int ext, int i)
 {
-    int ret;
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s\n", __func__);
+    target_ulong mask;
+
+    /* Check valid flag */
+    if (!(tlb->prot & PAGE_VALID)) {
+        if (loglevel != 0)
+            fprintf(logfile, "%s: TLB %d not valid\n", __func__, i);
+        return -1;
     }
-#endif    
-    if ((access_type == ACCESS_CODE && msr_ir == 0) ||
-        (access_type != ACCESS_CODE && msr_dr == 0)) {
-        /* No address translation */
-        *physical = address & ~0xFFF;
-        *prot = PAGE_READ | PAGE_WRITE;
-        ret = 0;
-    } else {
-        /* Try to find a BAT */
-        ret = get_bat(env, physical, prot, address, rw, access_type);
-        if (ret < 0) {
-            /* We didn't match any BAT entry */
-            ret = get_segment(env, physical, prot, address, rw, access_type);
+    mask = ~(tlb->size - 1);
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> "
+                ADDRX " " ADDRX " %d\n",
+                __func__, i, address, pid, tlb->EPN, mask, (int)tlb->PID);
+    }
+#endif
+    /* Check PID */
+    if (tlb->PID != 0 && tlb->PID != pid)
+        return -1;
+    /* Check effective address */
+    if ((address & mask) != tlb->EPN)
+        return -1;
+    *raddrp = (tlb->RPN & mask) | (address & ~mask);
+#if (TARGET_PHYS_ADDR_BITS >= 36)
+    if (ext) {
+        /* Extend the physical address to 36 bits */
+        *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
+    }
+#endif
+
+    return 0;
+}
+
+/* Generic TLB search function for PowerPC embedded implementations */
+int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, ret;
+
+    /* Default return value is no match */
+    ret = -1;
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
+            ret = i;
+            break;
         }
     }
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s address %08x => %08x\n",
-		__func__, address, *physical);
-    }
-#endif    
+
     return ret;
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+/* Helpers specific to PowerPC 40x implementations */
+static void ppc4xx_tlb_invalidate_all (CPUState *env)
 {
-    uint32_t phys_addr;
-    int prot;
+    ppcemb_tlb_t *tlb;
+    int i;
 
-    if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        tlb->prot &= ~PAGE_VALID;
+    }
+    tlb_flush(env, 1);
+}
+
+static void ppc4xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+                                        uint32_t pid)
+{
+#if !defined(FLUSH_ALL_TLBS)
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    target_ulong page, end;
+    int i;
+
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
+            end = tlb->EPN + tlb->size;
+            for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+                tlb_flush_page(env, page);
+            tlb->prot &= ~PAGE_VALID;
+            break;
+        }
+    }
+#else
+    ppc4xx_tlb_invalidate_all(env);
+#endif
+}
+
+int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
+                                 target_ulong address, int rw, int access_type)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, ret, zsel, zpr;
+
+    ret = -1;
+    raddr = -1;
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        if (ppcemb_tlb_check(env, tlb, &raddr, address,
+                             env->spr[SPR_40x_PID], 0, i) < 0)
+            continue;
+        zsel = (tlb->attr >> 4) & 0xF;
+        zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
+#if defined (DEBUG_SOFTWARE_TLB)
+        if (loglevel != 0) {
+            fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
+                    __func__, i, zsel, zpr, rw, tlb->attr);
+        }
+#endif
+        if (access_type == ACCESS_CODE) {
+            /* Check execute enable bit */
+            switch (zpr) {
+            case 0x2:
+                if (msr_pr)
+                    goto check_exec_perm;
+                goto exec_granted;
+            case 0x0:
+                if (msr_pr) {
+                    ctx->prot = 0;
+                    ret = -3;
+                    break;
+                }
+                /* No break here */
+            case 0x1:
+            check_exec_perm:
+                /* Check from TLB entry */
+                if (!(tlb->prot & PAGE_EXEC)) {
+                    ret = -3;
+                } else {
+                    if (tlb->prot & PAGE_WRITE) {
+                        ctx->prot = PAGE_READ | PAGE_WRITE;
+                    } else {
+                        ctx->prot = PAGE_READ;
+                    }
+                    ret = 0;
+                }
+                break;
+            case 0x3:
+            exec_granted:
+                /* All accesses granted */
+                ctx->prot = PAGE_READ | PAGE_WRITE;
+                ret = 0;
+                break;
+            }
+        } else {
+            switch (zpr) {
+            case 0x2:
+                if (msr_pr)
+                    goto check_rw_perm;
+                goto rw_granted;
+            case 0x0:
+                if (msr_pr) {
+                    ctx->prot = 0;
+                    ret = -2;
+                    break;
+                }
+                /* No break here */
+            case 0x1:
+            check_rw_perm:
+                /* Check from TLB entry */
+                /* Check write protection bit */
+                if (tlb->prot & PAGE_WRITE) {
+                    ctx->prot = PAGE_READ | PAGE_WRITE;
+                    ret = 0;
+                } else {
+                    ctx->prot = PAGE_READ;
+                    if (rw)
+                        ret = -2;
+                    else
+                        ret = 0;
+                }
+                break;
+            case 0x3:
+            rw_granted:
+                /* All accesses granted */
+                ctx->prot = PAGE_READ | PAGE_WRITE;
+                ret = 0;
+                break;
+            }
+        }
+        if (ret >= 0) {
+            ctx->raddr = raddr;
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (loglevel != 0) {
+                fprintf(logfile, "%s: access granted " ADDRX " => " REGX
+                        " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+                        ret);
+            }
+#endif
+            return 0;
+        }
+    }
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: access refused " ADDRX " => " REGX
+                " %d %d\n", __func__, address, raddr, ctx->prot,
+                ret);
+    }
+#endif
+
+    return ret;
+}
+
+void store_40x_sler (CPUPPCState *env, uint32_t val)
+{
+    /* XXX: TO BE FIXED */
+    if (val != 0x00000000) {
+        cpu_abort(env, "Little-endian regions are not supported by now\n");
+    }
+    env->spr[SPR_405_SLER] = val;
+}
+
+int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
+                                   target_ulong address, int rw,
+                                   int access_type)
+{
+    ppcemb_tlb_t *tlb;
+    target_phys_addr_t raddr;
+    int i, prot, ret;
+
+    ret = -1;
+    raddr = -1;
+    for (i = 0; i < env->nb_tlb; i++) {
+        tlb = &env->tlb[i].tlbe;
+        if (ppcemb_tlb_check(env, tlb, &raddr, address,
+                             env->spr[SPR_BOOKE_PID], 1, i) < 0)
+            continue;
+        if (msr_pr)
+            prot = tlb->prot & 0xF;
+        else
+            prot = (tlb->prot >> 4) & 0xF;
+        /* Check the address space */
+        if (access_type == ACCESS_CODE) {
+            if (msr_is != (tlb->attr & 1))
+                continue;
+            ctx->prot = prot;
+            if (prot & PAGE_EXEC) {
+                ret = 0;
+                break;
+            }
+            ret = -3;
+        } else {
+            if (msr_ds != (tlb->attr & 1))
+                continue;
+            ctx->prot = prot;
+            if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
+                ret = 0;
+                break;
+            }
+            ret = -2;
+        }
+    }
+    if (ret >= 0)
+        ctx->raddr = raddr;
+
+    return ret;
+}
+
+static int check_physical (CPUState *env, mmu_ctx_t *ctx,
+                           target_ulong eaddr, int rw)
+{
+    int in_plb, ret;
+
+    ctx->raddr = eaddr;
+    ctx->prot = PAGE_READ;
+    ret = 0;
+    switch (env->mmu_model) {
+    case POWERPC_MMU_32B:
+    case POWERPC_MMU_SOFT_6xx:
+    case POWERPC_MMU_SOFT_74xx:
+    case POWERPC_MMU_601:
+    case POWERPC_MMU_SOFT_4xx:
+    case POWERPC_MMU_REAL_4xx:
+    case POWERPC_MMU_BOOKE:
+        ctx->prot |= PAGE_WRITE;
+        break;
+#if defined(TARGET_PPC64)
+    case POWERPC_MMU_64B:
+    case POWERPC_MMU_64BRIDGE:
+        /* Real address are 60 bits long */
+        ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
+        ctx->prot |= PAGE_WRITE;
+        break;
+#endif
+    case POWERPC_MMU_SOFT_4xx_Z:
+        if (unlikely(msr_pe != 0)) {
+            /* 403 family add some particular protections,
+             * using PBL/PBU registers for accesses with no translation.
+             */
+            in_plb =
+                /* Check PLB validity */
+                (env->pb[0] < env->pb[1] &&
+                 /* and address in plb area */
+                 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
+                (env->pb[2] < env->pb[3] &&
+                 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
+            if (in_plb ^ msr_px) {
+                /* Access in protected area */
+                if (rw == 1) {
+                    /* Access is not allowed */
+                    ret = -2;
+                }
+            } else {
+                /* Read-write access is allowed */
+                ctx->prot |= PAGE_WRITE;
+            }
+        }
+        break;
+    case POWERPC_MMU_BOOKE_FSL:
+        /* XXX: TODO */
+        cpu_abort(env, "BookE FSL MMU model not implemented\n");
+        break;
+    default:
+        cpu_abort(env, "Unknown or invalid MMU model\n");
         return -1;
-    return phys_addr;
+    }
+
+    return ret;
+}
+
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
+                          int rw, int access_type, int check_BATs)
+{
+    int ret;
+#if 0
+    if (loglevel != 0) {
+        fprintf(logfile, "%s\n", __func__);
+    }
+#endif
+    if ((access_type == ACCESS_CODE && msr_ir == 0) ||
+        (access_type != ACCESS_CODE && msr_dr == 0)) {
+        /* No address translation */
+        ret = check_physical(env, ctx, eaddr, rw);
+    } else {
+        ret = -1;
+        switch (env->mmu_model) {
+        case POWERPC_MMU_32B:
+        case POWERPC_MMU_SOFT_6xx:
+        case POWERPC_MMU_SOFT_74xx:
+            /* Try to find a BAT */
+            if (check_BATs)
+                ret = get_bat(env, ctx, eaddr, rw, access_type);
+            /* No break here */
+#if defined(TARGET_PPC64)
+        case POWERPC_MMU_64B:
+        case POWERPC_MMU_64BRIDGE:
+#endif
+            if (ret < 0) {
+                /* We didn't match any BAT entry or don't have BATs */
+                ret = get_segment(env, ctx, eaddr, rw, access_type);
+            }
+            break;
+        case POWERPC_MMU_SOFT_4xx:
+        case POWERPC_MMU_SOFT_4xx_Z:
+            ret = mmu40x_get_physical_address(env, ctx, eaddr,
+                                              rw, access_type);
+            break;
+        case POWERPC_MMU_601:
+            /* XXX: TODO */
+            cpu_abort(env, "601 MMU model not implemented\n");
+            return -1;
+        case POWERPC_MMU_BOOKE:
+            ret = mmubooke_get_physical_address(env, ctx, eaddr,
+                                                rw, access_type);
+            break;
+        case POWERPC_MMU_BOOKE_FSL:
+            /* XXX: TODO */
+            cpu_abort(env, "BookE FSL MMU model not implemented\n");
+            return -1;
+        case POWERPC_MMU_REAL_4xx:
+            cpu_abort(env, "PowerPC 401 does not do any translation\n");
+            return -1;
+        default:
+            cpu_abort(env, "Unknown or invalid MMU model\n");
+            return -1;
+        }
+    }
+#if 0
+    if (loglevel != 0) {
+        fprintf(logfile, "%s address " ADDRX " => %d " PADDRX "\n",
+                __func__, eaddr, ret, ctx->raddr);
+    }
+#endif
+
+    return ret;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+{
+    mmu_ctx_t ctx;
+
+    if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0))
+        return -1;
+
+    return ctx.raddr & TARGET_PAGE_MASK;
 }
 
 /* Perform address translation */
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                               int is_user, int is_softmmu)
 {
-    uint32_t physical;
-    int prot;
+    mmu_ctx_t ctx;
     int exception = 0, error_code = 0;
     int access_type;
     int ret = 0;
@@ -444,35 +1242,78 @@
         access_type = ACCESS_INT;
         //        access_type = env->access_type;
     }
-    if (env->user_mode_only) {
-        /* user mode only emulation */
-        ret = -2;
-        goto do_fault;
-    }
-    ret = get_physical_address(env, &physical, &prot,
-                               address, rw, access_type);
+    ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
     if (ret == 0) {
-	ret = tlb_set_page(env, address & ~0xFFF, physical, prot,
-			   is_user, is_softmmu);
+        ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
+                           ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+                           is_user, is_softmmu);
     } else if (ret < 0) {
-    do_fault:
 #if defined (DEBUG_MMU)
-	if (loglevel > 0)
-	    cpu_dump_state(env, logfile, fprintf, 0);
+        if (loglevel != 0)
+            cpu_dump_state(env, logfile, fprintf, 0);
 #endif
         if (access_type == ACCESS_CODE) {
-            exception = EXCP_ISI;
+            exception = POWERPC_EXCP_ISI;
             switch (ret) {
             case -1:
-                /* No matches in page tables */
-                error_code = 0x40000000;
+                /* No matches in page tables or TLB */
+                switch (env->mmu_model) {
+                case POWERPC_MMU_SOFT_6xx:
+                    exception = POWERPC_EXCP_IFTLB;
+                    env->spr[SPR_IMISS] = address;
+                    env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
+                    error_code = 1 << 18;
+                    goto tlb_miss;
+                case POWERPC_MMU_SOFT_74xx:
+                    exception = POWERPC_EXCP_IFTLB;
+                    goto tlb_miss_74xx;
+                case POWERPC_MMU_SOFT_4xx:
+                case POWERPC_MMU_SOFT_4xx_Z:
+                    exception = POWERPC_EXCP_ITLB;
+                    error_code = 0;
+                    env->spr[SPR_40x_DEAR] = address;
+                    env->spr[SPR_40x_ESR] = 0x00000000;
+                    break;
+                case POWERPC_MMU_32B:
+                    error_code = 0x40000000;
+                    break;
+#if defined(TARGET_PPC64)
+                case POWERPC_MMU_64B:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case POWERPC_MMU_64BRIDGE:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+#endif
+                case POWERPC_MMU_601:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case POWERPC_MMU_BOOKE:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case POWERPC_MMU_BOOKE_FSL:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case POWERPC_MMU_REAL_4xx:
+                    cpu_abort(env, "PowerPC 401 should never raise any MMU "
+                              "exceptions\n");
+                    return -1;
+                default:
+                    cpu_abort(env, "Unknown or invalid MMU model\n");
+                    return -1;
+                }
                 break;
             case -2:
                 /* Access rights violation */
                 error_code = 0x08000000;
                 break;
             case -3:
-		/* No execute protection violation */
+                /* No execute protection violation */
                 error_code = 0x10000000;
                 break;
             case -4:
@@ -480,18 +1321,92 @@
                 /* No code fetch is allowed in direct-store areas */
                 error_code = 0x10000000;
                 break;
+#if defined(TARGET_PPC64)
             case -5:
                 /* No match in segment table */
-                exception = EXCP_ISEG;
+                exception = POWERPC_EXCP_ISEG;
                 error_code = 0;
                 break;
+#endif
             }
         } else {
-            exception = EXCP_DSI;
+            exception = POWERPC_EXCP_DSI;
             switch (ret) {
             case -1:
-                /* No matches in page tables */
-                error_code = 0x40000000;
+                /* No matches in page tables or TLB */
+                switch (env->mmu_model) {
+                case POWERPC_MMU_SOFT_6xx:
+                    if (rw == 1) {
+                        exception = POWERPC_EXCP_DSTLB;
+                        error_code = 1 << 16;
+                    } else {
+                        exception = POWERPC_EXCP_DLTLB;
+                        error_code = 0;
+                    }
+                    env->spr[SPR_DMISS] = address;
+                    env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
+                tlb_miss:
+                    error_code |= ctx.key << 19;
+                    env->spr[SPR_HASH1] = ctx.pg_addr[0];
+                    env->spr[SPR_HASH2] = ctx.pg_addr[1];
+                    /* Do not alter DAR nor DSISR */
+                    goto out;
+                case POWERPC_MMU_SOFT_74xx:
+                    if (rw == 1) {
+                        exception = POWERPC_EXCP_DSTLB;
+                    } else {
+                        exception = POWERPC_EXCP_DLTLB;
+                    }
+                tlb_miss_74xx:
+                    /* Implement LRU algorithm */
+                    env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
+                        ((env->last_way + 1) & (env->nb_ways - 1));
+                    env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
+                    error_code = ctx.key << 19;
+                    break;
+                case POWERPC_MMU_SOFT_4xx:
+                case POWERPC_MMU_SOFT_4xx_Z:
+                    exception = POWERPC_EXCP_DTLB;
+                    error_code = 0;
+                    env->spr[SPR_40x_DEAR] = address;
+                    if (rw)
+                        env->spr[SPR_40x_ESR] = 0x00800000;
+                    else
+                        env->spr[SPR_40x_ESR] = 0x00000000;
+                    break;
+                case POWERPC_MMU_32B:
+                    error_code = 0x40000000;
+                    break;
+#if defined(TARGET_PPC64)
+                case POWERPC_MMU_64B:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case POWERPC_MMU_64BRIDGE:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+#endif
+                case POWERPC_MMU_601:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case POWERPC_MMU_BOOKE:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case POWERPC_MMU_BOOKE_FSL:
+                    /* XXX: TODO */
+                    cpu_abort(env, "MMU model not implemented\n");
+                    return -1;
+                case POWERPC_MMU_REAL_4xx:
+                    cpu_abort(env, "PowerPC 401 should never raise any MMU "
+                              "exceptions\n");
+                    return -1;
+                default:
+                    cpu_abort(env, "Unknown or invalid MMU model\n");
+                    return -1;
+                }
                 break;
             case -2:
                 /* Access rights violation */
@@ -502,8 +1417,8 @@
                 switch (access_type) {
                 case ACCESS_FLOAT:
                     /* Floating point load/store */
-                    exception = EXCP_ALIGN;
-                    error_code = EXCP_ALIGN_FP;
+                    exception = POWERPC_EXCP_ALIGN;
+                    error_code = POWERPC_EXCP_ALIGN_FP;
                     break;
                 case ACCESS_RES:
                     /* lwarx, ldarx or srwcx. */
@@ -514,24 +1429,27 @@
                     error_code = 0x04100000;
                     break;
                 default:
-		    printf("DSI: invalid exception (%d)\n", ret);
-                    exception = EXCP_PROGRAM;
-                    error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
+                    printf("DSI: invalid exception (%d)\n", ret);
+                    exception = POWERPC_EXCP_PROGRAM;
+                    error_code = POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
                     break;
                 }
                 break;
+#if defined(TARGET_PPC64)
             case -5:
                 /* No match in segment table */
-                exception = EXCP_DSEG;
+                exception = POWERPC_EXCP_DSEG;
                 error_code = 0;
                 break;
+#endif
             }
-            if (exception == EXCP_DSI && rw == 1)
+            if (exception == POWERPC_EXCP_DSI && rw == 1)
                 error_code |= 0x02000000;
-	    /* Store fault address */
-	    env->spr[SPR_DAR] = address;
+            /* Store fault address */
+            env->spr[SPR_DAR] = address;
             env->spr[SPR_DSISR] = error_code;
         }
+    out:
 #if 0
         printf("%s: set exception to %d %02x\n",
                __func__, exception, error_code);
@@ -540,9 +1458,9 @@
         env->error_code = error_code;
         ret = 1;
     }
+
     return ret;
 }
-#endif
 
 /*****************************************************************************/
 /* BATs management */
@@ -551,11 +1469,14 @@
                                       target_ulong BATu, target_ulong mask)
 {
     target_ulong base, end, page;
+
     base = BATu & ~0x0001FFFF;
     end = base + mask + 0x00020000;
 #if defined (DEBUG_BATS)
-    if (loglevel != 0)
-        fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", base, end, mask);
+    if (loglevel != 0) {
+        fprintf(logfile, "Flush BAT from " ADDRX " to " ADDRX " (" ADDRX ")\n",
+                base, end, mask);
+    }
 #endif
     for (page = base; page != end; page += TARGET_PAGE_SIZE)
         tlb_flush_page(env, page);
@@ -571,9 +1492,8 @@
 {
 #if defined (DEBUG_BATS)
     if (loglevel != 0) {
-        fprintf(logfile, "Set %cBAT%d%c to 0x%08lx (0x%08lx)\n",
-                ID, nr, ul == 0 ? 'u' : 'l', (unsigned long)value,
-                (unsigned long)env->nip);
+        fprintf(logfile, "Set %cBAT%d%c to 0x" ADDRX " (0x" ADDRX ")\n",
+                ID, nr, ul == 0 ? 'u' : 'l', value, env->nip);
     }
 #endif
 }
@@ -608,8 +1528,7 @@
             (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
 #if !defined(FLUSH_ALL_TLBS)
         do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#endif
-#if defined(FLUSH_ALL_TLBS)
+#else
         tlb_flush(env, 1);
 #endif
     }
@@ -663,23 +1582,141 @@
     env->DBAT[1][nr] = value;
 }
 
-static inline void invalidate_all_tlbs (CPUPPCState *env)
+
+/*****************************************************************************/
+/* TLB management */
+void ppc_tlb_invalidate_all (CPUPPCState *env)
 {
-    /* XXX: this needs to be completed for sotware driven TLB support */
+    switch (env->mmu_model) {
+    case POWERPC_MMU_SOFT_6xx:
+    case POWERPC_MMU_SOFT_74xx:
+        ppc6xx_tlb_invalidate_all(env);
+        break;
+    case POWERPC_MMU_SOFT_4xx:
+    case POWERPC_MMU_SOFT_4xx_Z:
+        ppc4xx_tlb_invalidate_all(env);
+        break;
+    case POWERPC_MMU_REAL_4xx:
+        cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+        break;
+    case POWERPC_MMU_BOOKE:
+        /* XXX: TODO */
+        cpu_abort(env, "MMU model not implemented\n");
+        break;
+    case POWERPC_MMU_BOOKE_FSL:
+        /* XXX: TODO */
+        cpu_abort(env, "MMU model not implemented\n");
+        break;
+    case POWERPC_MMU_601:
+        /* XXX: TODO */
+        cpu_abort(env, "MMU model not implemented\n");
+        break;
+    case POWERPC_MMU_32B:
+    case POWERPC_MMU_64B:
+    case POWERPC_MMU_64BRIDGE:
+        tlb_flush(env, 1);
+        break;
+    }
+}
+
+void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
+{
+#if !defined(FLUSH_ALL_TLBS)
+    addr &= TARGET_PAGE_MASK;
+    switch (env->mmu_model) {
+    case POWERPC_MMU_SOFT_6xx:
+    case POWERPC_MMU_SOFT_74xx:
+        ppc6xx_tlb_invalidate_virt(env, addr, 0);
+        if (env->id_tlbs == 1)
+            ppc6xx_tlb_invalidate_virt(env, addr, 1);
+        break;
+    case POWERPC_MMU_SOFT_4xx:
+    case POWERPC_MMU_SOFT_4xx_Z:
+        ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
+        break;
+    case POWERPC_MMU_REAL_4xx:
+        cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
+        break;
+    case POWERPC_MMU_BOOKE:
+        /* XXX: TODO */
+        cpu_abort(env, "MMU model not implemented\n");
+        break;
+    case POWERPC_MMU_BOOKE_FSL:
+        /* XXX: TODO */
+        cpu_abort(env, "MMU model not implemented\n");
+        break;
+    case POWERPC_MMU_601:
+        /* XXX: TODO */
+        cpu_abort(env, "MMU model not implemented\n");
+        break;
+    case POWERPC_MMU_32B:
+        /* tlbie invalidate TLBs for all segments */
+        addr &= ~((target_ulong)-1 << 28);
+        /* XXX: this case should be optimized,
+         * giving a mask to tlb_flush_page
+         */
+        tlb_flush_page(env, addr | (0x0 << 28));
+        tlb_flush_page(env, addr | (0x1 << 28));
+        tlb_flush_page(env, addr | (0x2 << 28));
+        tlb_flush_page(env, addr | (0x3 << 28));
+        tlb_flush_page(env, addr | (0x4 << 28));
+        tlb_flush_page(env, addr | (0x5 << 28));
+        tlb_flush_page(env, addr | (0x6 << 28));
+        tlb_flush_page(env, addr | (0x7 << 28));
+        tlb_flush_page(env, addr | (0x8 << 28));
+        tlb_flush_page(env, addr | (0x9 << 28));
+        tlb_flush_page(env, addr | (0xA << 28));
+        tlb_flush_page(env, addr | (0xB << 28));
+        tlb_flush_page(env, addr | (0xC << 28));
+        tlb_flush_page(env, addr | (0xD << 28));
+        tlb_flush_page(env, addr | (0xE << 28));
+        tlb_flush_page(env, addr | (0xF << 28));
+        break;
+    case POWERPC_MMU_64B:
+    case POWERPC_MMU_64BRIDGE:
+        /* tlbie invalidate TLBs for all segments */
+        /* XXX: given the fact that there are too many segments to invalidate,
+         *      we just invalidate all TLBs
+         */
+        tlb_flush(env, 1);
+        break;
+    }
+#else
+    ppc_tlb_invalidate_all(env);
+#endif
+}
+
+#if defined(TARGET_PPC64)
+void ppc_slb_invalidate_all (CPUPPCState *env)
+{
+    /* XXX: TODO */
     tlb_flush(env, 1);
 }
 
+void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
+{
+    /* XXX: TODO */
+    tlb_flush(env, 1);
+}
+#endif
+
+
 /*****************************************************************************/
 /* Special registers manipulation */
-target_ulong do_load_nip (CPUPPCState *env)
+#if defined(TARGET_PPC64)
+target_ulong ppc_load_asr (CPUPPCState *env)
 {
-    return env->nip;
+    return env->asr;
 }
 
-void do_store_nip (CPUPPCState *env, target_ulong value)
+void ppc_store_asr (CPUPPCState *env, target_ulong value)
 {
-    env->nip = value;
+    if (env->asr != value) {
+        env->asr = value;
+        tlb_flush(env, 1);
+    }
 }
+#endif
 
 target_ulong do_load_sdr1 (CPUPPCState *env)
 {
@@ -690,12 +1727,12 @@
 {
 #if defined (DEBUG_MMU)
     if (loglevel != 0) {
-        fprintf(logfile, "%s: 0x%08lx\n", __func__, (unsigned long)value);
+        fprintf(logfile, "%s: 0x" ADDRX "\n", __func__, value);
     }
 #endif
     if (env->sdr1 != value) {
         env->sdr1 = value;
-        invalidate_all_tlbs(env);
+        tlb_flush(env, 1);
     }
 }
 
@@ -708,8 +1745,8 @@
 {
 #if defined (DEBUG_MMU)
     if (loglevel != 0) {
-        fprintf(logfile, "%s: reg=%d 0x%08lx %08lx\n",
-                __func__, srnum, (unsigned long)value, env->sr[srnum]);
+        fprintf(logfile, "%s: reg=%d 0x" ADDRX " " ADDRX "\n",
+                __func__, srnum, value, env->sr[srnum]);
     }
 #endif
     if (env->sr[srnum] != value) {
@@ -724,34 +1761,13 @@
                 tlb_flush_page(env, page);
         }
 #else
-        invalidate_all_tlbs(env);
+        tlb_flush(env, 1);
 #endif
     }
 }
+#endif /* !defined (CONFIG_USER_ONLY) */
 
-uint32_t do_load_cr (CPUPPCState *env)
-{
-    return (env->crf[0] << 28) |
-        (env->crf[1] << 24) |
-        (env->crf[2] << 20) |
-        (env->crf[3] << 16) |
-        (env->crf[4] << 12) |
-        (env->crf[5] << 8) |
-        (env->crf[6] << 4) |
-        (env->crf[7] << 0);
-}
-
-void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask)
-{
-    int i, sh;
-
-    for (i = 0, sh = 7; i < 8; i++, sh --) {
-        if (mask & (1 << sh))
-            env->crf[i] = (value >> (sh * 4)) & 0xFUL;
-    }
-}
-
-uint32_t do_load_xer (CPUPPCState *env)
+target_ulong ppc_load_xer (CPUPPCState *env)
 {
     return (xer_so << XER_SO) |
         (xer_ov << XER_OV) |
@@ -760,49 +1776,67 @@
         (xer_cmp << XER_CMP);
 }
 
-void do_store_xer (CPUPPCState *env, uint32_t value)
+void ppc_store_xer (CPUPPCState *env, target_ulong value)
 {
     xer_so = (value >> XER_SO) & 0x01;
     xer_ov = (value >> XER_OV) & 0x01;
     xer_ca = (value >> XER_CA) & 0x01;
     xer_cmp = (value >> XER_CMP) & 0xFF;
-    xer_bc = (value >> XER_BC) & 0x3F;
+    xer_bc = (value >> XER_BC) & 0x7F;
 }
 
+/* Swap temporary saved registers with GPRs */
+static inline void swap_gpr_tgpr (CPUPPCState *env)
+{
+    ppc_gpr_t tmp;
+
+    tmp = env->gpr[0];
+    env->gpr[0] = env->tgpr[0];
+    env->tgpr[0] = tmp;
+    tmp = env->gpr[1];
+    env->gpr[1] = env->tgpr[1];
+    env->tgpr[1] = tmp;
+    tmp = env->gpr[2];
+    env->gpr[2] = env->tgpr[2];
+    env->tgpr[2] = tmp;
+    tmp = env->gpr[3];
+    env->gpr[3] = env->tgpr[3];
+    env->tgpr[3] = tmp;
+}
+
+/* GDBstub can read and write MSR... */
 target_ulong do_load_msr (CPUPPCState *env)
 {
-    return (msr_vr << MSR_VR)  |
-        (msr_ap  << MSR_AP)  |
-        (msr_sa  << MSR_SA)  |
-        (msr_key << MSR_KEY) |
-        (msr_pow << MSR_POW) |
-        (msr_tlb << MSR_TLB) |
-        (msr_ile << MSR_ILE) |
-        (msr_ee << MSR_EE) |
-        (msr_pr << MSR_PR) |
-        (msr_fp << MSR_FP) |
-        (msr_me << MSR_ME) |
-        (msr_fe0 << MSR_FE0) |
-        (msr_se << MSR_SE) |
-        (msr_be << MSR_BE) |
-        (msr_fe1 << MSR_FE1) |
-        (msr_al  << MSR_AL)  |
-        (msr_ip << MSR_IP) |
-        (msr_ir << MSR_IR) |
-        (msr_dr << MSR_DR) |
-        (msr_pe  << MSR_PE)  |
-        (msr_px  << MSR_PX)  |
-        (msr_ri << MSR_RI) |
-        (msr_le << MSR_LE);
-}
-
-void do_compute_hflags (CPUPPCState *env)
-{
-    /* Compute current hflags */
-    env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
-        (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
-        (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | 
-        (msr_se << MSR_SE) | (msr_be << MSR_BE);
+    return
+#if defined (TARGET_PPC64)
+        ((target_ulong)msr_sf   << MSR_SF)   |
+        ((target_ulong)msr_isf  << MSR_ISF)  |
+        ((target_ulong)msr_hv   << MSR_HV)   |
+#endif
+        ((target_ulong)msr_ucle << MSR_UCLE) |
+        ((target_ulong)msr_vr   << MSR_VR)   | /* VR / SPE */
+        ((target_ulong)msr_ap   << MSR_AP)   |
+        ((target_ulong)msr_sa   << MSR_SA)   |
+        ((target_ulong)msr_key  << MSR_KEY)  |
+        ((target_ulong)msr_pow  << MSR_POW)  | /* POW / WE */
+        ((target_ulong)msr_tlb  << MSR_TLB)  | /* TLB / TGPE / CE */
+        ((target_ulong)msr_ile  << MSR_ILE)  |
+        ((target_ulong)msr_ee   << MSR_EE)   |
+        ((target_ulong)msr_pr   << MSR_PR)   |
+        ((target_ulong)msr_fp   << MSR_FP)   |
+        ((target_ulong)msr_me   << MSR_ME)   |
+        ((target_ulong)msr_fe0  << MSR_FE0)  |
+        ((target_ulong)msr_se   << MSR_SE)   | /* SE / DWE / UBLE */
+        ((target_ulong)msr_be   << MSR_BE)   | /* BE / DE */
+        ((target_ulong)msr_fe1  << MSR_FE1)  |
+        ((target_ulong)msr_al   << MSR_AL)   |
+        ((target_ulong)msr_ip   << MSR_IP)   |
+        ((target_ulong)msr_ir   << MSR_IR)   | /* IR / IS */
+        ((target_ulong)msr_dr   << MSR_DR)   | /* DR / DS */
+        ((target_ulong)msr_pe   << MSR_PE)   | /* PE / EP */
+        ((target_ulong)msr_px   << MSR_PX)   | /* PX / PMM */
+        ((target_ulong)msr_ri   << MSR_RI)   |
+        ((target_ulong)msr_le   << MSR_LE);
 }
 
 void do_store_msr (CPUPPCState *env, target_ulong value)
@@ -812,10 +1846,7 @@
     value &= env->msr_mask;
     if (((value >> MSR_IR) & 1) != msr_ir ||
         ((value >> MSR_DR) & 1) != msr_dr) {
-        /* Flush all tlb when changing translation mode
-         * When using software driven TLB, we may also need to reload
-         * all defined TLBs
-         */
+        /* Flush all tlb when changing translation mode */
         tlb_flush(env, 1);
         env->interrupt_request |= CPU_INTERRUPT_EXITTB;
     }
@@ -824,117 +1855,102 @@
         fprintf(logfile, "%s: T0 %08lx\n", __func__, value);
     }
 #endif
-    msr_vr  = (value >> MSR_VR)  & 1;
-    msr_ap  = (value >> MSR_AP)  & 1;
-    msr_sa  = (value >> MSR_SA)  & 1;
-    msr_key = (value >> MSR_KEY) & 1;
-    msr_pow = (value >> MSR_POW) & 1;
-    msr_tlb = (value >> MSR_TLB)  & 1;
-    msr_ile = (value >> MSR_ILE) & 1;
-    msr_ee  = (value >> MSR_EE)  & 1;
-    msr_pr  = (value >> MSR_PR)  & 1;
-    msr_fp  = (value >> MSR_FP)  & 1;
-    msr_me  = (value >> MSR_ME)  & 1;
-    msr_fe0 = (value >> MSR_FE0) & 1;
-    msr_se  = (value >> MSR_SE)  & 1;
-    msr_be  = (value >> MSR_BE)  & 1;
-    msr_fe1 = (value >> MSR_FE1) & 1;
-    msr_al  = (value >> MSR_AL)  & 1;
-    msr_ip  = (value >> MSR_IP)  & 1;
-    msr_ir  = (value >> MSR_IR)  & 1;
-    msr_dr  = (value >> MSR_DR)  & 1;
-    msr_pe  = (value >> MSR_PE)  & 1;
-    msr_px  = (value >> MSR_PX)  & 1;
-    msr_ri  = (value >> MSR_RI)  & 1;
-    msr_le  = (value >> MSR_LE)  & 1;
+    switch (env->excp_model) {
+    case POWERPC_EXCP_602:
+    case POWERPC_EXCP_603:
+    case POWERPC_EXCP_603E:
+    case POWERPC_EXCP_G2:
+        if (((value >> MSR_TGPR) & 1) != msr_tgpr) {
+            /* Swap temporary saved registers with GPRs */
+            swap_gpr_tgpr(env);
+        }
+        break;
+    default:
+        break;
+    }
+#if defined (TARGET_PPC64)
+    msr_sf   = (value >> MSR_SF)   & 1;
+    msr_isf  = (value >> MSR_ISF)  & 1;
+    msr_hv   = (value >> MSR_HV)   & 1;
+#endif
+    msr_ucle = (value >> MSR_UCLE) & 1;
+    msr_vr   = (value >> MSR_VR)   & 1; /* VR / SPE */
+    msr_ap   = (value >> MSR_AP)   & 1;
+    msr_sa   = (value >> MSR_SA)   & 1;
+    msr_key  = (value >> MSR_KEY)  & 1;
+    msr_pow  = (value >> MSR_POW)  & 1; /* POW / WE */
+    msr_tlb  = (value >> MSR_TLB)  & 1; /* TLB / TGPR / CE */
+    msr_ile  = (value >> MSR_ILE)  & 1;
+    msr_ee   = (value >> MSR_EE)   & 1;
+    msr_pr   = (value >> MSR_PR)   & 1;
+    msr_fp   = (value >> MSR_FP)   & 1;
+    msr_me   = (value >> MSR_ME)   & 1;
+    msr_fe0  = (value >> MSR_FE0)  & 1;
+    msr_se   = (value >> MSR_SE)   & 1; /* SE / DWE / UBLE */
+    msr_be   = (value >> MSR_BE)   & 1; /* BE / DE */
+    msr_fe1  = (value >> MSR_FE1)  & 1;
+    msr_al   = (value >> MSR_AL)   & 1;
+    msr_ip   = (value >> MSR_IP)   & 1;
+    msr_ir   = (value >> MSR_IR)   & 1; /* IR / IS */
+    msr_dr   = (value >> MSR_DR)   & 1; /* DR / DS */
+    msr_pe   = (value >> MSR_PE)   & 1; /* PE / EP */
+    msr_px   = (value >> MSR_PX)   & 1; /* PX / PMM */
+    msr_ri   = (value >> MSR_RI)   & 1;
+    msr_le   = (value >> MSR_LE)   & 1;
     do_compute_hflags(env);
 
     enter_pm = 0;
-    switch (PPC_EXCP(env)) {
-    case PPC_FLAGS_EXCP_7x0:
-	if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
+    switch (env->excp_model) {
+    case POWERPC_EXCP_603:
+    case POWERPC_EXCP_603E:
+    case POWERPC_EXCP_G2:
+        /* Don't handle SLEEP mode: we should disable all clocks...
+         * No dynamic power-management.
+         */
+        if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00C00000) != 0)
+            enter_pm = 1;
+        break;
+    case POWERPC_EXCP_604:
+        if (msr_pow == 1)
+            enter_pm = 1;
+        break;
+    case POWERPC_EXCP_7x0:
+        if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
             enter_pm = 1;
         break;
     default:
         break;
     }
     if (enter_pm) {
-        /* power save: exit cpu loop */
-        env->halted = 1;
-        env->exception_index = EXCP_HLT;
-        cpu_loop_exit();
+        if (likely(!env->halted)) {
+            /* power save: exit cpu loop */
+            env->halted = 1;
+            env->exception_index = EXCP_HLT;
+            cpu_loop_exit();
+        }
     }
 }
 
-float64 do_load_fpscr (CPUPPCState *env)
+#if defined(TARGET_PPC64)
+void ppc_store_msr_32 (CPUPPCState *env, uint32_t value)
 {
-    /* The 32 MSB of the target fpr are undefined.
-     * They'll be zero...
-     */
-    union {
-        float64 d;
-        struct {
-            uint32_t u[2];
-        } s;
-    } u;
-    int i;
-
-#ifdef WORDS_BIGENDIAN
-#define WORD0 0
-#define WORD1 1
-#else
-#define WORD0 1
-#define WORD1 0
+    do_store_msr(env,
+                 (do_load_msr(env) & ~0xFFFFFFFFULL) | (value & 0xFFFFFFFF));
+}
 #endif
-    u.s.u[WORD0] = 0;
-    u.s.u[WORD1] = 0;
-    for (i = 0; i < 8; i++)
-        u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
-    return u.d;
-}
 
-void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask)
+void do_compute_hflags (CPUPPCState *env)
 {
-    /*
-     * We use only the 32 LSB of the incoming fpr
-     */
-    union {
-        double d;
-        struct {
-            uint32_t u[2];
-        } s;
-    } u;
-    int i, rnd_type;
-
-    u.d = f;
-    if (mask & 0x80)
-        env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
-    for (i = 1; i < 7; i++) {
-        if (mask & (1 << (7 - i)))
-            env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
-    }
-    /* TODO: update FEX & VX */
-    /* Set rounding mode */
-    switch (env->fpscr[0] & 0x3) {
-    case 0:
-        /* Best approximation (round to nearest) */
-        rnd_type = float_round_nearest_even;
-        break;
-    case 1:
-        /* Smaller magnitude (round toward zero) */
-        rnd_type = float_round_to_zero;
-        break;
-    case 2:
-        /* Round toward +infinite */
-        rnd_type = float_round_up;
-        break;
-    default:
-    case 3:
-        /* Round toward -infinite */
-        rnd_type = float_round_down;
-        break;
-    }
-    set_float_rounding_mode(rnd_type, &env->fp_status);
+    /* Compute current hflags */
+    env->hflags = (msr_vr << MSR_VR) |
+        (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) |
+        (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) |
+        (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE);
+#if defined (TARGET_PPC64)
+    env->hflags |= msr_cm << MSR_CM;
+    env->hflags |= (uint64_t)msr_sf << MSR_SF;
+    env->hflags |= (uint64_t)msr_hv << MSR_HV;
+#endif
 }
 
 /*****************************************************************************/
@@ -942,128 +1958,152 @@
 #if defined (CONFIG_USER_ONLY)
 void do_interrupt (CPUState *env)
 {
-    env->exception_index = -1;
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
 }
-#else
-static void dump_syscall(CPUState *env)
+
+void ppc_hw_interrupt (CPUState *env)
 {
-    fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x r5=0x%08x r6=0x%08x nip=0x%08x\n",
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
+}
+#else /* defined (CONFIG_USER_ONLY) */
+static void dump_syscall (CPUState *env)
+{
+    fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX
+            " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n",
             env->gpr[0], env->gpr[3], env->gpr[4],
             env->gpr[5], env->gpr[6], env->nip);
 }
 
-void do_interrupt (CPUState *env)
+/* Note that this function should be greatly optimized
+ * when called with a constant excp, from ppc_hw_interrupt
+ */
+static always_inline void powerpc_excp (CPUState *env,
+                                        int excp_model, int excp)
 {
-    target_ulong msr, *srr_0, *srr_1, tmp;
-    int excp;
+    target_ulong msr, vector;
+    int srr0, srr1, asrr0, asrr1;
 
-    excp = env->exception_index;
-    msr = do_load_msr(env);
-    /* The default is to use SRR0 & SRR1 to save the exception context */
-    srr_0 = &env->spr[SPR_SRR0];
-    srr_1 = &env->spr[SPR_SRR1];
-#if defined (DEBUG_EXCEPTIONS)
-    if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) {
-        if (loglevel != 0) {
-            fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
-                    (unsigned long)env->nip, excp, env->error_code);
- 	    cpu_dump_state(env, logfile, fprintf, 0);
-        }
-    }
-#endif
     if (loglevel & CPU_LOG_INT) {
-        fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
-                (unsigned long)env->nip, excp, env->error_code);
+        fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n",
+                env->nip, excp, env->error_code);
     }
-    msr_pow = 0;
-    /* Generate informations in save/restore registers */
+    msr = do_load_msr(env);
+    srr0 = SPR_SRR0;
+    srr1 = SPR_SRR1;
+    asrr0 = -1;
+    asrr1 = -1;
+    msr &= ~((target_ulong)0x783F0000);
     switch (excp) {
-        /* Generic PowerPC exceptions */
-    case EXCP_RESET: /* 0x0100 */
-        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) {
-            if (msr_ip)
-                excp += 0xFFC00;
-            excp |= 0xFFC00000;
-        } else {
-            srr_0 = &env->spr[SPR_40x_SRR2];
-            srr_1 = &env->spr[SPR_40x_SRR3];
+    case POWERPC_EXCP_NONE:
+        /* Should never happen */
+        return;
+    case POWERPC_EXCP_CRITICAL:    /* Critical input                         */
+        msr_ri = 0; /* XXX: check this */
+        switch (excp_model) {
+        case POWERPC_EXCP_40x:
+            srr0 = SPR_40x_SRR2;
+            srr1 = SPR_40x_SRR3;
+            break;
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_CSRR0;
+            srr1 = SPR_BOOKE_CSRR1;
+            break;
+        case POWERPC_EXCP_G2:
+            break;
+        default:
+            goto excp_invalid;
         }
         goto store_next;
-    case EXCP_MACHINE_CHECK: /* 0x0200 */
+    case POWERPC_EXCP_MCHECK:    /* Machine check exception                  */
         if (msr_me == 0) {
-            cpu_abort(env, "Machine check exception while not allowed\n");
+            /* Machine check exception is not enabled */
+            /* XXX: we may just stop the processor here, to allow debugging */
+            excp = POWERPC_EXCP_RESET;
+            goto excp_reset;
         }
-        if (PPC_EXCP(env) == PPC_FLAGS_EXCP_40x) {
-            srr_0 = &env->spr[SPR_40x_SRR2];
-            srr_1 = &env->spr[SPR_40x_SRR3];
-        }
+        msr_ri = 0;
         msr_me = 0;
-        break;
-    case EXCP_DSI: /* 0x0300 */
-        /* Store exception cause */
-        /* data location address has been stored
-         * when the fault has been detected
-         */
-	msr &= ~0xFFFF0000;
+#if defined(TARGET_PPC64H)
+        msr_hv = 1;
+#endif
+        /* XXX: should also have something loaded in DAR / DSISR */
+        switch (excp_model) {
+        case POWERPC_EXCP_40x:
+            srr0 = SPR_40x_SRR2;
+            srr1 = SPR_40x_SRR3;
+            break;
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_MCSRR0;
+            srr1 = SPR_BOOKE_MCSRR1;
+            asrr0 = SPR_BOOKE_CSRR0;
+            asrr1 = SPR_BOOKE_CSRR1;
+            break;
+        default:
+            break;
+        }
+        goto store_next;
+    case POWERPC_EXCP_DSI:       /* Data storage exception                   */
 #if defined (DEBUG_EXCEPTIONS)
-	if (loglevel) {
-	    fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
-		    env->spr[SPR_DSISR], env->spr[SPR_DAR]);
-	} else {
-	    printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
-		   env->spr[SPR_DSISR], env->spr[SPR_DAR]);
-	}
+        if (loglevel != 0) {
+            fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX
+                    "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+        }
+#endif
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
 #endif
         goto store_next;
-    case EXCP_ISI: /* 0x0400 */
-        /* Store exception cause */
-	msr &= ~0xFFFF0000;
+    case POWERPC_EXCP_ISI:       /* Instruction storage exception            */
+#if defined (DEBUG_EXCEPTIONS)
+        if (loglevel != 0) {
+            fprintf(logfile, "ISI exception: msr=0x" ADDRX ", nip=0x" ADDRX
+                    "\n", msr, env->nip);
+        }
+#endif
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
         msr |= env->error_code;
-#if defined (DEBUG_EXCEPTIONS)
-	if (loglevel != 0) {
-	    fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
-		    msr, env->nip);
-	}
+        goto store_next;
+    case POWERPC_EXCP_EXTERNAL:  /* External input                           */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes0 == 1)
+            msr_hv = 1;
 #endif
         goto store_next;
-    case EXCP_EXTERNAL: /* 0x0500 */
-        if (msr_ee == 0) {
-#if defined (DEBUG_EXCEPTIONS)
-            if (loglevel > 0) {
-                fprintf(logfile, "Skipping hardware interrupt\n");
-            }
+    case POWERPC_EXCP_ALIGN:     /* Alignment exception                      */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
 #endif
-            /* Requeue it */
-            env->interrupt_request |= CPU_INTERRUPT_HARD;
-            return;
-        }
-        goto store_next;
-    case EXCP_ALIGN: /* 0x0600 */
-        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) {
-            /* Store exception cause */
-            /* Get rS/rD and rA from faulting opcode */
-            env->spr[SPR_DSISR] |=
-                (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
-            /* data location address has been stored
-             * when the fault has been detected
-             */
-        } else {
-            /* IO error exception on PowerPC 601 */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "601 IO error exception is not implemented yet !\n");
-        }
+        /* XXX: this is false */
+        /* Get rS/rD and rA from faulting opcode */
+        env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
         goto store_current;
-    case EXCP_PROGRAM: /* 0x0700 */
-        msr &= ~0xFFFF0000;
+    case POWERPC_EXCP_PROGRAM:   /* Program exception                        */
         switch (env->error_code & ~0xF) {
-        case EXCP_FP:
-            if (msr_fe0 == 0 && msr_fe1 == 0) {
+        case POWERPC_EXCP_FP:
+            if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
 #if defined (DEBUG_EXCEPTIONS)
-                printf("Ignore floating point exception\n");
+                if (loglevel != 0) {
+                    fprintf(logfile, "Ignore floating point exception\n");
+                }
 #endif
                 return;
-        }
+            }
+            msr_ri = 0;
+#if defined(TARGET_PPC64H)
+            if (lpes1 == 0)
+                msr_hv = 1;
+#endif
             msr |= 0x00100000;
             /* Set FX */
             env->fpscr[7] |= 0x8;
@@ -1071,38 +2111,59 @@
             if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
                 ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
                 env->fpscr[7] |= 0x4;
-        break;
-        case EXCP_INVAL:
-            //	    printf("Invalid instruction at 0x%08x\n", env->nip);
+            if (msr_fe0 != msr_fe1) {
+                msr |= 0x00010000;
+                goto store_current;
+            }
+            break;
+        case POWERPC_EXCP_INVAL:
+#if defined (DEBUG_EXCEPTIONS)
+            if (loglevel != 0) {
+                fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n",
+                        env->nip);
+            }
+#endif
+            msr_ri = 0;
+#if defined(TARGET_PPC64H)
+            if (lpes1 == 0)
+                msr_hv = 1;
+#endif
             msr |= 0x00080000;
-        break;
-        case EXCP_PRIV:
+            break;
+        case POWERPC_EXCP_PRIV:
+            msr_ri = 0;
+#if defined(TARGET_PPC64H)
+            if (lpes1 == 0)
+                msr_hv = 1;
+#endif
             msr |= 0x00040000;
-        break;
-        case EXCP_TRAP:
+            break;
+        case POWERPC_EXCP_TRAP:
+            msr_ri = 0;
+#if defined(TARGET_PPC64H)
+            if (lpes1 == 0)
+                msr_hv = 1;
+#endif
             msr |= 0x00020000;
             break;
         default:
             /* Should never occur */
-        break;
-    }
-        msr |= 0x00010000;
-        goto store_current;
-    case EXCP_NO_FP: /* 0x0800 */
-        msr &= ~0xFFFF0000;
-        goto store_current;
-    case EXCP_DECR:
-        if (msr_ee == 0) {
-#if 1
-            /* Requeue it */
-            env->interrupt_request |= CPU_INTERRUPT_TIMER;
-#endif
-            return;
+            cpu_abort(env, "Invalid program exception %d. Aborting\n",
+                      env->error_code);
+            break;
         }
         goto store_next;
-    case EXCP_SYSCALL: /* 0x0C00 */
+    case POWERPC_EXCP_FPU:       /* Floating-point unavailable exception     */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
+        goto store_current;
+    case POWERPC_EXCP_SYSCALL:   /* System call exception                    */
         /* NOTE: this is a temporary hack to support graphics OSI
            calls from the MOL driver */
+        /* XXX: To be removed */
         if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
             env->osi_call) {
             if (env->osi_call(env) != 0)
@@ -1111,330 +2172,387 @@
         if (loglevel & CPU_LOG_INT) {
             dump_syscall(env);
         }
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
+            msr_hv = 1;
+#endif
         goto store_next;
-    case EXCP_TRACE: /* 0x0D00 */
+    case POWERPC_EXCP_APU:       /* Auxiliary processor unavailable          */
+        msr_ri = 0;
+        goto store_current;
+    case POWERPC_EXCP_DECR:      /* Decrementer exception                    */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
         goto store_next;
-    case EXCP_PERF: /* 0x0F00 */
+    case POWERPC_EXCP_FIT:       /* Fixed-interval timer interrupt           */
+        /* FIT on 4xx */
+#if defined (DEBUG_EXCEPTIONS)
+        if (loglevel != 0)
+            fprintf(logfile, "FIT exception\n");
+#endif
+        msr_ri = 0; /* XXX: check this */
+        goto store_next;
+    case POWERPC_EXCP_WDT:       /* Watchdog timer interrupt                 */
+#if defined (DEBUG_EXCEPTIONS)
+        if (loglevel != 0)
+            fprintf(logfile, "WDT exception\n");
+#endif
+        switch (excp_model) {
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_CSRR0;
+            srr1 = SPR_BOOKE_CSRR1;
+            break;
+        default:
+            break;
+        }
+        msr_ri = 0; /* XXX: check this */
+        goto store_next;
+    case POWERPC_EXCP_DTLB:      /* Data TLB error                           */
+        msr_ri = 0; /* XXX: check this */
+        goto store_next;
+    case POWERPC_EXCP_ITLB:      /* Instruction TLB error                    */
+        msr_ri = 0; /* XXX: check this */
+        goto store_next;
+    case POWERPC_EXCP_DEBUG:     /* Debug interrupt                          */
+        switch (excp_model) {
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_DSRR0;
+            srr1 = SPR_BOOKE_DSRR1;
+            asrr0 = SPR_BOOKE_CSRR0;
+            asrr1 = SPR_BOOKE_CSRR1;
+            break;
+        default:
+            break;
+        }
+        /* XXX: TODO */
+        cpu_abort(env, "Debug exception is not implemented yet !\n");
+        goto store_next;
+#if defined(TARGET_PPCEMB)
+    case POWERPC_EXCP_SPEU:      /* SPE/embedded floating-point unavailable  */
+        msr_ri = 0; /* XXX: check this */
+        goto store_current;
+    case POWERPC_EXCP_EFPDI:     /* Embedded floating-point data interrupt   */
+        /* XXX: TODO */
+        cpu_abort(env, "Embedded floating point data exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_EFPRI:     /* Embedded floating-point round interrupt  */
+        /* XXX: TODO */
+        cpu_abort(env, "Embedded floating point round exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_EPERFM:    /* Embedded performance monitor interrupt   */
+        msr_ri = 0;
         /* XXX: TODO */
         cpu_abort(env,
                   "Performance counter exception is not implemented yet !\n");
         goto store_next;
-    /* 32 bits PowerPC specific exceptions */
-    case EXCP_FP_ASSIST: /* 0x0E00 */
+    case POWERPC_EXCP_DOORI:     /* Embedded doorbell interrupt              */
         /* XXX: TODO */
-        cpu_abort(env, "Floating point assist exception "
+        cpu_abort(env,
+                  "Embedded doorbell interrupt is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_DOORCI:    /* Embedded doorbell critical interrupt     */
+        switch (excp_model) {
+        case POWERPC_EXCP_BOOKE:
+            srr0 = SPR_BOOKE_CSRR0;
+            srr1 = SPR_BOOKE_CSRR1;
+            break;
+        default:
+            break;
+        }
+        /* XXX: TODO */
+        cpu_abort(env, "Embedded doorbell critical interrupt "
                   "is not implemented yet !\n");
         goto store_next;
-    /* 64 bits PowerPC exceptions */
-    case EXCP_DSEG: /* 0x0380 */
+#endif /* defined(TARGET_PPCEMB) */
+    case POWERPC_EXCP_RESET:     /* System reset exception                   */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        msr_hv = 1;
+#endif
+    excp_reset:
+        goto store_next;
+#if defined(TARGET_PPC64)
+    case POWERPC_EXCP_DSEG:      /* Data segment exception                   */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
         /* XXX: TODO */
         cpu_abort(env, "Data segment exception is not implemented yet !\n");
         goto store_next;
-    case EXCP_ISEG: /* 0x0480 */
+    case POWERPC_EXCP_ISEG:      /* Instruction segment exception            */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
         /* XXX: TODO */
         cpu_abort(env,
                   "Instruction segment exception is not implemented yet !\n");
         goto store_next;
-    case EXCP_HDECR: /* 0x0980 */
-        if (msr_ee == 0) {
-#if 1
-            /* Requeue it */
-            env->interrupt_request |= CPU_INTERRUPT_TIMER;
-#endif
-        return;
-        }
-        cpu_abort(env,
-                  "Hypervisor decrementer exception is not implemented yet !\n");
+#endif /* defined(TARGET_PPC64) */
+#if defined(TARGET_PPC64H)
+    case POWERPC_EXCP_HDECR:     /* Hypervisor decrementer exception         */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSSR1;
+        msr_hv = 1;
         goto store_next;
-    /* Implementation specific exceptions */
-    case 0x0A00:
-        if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) {
-            /* Critical interrupt on G2 */
-            /* XXX: TODO */
-            cpu_abort(env, "G2 critical interrupt is not implemented yet !\n");
-            goto store_next;
-        } else {
-            cpu_abort(env, "Invalid exception 0x0A00 !\n");
-        }
-        return;
-    case 0x0F20:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_40x:
-            /* APU unavailable on 405 */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "APU unavailable exception is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_74xx:
-            /* Altivec unavailable */
-            /* XXX: TODO */
-            cpu_abort(env, "Altivec unavailable exception "
-                      "is not implemented yet !\n");
-            goto store_next;
+#endif
+    case POWERPC_EXCP_TRACE:     /* Trace exception                          */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
+        goto store_next;
+#if defined(TARGET_PPC64H)
+    case POWERPC_EXCP_HDSI:      /* Hypervisor data storage exception        */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSSR1;
+        msr_hv = 1;
+        goto store_next;
+    case POWERPC_EXCP_HISI:      /* Hypervisor instruction storage exception */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSSR1;
+        msr_hv = 1;
+        /* XXX: TODO */
+        cpu_abort(env, "Hypervisor instruction storage exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_HDSEG:     /* Hypervisor data segment exception        */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSSR1;
+        msr_hv = 1;
+        goto store_next;
+    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
+        srr0 = SPR_HSRR0;
+        srr1 = SPR_HSSR1;
+        msr_hv = 1;
+        goto store_next;
+#endif /* defined(TARGET_PPC64H) */
+    case POWERPC_EXCP_VPU:       /* Vector unavailable exception             */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
+        goto store_current;
+    case POWERPC_EXCP_PIT:       /* Programmable interval timer interrupt    */
+#if defined (DEBUG_EXCEPTIONS)
+        if (loglevel != 0)
+            fprintf(logfile, "PIT exception\n");
+#endif
+        msr_ri = 0; /* XXX: check this */
+        goto store_next;
+    case POWERPC_EXCP_IO:        /* IO error exception                       */
+        /* XXX: TODO */
+        cpu_abort(env, "601 IO error exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_RUNM:      /* Run mode exception                       */
+        /* XXX: TODO */
+        cpu_abort(env, "601 run mode exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_EMUL:      /* Emulation trap exception                 */
+        /* XXX: TODO */
+        cpu_abort(env, "602 emulation trap exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_IFTLB:     /* Instruction fetch TLB error              */
+        msr_ri = 0; /* XXX: check this */
+#if defined(TARGET_PPC64H) /* XXX: check this */
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
+        switch (excp_model) {
+        case POWERPC_EXCP_602:
+        case POWERPC_EXCP_603:
+        case POWERPC_EXCP_603E:
+        case POWERPC_EXCP_G2:
+            goto tlb_miss_tgpr;
+        case POWERPC_EXCP_7x5:
+            goto tlb_miss;
+        case POWERPC_EXCP_74xx:
+            goto tlb_miss_74xx;
         default:
-            cpu_abort(env, "Invalid exception 0x0F20 !\n");
+            cpu_abort(env, "Invalid instruction TLB miss exception\n");
             break;
         }
-        return;
-    case 0x1000:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_40x:
-            /* PIT on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env, "40x PIT exception is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_602:
-        case PPC_FLAGS_EXCP_603:
-            /* ITLBMISS on 602/603 */
-            msr &= ~0xF00F0000;
+        break;
+    case POWERPC_EXCP_DLTLB:     /* Data load TLB miss                       */
+        msr_ri = 0; /* XXX: check this */
+#if defined(TARGET_PPC64H) /* XXX: check this */
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
+        switch (excp_model) {
+        case POWERPC_EXCP_602:
+        case POWERPC_EXCP_603:
+        case POWERPC_EXCP_603E:
+        case POWERPC_EXCP_G2:
+            goto tlb_miss_tgpr;
+        case POWERPC_EXCP_7x5:
+            goto tlb_miss;
+        case POWERPC_EXCP_74xx:
+            goto tlb_miss_74xx;
+        default:
+            cpu_abort(env, "Invalid data load TLB miss exception\n");
+            break;
+        }
+        break;
+    case POWERPC_EXCP_DSTLB:     /* Data store TLB miss                      */
+        msr_ri = 0; /* XXX: check this */
+#if defined(TARGET_PPC64H) /* XXX: check this */
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
+        switch (excp_model) {
+        case POWERPC_EXCP_602:
+        case POWERPC_EXCP_603:
+        case POWERPC_EXCP_603E:
+        case POWERPC_EXCP_G2:
+        tlb_miss_tgpr:
+            /* Swap temporary saved registers with GPRs */
+            swap_gpr_tgpr(env);
             msr_tgpr = 1;
-            goto store_gprs;
-        default:
-            cpu_abort(env, "Invalid exception 0x1000 !\n");
-            break;
-        }
-        return;
-    case 0x1010:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_40x:
-            /* FIT on 4xx */
-            cpu_abort(env, "40x FIT exception is not implemented yet !\n");
-            /* XXX: TODO */
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1010 !\n");
-            break;
-        }
-        return;
-    case 0x1020:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_40x:
-            /* Watchdog on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "40x watchdog exception is not implemented yet !\n");
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1020 !\n");
-            break;
-        }
-        return;
-    case 0x1100:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_40x:
-            /* DTLBMISS on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "40x DTLBMISS exception is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_602:
-        case PPC_FLAGS_EXCP_603:
-            /* DLTLBMISS on 602/603 */
-            msr &= ~0xF00F0000;
-            msr_tgpr = 1;
-            goto store_gprs;
-        default:
-            cpu_abort(env, "Invalid exception 0x1100 !\n");
-            break;
-        }
-        return;
-    case 0x1200:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_40x:
-            /* ITLBMISS on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "40x ITLBMISS exception is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_602:
-        case PPC_FLAGS_EXCP_603:
-            /* DSTLBMISS on 602/603 */
-            msr &= ~0xF00F0000;
-            msr_tgpr = 1;
-        store_gprs:
+            goto tlb_miss;
+        case POWERPC_EXCP_7x5:
+        tlb_miss:
 #if defined (DEBUG_SOFTWARE_TLB)
             if (loglevel != 0) {
-                fprintf(logfile, "6xx %sTLB miss: IM %08x DM %08x IC %08x "
-                        "DC %08x H1 %08x H2 %08x %08x\n",
-                        excp == 0x1000 ? "I" : excp == 0x1100 ? "DL" : "DS",
-                        env->spr[SPR_IMISS], env->spr[SPR_DMISS],
-                        env->spr[SPR_ICMP], env->spr[SPR_DCMP],
-                        env->spr[SPR_DHASH1], env->spr[SPR_DHASH2],
+                const unsigned char *es;
+                target_ulong *miss, *cmp;
+                int en;
+                if (excp == POWERPC_EXCP_IFTLB) {
+                    es = "I";
+                    en = 'I';
+                    miss = &env->spr[SPR_IMISS];
+                    cmp = &env->spr[SPR_ICMP];
+                } else {
+                    if (excp == POWERPC_EXCP_DLTLB)
+                        es = "DL";
+                    else
+                        es = "DS";
+                    en = 'D';
+                    miss = &env->spr[SPR_DMISS];
+                    cmp = &env->spr[SPR_DCMP];
+                }
+                fprintf(logfile, "6xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
+                        " H1 " ADDRX " H2 " ADDRX " %08x\n",
+                        es, en, *miss, en, *cmp,
+                        env->spr[SPR_HASH1], env->spr[SPR_HASH2],
                         env->error_code);
             }
 #endif
-            /* Swap temporary saved registers with GPRs */
-            tmp = env->gpr[0];
-            env->gpr[0] = env->tgpr[0];
-            env->tgpr[0] = tmp;
-            tmp = env->gpr[1];
-            env->gpr[1] = env->tgpr[1];
-            env->tgpr[1] = tmp;
-            tmp = env->gpr[2];
-            env->gpr[2] = env->tgpr[2];
-            env->tgpr[2] = tmp;
-            tmp = env->gpr[3];
-            env->gpr[3] = env->tgpr[3];
-            env->tgpr[3] = tmp;
             msr |= env->crf[0] << 28;
             msr |= env->error_code; /* key, D/I, S/L bits */
             /* Set way using a LRU mechanism */
-            msr |= (env->last_way ^ 1) << 17;
-            goto store_next;
+            msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+            break;
+        case POWERPC_EXCP_74xx:
+        tlb_miss_74xx:
+#if defined (DEBUG_SOFTWARE_TLB)
+            if (loglevel != 0) {
+                const unsigned char *es;
+                target_ulong *miss, *cmp;
+                int en;
+                if (excp == POWERPC_EXCP_IFTLB) {
+                    es = "I";
+                    en = 'I';
+                    miss = &env->spr[SPR_IMISS];
+                    cmp = &env->spr[SPR_ICMP];
+                } else {
+                    if (excp == POWERPC_EXCP_DLTLB)
+                        es = "DL";
+                    else
+                        es = "DS";
+                    en = 'D';
+                    miss = &env->spr[SPR_TLBMISS];
+                    cmp = &env->spr[SPR_PTEHI];
+                }
+                fprintf(logfile, "74xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
+                        " %08x\n",
+                        es, en, *miss, en, *cmp, env->error_code);
+            }
+#endif
+            msr |= env->error_code; /* key bit */
+            break;
         default:
-            cpu_abort(env, "Invalid exception 0x1200 !\n");
+            cpu_abort(env, "Invalid data store TLB miss exception\n");
             break;
         }
-        return;
-    case 0x1300:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_601:
-        case PPC_FLAGS_EXCP_602:
-        case PPC_FLAGS_EXCP_603:
-        case PPC_FLAGS_EXCP_604:
-        case PPC_FLAGS_EXCP_7x0:
-        case PPC_FLAGS_EXCP_7x5:
-            /* IABR on 6xx/7xx */
-            /* XXX: TODO */
-            cpu_abort(env, "IABR exception is not implemented yet !\n");
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1300 !\n");
-            break;
-        }
-        return;
-    case 0x1400:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_601:
-        case PPC_FLAGS_EXCP_602:
-        case PPC_FLAGS_EXCP_603:
-        case PPC_FLAGS_EXCP_604:
-        case PPC_FLAGS_EXCP_7x0:
-        case PPC_FLAGS_EXCP_7x5:
-            /* SMI on 6xx/7xx */
-            /* XXX: TODO */
-            cpu_abort(env, "SMI exception is not implemented yet !\n");
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1400 !\n");
-            break;
-        }
-        return;
-    case 0x1500:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_602:
-            /* Watchdog on 602 */
-            cpu_abort(env,
-                      "602 watchdog exception is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_970:
-            /* Soft patch exception on 970 */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "970 soft-patch exception is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_74xx:
-            /* VPU assist on 74xx */
-            /* XXX: TODO */
-            cpu_abort(env, "VPU assist exception is not implemented yet !\n");
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1500 !\n");
-            break;
-        }
-        return;
-    case 0x1600:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_602:
-            /* Emulation trap on 602 */
-            /* XXX: TODO */
-            cpu_abort(env, "602 emulation trap exception "
-                      "is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_970:
-            /* Maintenance exception on 970 */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "970 maintenance exception is not implemented yet !\n");
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1600 !\n");
-            break;
-        }
-        return;
-    case 0x1700:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_7x0:
-        case PPC_FLAGS_EXCP_7x5:
-            /* Thermal management interrupt on G3 */
-            /* XXX: TODO */
-            cpu_abort(env, "G3 thermal management exception "
-                      "is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_970:
-            /* VPU assist on 970 */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "970 VPU assist exception is not implemented yet !\n");
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1700 !\n");
-            break;
-        }
-        return;
-    case 0x1800:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_970:
-            /* Thermal exception on 970 */
-            /* XXX: TODO */
-            cpu_abort(env, "970 thermal management exception "
-                      "is not implemented yet !\n");
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1800 !\n");
-            break;
-        }
-        return;
-    case 0x2000:
-        switch (PPC_EXCP(env)) {
-        case PPC_FLAGS_EXCP_40x:
-            /* DEBUG on 4xx */
-            /* XXX: TODO */
-            cpu_abort(env, "40x debug exception is not implemented yet !\n");
-            goto store_next;
-        case PPC_FLAGS_EXCP_601:
-            /* Run mode exception on 601 */
-            /* XXX: TODO */
-            cpu_abort(env,
-                      "601 run mode exception is not implemented yet !\n");
-            goto store_next;
-        default:
-            cpu_abort(env, "Invalid exception 0x1800 !\n");
-            break;
-        }
-        return;
-    /* Other exceptions */
-    /* Qemu internal exceptions:
-     * we should never come here with those values: abort execution
-     */
+        goto store_next;
+    case POWERPC_EXCP_FPA:       /* Floating-point assist exception          */
+        /* XXX: TODO */
+        cpu_abort(env, "Floating point assist exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_IABR:      /* Instruction address breakpoint           */
+        /* XXX: TODO */
+        cpu_abort(env, "IABR exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_SMI:       /* System management interrupt              */
+        /* XXX: TODO */
+        cpu_abort(env, "SMI exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_THERM:     /* Thermal interrupt                        */
+        /* XXX: TODO */
+        cpu_abort(env, "Thermal management exception "
+                  "is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_PERFM:     /* Embedded performance monitor interrupt   */
+        msr_ri = 0;
+#if defined(TARGET_PPC64H)
+        if (lpes1 == 0)
+            msr_hv = 1;
+#endif
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "Performance counter exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_VPUA:      /* Vector assist exception                  */
+        /* XXX: TODO */
+        cpu_abort(env, "VPU assist exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_SOFTP:     /* Soft patch exception                     */
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "970 soft-patch exception is not implemented yet !\n");
+        goto store_next;
+    case POWERPC_EXCP_MAINT:     /* Maintenance exception                    */
+        /* XXX: TODO */
+        cpu_abort(env,
+                  "970 maintenance exception is not implemented yet !\n");
+        goto store_next;
     default:
-        cpu_abort(env, "Invalid exception: code %d (%04x)\n", excp, excp);
-        return;
+    excp_invalid:
+        cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
+        break;
     store_current:
         /* save current instruction location */
-        *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL;
+        env->spr[srr0] = env->nip - 4;
         break;
     store_next:
         /* save next instruction location */
-        *srr_0 = env->nip & 0xFFFFFFFFULL;
+        env->spr[srr0] = env->nip;
         break;
     }
-    /* Save msr */
-    *srr_1 = msr;
+    /* Save MSR */
+    env->spr[srr1] = msr;
+    /* If any alternate SRR register are defined, duplicate saved values */
+    if (asrr0 != -1)
+        env->spr[asrr0] = env->spr[srr0];
+    if (asrr1 != -1)
+        env->spr[asrr1] = env->spr[srr1];
     /* If we disactivated any translation, flush TLBs */
-    if (msr_ir || msr_dr) {
+    if (msr_ir || msr_dr)
         tlb_flush(env, 1);
-    }
     /* reload MSR with correct bits */
     msr_ee = 0;
     msr_pr = 0;
@@ -1445,12 +2563,253 @@
     msr_fe1 = 0;
     msr_ir = 0;
     msr_dr = 0;
-    msr_ri = 0;
+#if 0 /* Fix this: not on all targets */
+    msr_pmm = 0;
+#endif
     msr_le = msr_ile;
-    msr_sf = msr_isf;
     do_compute_hflags(env);
     /* Jump to handler */
-    env->nip = excp;
-    env->exception_index = EXCP_NONE;
+    vector = env->excp_vectors[excp];
+    if (vector == (target_ulong)-1) {
+        cpu_abort(env, "Raised an exception without defined vector %d\n",
+                  excp);
+    }
+    vector |= env->excp_prefix;
+#if defined(TARGET_PPC64)
+    if (excp_model == POWERPC_EXCP_BOOKE) {
+        msr_cm = msr_icm;
+        if (!msr_cm)
+            vector = (uint32_t)vector;
+    } else {
+        msr_sf = msr_isf;
+        if (!msr_sf)
+            vector = (uint32_t)vector;
+    }
+#endif
+    env->nip = vector;
+    /* Reset exception state */
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
+}
+
+void do_interrupt (CPUState *env)
+{
+    powerpc_excp(env, env->excp_model, env->exception_index);
+}
+
+void ppc_hw_interrupt (CPUPPCState *env)
+{
+#if 1
+    if (loglevel & CPU_LOG_INT) {
+        fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n",
+                __func__, env, env->pending_interrupts,
+                env->interrupt_request, msr_me, msr_ee);
+    }
+#endif
+    /* External reset */
+    if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
+        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
+        powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
+        return;
+    }
+    /* Machine check exception */
+    if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
+        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
+        powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
+        return;
+    }
+#if 0 /* TODO */
+    /* External debug exception */
+    if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
+        env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
+        powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
+        return;
+    }
+#endif
+#if defined(TARGET_PPC64H)
+    if ((msr_ee != 0 || msr_hv == 0 || msr_pr == 1) & hdice != 0) {
+        /* Hypervisor decrementer exception */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
+            return;
+        }
+    }
+#endif
+    if (msr_ce != 0) {
+        /* External critical interrupt */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
+            /* Taking a critical external interrupt does not clear the external
+             * critical interrupt status
+             */
+#if 0
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
+#endif
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
+            return;
+        }
+    }
+    if (msr_ee != 0) {
+        /* Watchdog timer on embedded PowerPC */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
+            return;
+        }
+#if defined(TARGET_PPCEMB)
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
+            return;
+        }
+#endif
+#if defined(TARGET_PPCEMB)
+        /* External interrupt */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
+            /* Taking an external interrupt does not clear the external
+             * interrupt status
+             */
+#if 0
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
+#endif
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
+            return;
+        }
+#endif
+        /* Fixed interval timer on embedded PowerPC */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
+            return;
+        }
+        /* Programmable interval timer on embedded PowerPC */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
+            return;
+        }
+        /* Decrementer exception */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
+            return;
+        }
+#if !defined(TARGET_PPCEMB)
+        /* External interrupt */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
+            /* Taking an external interrupt does not clear the external
+             * interrupt status
+             */
+#if 0
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
+#endif
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
+            return;
+        }
+#endif
+#if defined(TARGET_PPCEMB)
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
+            return;
+        }
+#endif
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
+            return;
+        }
+        /* Thermal interrupt */
+        if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
+            env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
+            powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
+            return;
+        }
+    }
 }
 #endif /* !CONFIG_USER_ONLY */
+
+void cpu_dump_EA (target_ulong EA)
+{
+    FILE *f;
+
+    if (logfile) {
+        f = logfile;
+    } else {
+        f = stdout;
+        return;
+    }
+    fprintf(f, "Memory access at address " ADDRX "\n", EA);
+}
+
+void cpu_dump_rfi (target_ulong RA, target_ulong msr)
+{
+    FILE *f;
+
+    if (logfile) {
+        f = logfile;
+    } else {
+        f = stdout;
+        return;
+    }
+    fprintf(f, "Return from exception at " ADDRX " with flags " ADDRX "\n",
+            RA, msr);
+}
+
+void cpu_ppc_reset (void *opaque)
+{
+    CPUPPCState *env;
+    int i;
+
+    env = opaque;
+    /* XXX: some of those flags initialisation values could depend
+     *      on the actual PowerPC implementation
+     */
+    for (i = 0; i < 63; i++)
+        env->msr[i] = 0;
+#if defined(TARGET_PPC64)
+    msr_hv = 0; /* Should be 1... */
+#endif
+    msr_ap = 0; /* TO BE CHECKED */
+    msr_sa = 0; /* TO BE CHECKED */
+    msr_ip = 0; /* TO BE CHECKED */
+#if defined (DO_SINGLE_STEP) && 0
+    /* Single step trace mode */
+    msr_se = 1;
+    msr_be = 1;
+#endif
+#if defined(CONFIG_USER_ONLY)
+    msr_fp = 1; /* Allow floating point exceptions */
+    msr_pr = 1;
+#else
+    env->nip = 0xFFFFFFFC;
+    ppc_tlb_invalidate_all(env);
+#endif
+    do_compute_hflags(env);
+    env->reserve = -1;
+    /* Be sure no exception or interrupt is pending */
+    env->pending_interrupts = 0;
+    env->exception_index = POWERPC_EXCP_NONE;
+    env->error_code = 0;
+    /* Flush all TLBs */
+    tlb_flush(env, 1);
+}
+
+CPUPPCState *cpu_ppc_init (void)
+{
+    CPUPPCState *env;
+
+    env = qemu_mallocz(sizeof(CPUPPCState));
+    if (!env)
+        return NULL;
+    cpu_exec_init(env);
+    cpu_ppc_reset(env);
+
+    return env;
+}
+
+void cpu_ppc_close (CPUPPCState *env)
+{
+    /* Should also remove all opcode tables... */
+    free(env);
+}
diff --git a/target-ppc/mfrom_table.c b/target-ppc/mfrom_table.c
new file mode 100644
index 0000000..6a1fa37
--- /dev/null
+++ b/target-ppc/mfrom_table.c
@@ -0,0 +1,79 @@
+static const uint8_t mfrom_ROM_table[602] =
+{
+     77,  77,  76,  76,  75,  75,  74,  74,
+     73,  73,  72,  72,  71,  71,  70,  70,
+     69,  69,  68,  68,  68,  67,  67,  66,
+     66,  65,  65,  64,  64,  64,  63,  63,
+     62,  62,  61,  61,  61,  60,  60,  59,
+     59,  58,  58,  58,  57,  57,  56,  56,
+     56,  55,  55,  54,  54,  54,  53,  53,
+     53,  52,  52,  51,  51,  51,  50,  50,
+     50,  49,  49,  49,  48,  48,  47,  47,
+     47,  46,  46,  46,  45,  45,  45,  44,
+     44,  44,  43,  43,  43,  42,  42,  42,
+     42,  41,  41,  41,  40,  40,  40,  39,
+     39,  39,  39,  38,  38,  38,  37,  37,
+     37,  37,  36,  36,  36,  35,  35,  35,
+     35,  34,  34,  34,  34,  33,  33,  33,
+     33,  32,  32,  32,  32,  31,  31,  31,
+     31,  30,  30,  30,  30,  29,  29,  29,
+     29,  28,  28,  28,  28,  28,  27,  27,
+     27,  27,  26,  26,  26,  26,  26,  25,
+     25,  25,  25,  25,  24,  24,  24,  24,
+     24,  23,  23,  23,  23,  23,  23,  22,
+     22,  22,  22,  22,  21,  21,  21,  21,
+     21,  21,  20,  20,  20,  20,  20,  20,
+     19,  19,  19,  19,  19,  19,  19,  18,
+     18,  18,  18,  18,  18,  17,  17,  17,
+     17,  17,  17,  17,  16,  16,  16,  16,
+     16,  16,  16,  16,  15,  15,  15,  15,
+     15,  15,  15,  15,  14,  14,  14,  14,
+     14,  14,  14,  14,  13,  13,  13,  13,
+     13,  13,  13,  13,  13,  12,  12,  12,
+     12,  12,  12,  12,  12,  12,  12,  11,
+     11,  11,  11,  11,  11,  11,  11,  11,
+     11,  11,  10,  10,  10,  10,  10,  10,
+     10,  10,  10,  10,  10,   9,   9,   9,
+      9,   9,   9,   9,   9,   9,   9,   9,
+      9,   9,   8,   8,   8,   8,   8,   8,
+      8,   8,   8,   8,   8,   8,   8,   8,
+      7,   7,   7,   7,   7,   7,   7,   7,
+      7,   7,   7,   7,   7,   7,   7,   7,
+      7,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   6,   6,   6,   6,
+      6,   6,   6,   6,   5,   5,   5,   5,
+      5,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,   5,   5,   5,   5,   5,
+      5,   5,   5,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   4,   4,
+      4,   4,   4,   4,   4,   4,   4,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   3,   3,   3,
+      3,   3,   3,   3,   3,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   2,   2,
+      2,   2,   2,   2,   2,   2,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   1,   1,   1,   1,   1,   1,   1,
+      1,   0,
+};
diff --git a/target-ppc/mfrom_table_gen.c b/target-ppc/mfrom_table_gen.c
new file mode 100644
index 0000000..4c06aa4
--- /dev/null
+++ b/target-ppc/mfrom_table_gen.c
@@ -0,0 +1,33 @@
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <math.h>
+
+int main (void)
+{
+    double d;
+    uint8_t n;
+    int i;
+
+    printf("static const uint8_t mfrom_ROM_table[602] =\n{\n    ");
+    for (i = 0; i < 602; i++) {
+        /* Extremly decomposed:
+         *                    -T0 / 256
+         * T0 = 256 * log10(10          + 1.0) + 0.5
+         */
+        d = -i;
+        d /= 256.0;
+        d = exp10(d);
+        d += 1.0;
+        d = log10(d);
+        d *= 256;
+        d += 0.5;
+        n = d;
+        printf("%3d, ", n);
+        if ((i & 7) == 7)
+            printf("\n    ");
+    }
+    printf("\n};\n");
+
+    return 0;
+}
diff --git a/target-ppc/op.c b/target-ppc/op.c
index ca1dbc5..822c267 100644
--- a/target-ppc/op.c
+++ b/target-ppc/op.c
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation micro-operations for qemu.
- * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -22,17 +22,7 @@
 
 #include "config.h"
 #include "exec.h"
-
-#define regs (env)
-#define Ts0 (int32_t)T0
-#define Ts1 (int32_t)T1
-#define Ts2 (int32_t)T2
-
-#define FT0 (env->ft0)
-#define FT1 (env->ft1)
-#define FT2 (env->ft2)
-
-#define PPC_OP(name) void glue(op_, name)(void)
+#include "op_helper.h"
 
 #define REG 0
 #include "op_template.h"
@@ -130,256 +120,386 @@
 #define REG 31
 #include "op_template.h"
 
+
+void OPPROTO op_print_mem_EA (void)
+{
+    do_print_mem_EA(T0);
+    RETURN();
+}
+
 /* PowerPC state maintenance operations */
 /* set_Rc0 */
-PPC_OP(set_Rc0)
+void OPPROTO op_set_Rc0 (void)
 {
-    uint32_t tmp;
-
-    if (Ts0 < 0) {
-        tmp = 0x08;
-    } else if (Ts0 > 0) {
-        tmp = 0x04;
-    } else {
-        tmp = 0x02;
-    }
-    tmp |= xer_ov;
-    env->crf[0] = tmp;
-    RETURN();
-}
-
-/* reset_Rc0 */
-PPC_OP(reset_Rc0)
-{
-    env->crf[0] = 0x02 | xer_ov;
-    RETURN();
-}
-
-/* set_Rc0_1 */
-PPC_OP(set_Rc0_1)
-{
-    env->crf[0] = 0x04 | xer_ov;
+    env->crf[0] = T0 | xer_so;
     RETURN();
 }
 
 /* Set Rc1 (for floating point arithmetic) */
-PPC_OP(set_Rc1)
+void OPPROTO op_set_Rc1 (void)
 {
-    env->crf[1] = regs->fpscr[7];
+    env->crf[1] = env->fpscr[7];
     RETURN();
 }
 
 /* Constants load */
-PPC_OP(set_T0)
+void OPPROTO op_reset_T0 (void)
 {
-    T0 = PARAM(1);
+    T0 = 0;
     RETURN();
 }
 
-PPC_OP(set_T1)
+void OPPROTO op_set_T0 (void)
 {
-    T1 = PARAM(1);
+    T0 = (uint32_t)PARAM1;
     RETURN();
 }
 
-PPC_OP(set_T2)
+#if defined(TARGET_PPC64)
+void OPPROTO op_set_T0_64 (void)
 {
-    T2 = PARAM(1);
+    T0 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_set_T1 (void)
+{
+    T1 = (uint32_t)PARAM1;
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_set_T1_64 (void)
+{
+    T1 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
+    RETURN();
+}
+#endif
+
+#if 0 // unused
+void OPPROTO op_set_T2 (void)
+{
+    T2 = PARAM1;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_move_T1_T0 (void)
+{
+    T1 = T0;
+    RETURN();
+}
+
+void OPPROTO op_move_T2_T0 (void)
+{
+    T2 = T0;
     RETURN();
 }
 
 /* Generate exceptions */
-PPC_OP(raise_exception_err)
+void OPPROTO op_raise_exception_err (void)
 {
-    do_raise_exception_err(PARAM(1), PARAM(2));
+    do_raise_exception_err(PARAM1, PARAM2);
 }
 
-PPC_OP(raise_exception)
+void OPPROTO op_update_nip (void)
 {
-    do_raise_exception(PARAM(1));
+    env->nip = (uint32_t)PARAM1;
+    RETURN();
 }
 
-PPC_OP(update_nip)
+#if defined(TARGET_PPC64)
+void OPPROTO op_update_nip_64 (void)
 {
-    env->nip = PARAM(1);
+    env->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
+    RETURN();
 }
+#endif
 
-PPC_OP(debug)
+void OPPROTO op_debug (void)
 {
     do_raise_exception(EXCP_DEBUG);
 }
 
-/* Segment registers load and store with immediate index */
-PPC_OP(load_srin)
-{
-    T0 = regs->sr[T1 >> 28];
-    RETURN();
-}
-
-PPC_OP(store_srin)
-{
-    do_store_sr(env, ((uint32_t)T1 >> 28), T0);
-    RETURN();
-}
-
-PPC_OP(load_sdr1)
-{
-    T0 = regs->sdr1;
-    RETURN();
-}
-
-PPC_OP(store_sdr1)
-{
-    do_store_sdr1(env, T0);
-    RETURN();
-}
-
-PPC_OP(exit_tb)
+void OPPROTO op_exit_tb (void)
 {
     EXIT_TB();
 }
 
 /* Load/store special registers */
-PPC_OP(load_cr)
+void OPPROTO op_load_cr (void)
 {
-    T0 = do_load_cr(env);
+    do_load_cr();
     RETURN();
 }
 
-PPC_OP(store_cr)
+void OPPROTO op_store_cr (void)
 {
-    do_store_cr(env, T0, PARAM(1));
+    do_store_cr(PARAM1);
     RETURN();
 }
 
-PPC_OP(load_xer_cr)
+void OPPROTO op_load_cro (void)
+{
+    T0 = env->crf[PARAM1];
+    RETURN();
+}
+
+void OPPROTO op_store_cro (void)
+{
+    env->crf[PARAM1] = T0;
+    RETURN();
+}
+
+void OPPROTO op_load_xer_cr (void)
 {
     T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1);
     RETURN();
 }
 
-PPC_OP(clear_xer_cr)
+void OPPROTO op_clear_xer_ov (void)
 {
     xer_so = 0;
     xer_ov = 0;
+    RETURN();
+}
+
+void OPPROTO op_clear_xer_ca (void)
+{
     xer_ca = 0;
     RETURN();
 }
 
-PPC_OP(load_xer_bc)
+void OPPROTO op_load_xer_bc (void)
 {
     T1 = xer_bc;
     RETURN();
 }
 
-PPC_OP(load_xer)
+void OPPROTO op_store_xer_bc (void)
 {
-    T0 = do_load_xer(env);
+    xer_bc = T0;
     RETURN();
 }
 
-PPC_OP(store_xer)
+void OPPROTO op_load_xer (void)
 {
-    do_store_xer(env, T0);
+    do_load_xer();
     RETURN();
 }
 
-PPC_OP(load_msr)
+void OPPROTO op_store_xer (void)
+{
+    do_store_xer();
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_store_pri (void)
+{
+    do_store_pri(PARAM1);
+    RETURN();
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+/* Segment registers load and store */
+void OPPROTO op_load_sr (void)
+{
+    T0 = env->sr[T1];
+    RETURN();
+}
+
+void OPPROTO op_store_sr (void)
+{
+    do_store_sr(env, T1, T0);
+    RETURN();
+}
+
+void OPPROTO op_load_sdr1 (void)
+{
+    T0 = env->sdr1;
+    RETURN();
+}
+
+void OPPROTO op_store_sdr1 (void)
+{
+    do_store_sdr1(env, T0);
+    RETURN();
+}
+
+#if defined (TARGET_PPC64)
+void OPPROTO op_load_asr (void)
+{
+    T0 = env->asr;
+    RETURN();
+}
+
+void OPPROTO op_store_asr (void)
+{
+    ppc_store_asr(env, T0);
+    RETURN();
+}
+#endif
+
+void OPPROTO op_load_msr (void)
 {
     T0 = do_load_msr(env);
     RETURN();
 }
 
-PPC_OP(store_msr)
+void OPPROTO op_store_msr (void)
 {
     do_store_msr(env, T0);
     RETURN();
 }
 
+void OPPROTO op_update_riee (void)
+{
+    msr_ri = (T0 >> MSR_RI) & 1;
+    msr_ee = (T0 >> MSR_EE) & 1;
+    RETURN();
+}
+
+#if defined (TARGET_PPC64)
+void OPPROTO op_store_msr_32 (void)
+{
+    ppc_store_msr_32(env, T0);
+    RETURN();
+}
+#endif
+#endif
+
 /* SPR */
-PPC_OP(load_spr)
+void OPPROTO op_load_spr (void)
 {
-    T0 = regs->spr[PARAM(1)];
+    T0 = env->spr[PARAM1];
     RETURN();
 }
 
-PPC_OP(store_spr)
+void OPPROTO op_store_spr (void)
 {
-    regs->spr[PARAM(1)] = T0;
+    env->spr[PARAM1] = T0;
     RETURN();
 }
 
-PPC_OP(load_lr)
+void OPPROTO op_load_dump_spr (void)
 {
-    T0 = regs->lr;
+    T0 = ppc_load_dump_spr(PARAM1);
     RETURN();
 }
 
-PPC_OP(store_lr)
+void OPPROTO op_store_dump_spr (void)
 {
-    regs->lr = T0;
+    ppc_store_dump_spr(PARAM1, T0);
     RETURN();
 }
 
-PPC_OP(load_ctr)
+void OPPROTO op_mask_spr (void)
 {
-    T0 = regs->ctr;
+    env->spr[PARAM1] &= ~T0;
     RETURN();
 }
 
-PPC_OP(store_ctr)
+void OPPROTO op_load_lr (void)
 {
-    regs->ctr = T0;
+    T0 = env->lr;
     RETURN();
 }
 
-PPC_OP(load_tbl)
+void OPPROTO op_store_lr (void)
 {
-    T0 = cpu_ppc_load_tbl(regs);
+    env->lr = T0;
     RETURN();
 }
 
-PPC_OP(load_tbu)
+void OPPROTO op_load_ctr (void)
 {
-    T0 = cpu_ppc_load_tbu(regs);
+    T0 = env->ctr;
     RETURN();
 }
 
-PPC_OP(store_tbl)
+void OPPROTO op_store_ctr (void)
 {
-    cpu_ppc_store_tbl(regs, T0);
+    env->ctr = T0;
     RETURN();
 }
 
-PPC_OP(store_tbu)
+void OPPROTO op_load_tbl (void)
 {
-    cpu_ppc_store_tbu(regs, T0);
+    T0 = cpu_ppc_load_tbl(env);
     RETURN();
 }
 
-PPC_OP(load_decr)
+void OPPROTO op_load_tbu (void)
 {
-    T0 = cpu_ppc_load_decr(regs);
-    }
-
-PPC_OP(store_decr)
-{
-    cpu_ppc_store_decr(regs, T0);
+    T0 = cpu_ppc_load_tbu(env);
     RETURN();
 }
 
-PPC_OP(load_ibat)
+void OPPROTO op_load_atbl (void)
 {
-    T0 = regs->IBAT[PARAM(1)][PARAM(2)];
+    T0 = cpu_ppc_load_atbl(env);
+    RETURN();
 }
 
-void op_store_ibatu (void)
+void OPPROTO op_load_atbu (void)
+{
+    T0 = cpu_ppc_load_atbu(env);
+    RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_tbl (void)
+{
+    cpu_ppc_store_tbl(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_store_tbu (void)
+{
+    cpu_ppc_store_tbu(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_store_atbl (void)
+{
+    cpu_ppc_store_atbl(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_store_atbu (void)
+{
+    cpu_ppc_store_atbu(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_load_decr (void)
+{
+    T0 = cpu_ppc_load_decr(env);
+    RETURN();
+}
+
+void OPPROTO op_store_decr (void)
+{
+    cpu_ppc_store_decr(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_load_ibat (void)
+{
+    T0 = env->IBAT[PARAM1][PARAM2];
+    RETURN();
+}
+
+void OPPROTO op_store_ibatu (void)
 {
     do_store_ibatu(env, PARAM1, T0);
     RETURN();
 }
 
-void op_store_ibatl (void)
+void OPPROTO op_store_ibatl (void)
 {
 #if 1
     env->IBAT[1][PARAM1] = T0;
@@ -389,18 +509,19 @@
     RETURN();
 }
 
-PPC_OP(load_dbat)
+void OPPROTO op_load_dbat (void)
 {
-    T0 = regs->DBAT[PARAM(1)][PARAM(2)];
+    T0 = env->DBAT[PARAM1][PARAM2];
+    RETURN();
 }
 
-void op_store_dbatu (void)
+void OPPROTO op_store_dbatu (void)
 {
     do_store_dbatu(env, PARAM1, T0);
     RETURN();
 }
 
-void op_store_dbatl (void)
+void OPPROTO op_store_dbatl (void)
 {
 #if 1
     env->DBAT[1][PARAM1] = T0;
@@ -409,390 +530,606 @@
 #endif
     RETURN();
 }
+#endif /* !defined(CONFIG_USER_ONLY) */
 
 /* FPSCR */
-PPC_OP(load_fpscr)
+void OPPROTO op_load_fpscr (void)
 {
-    FT0 = do_load_fpscr(env);
+    do_load_fpscr();
     RETURN();
 }
 
-PPC_OP(store_fpscr)
+void OPPROTO op_store_fpscr (void)
 {
-    do_store_fpscr(env, FT0, PARAM1);
+    do_store_fpscr(PARAM1);
     RETURN();
 }
 
-PPC_OP(reset_scrfx)
+void OPPROTO op_reset_scrfx (void)
 {
-    regs->fpscr[7] &= ~0x8;
+    env->fpscr[7] &= ~0x8;
     RETURN();
 }
 
 /* crf operations */
-PPC_OP(getbit_T0)
+void OPPROTO op_getbit_T0 (void)
 {
-    T0 = (T0 >> PARAM(1)) & 1;
+    T0 = (T0 >> PARAM1) & 1;
     RETURN();
 }
 
-PPC_OP(getbit_T1)
+void OPPROTO op_getbit_T1 (void)
 {
-    T1 = (T1 >> PARAM(1)) & 1;
+    T1 = (T1 >> PARAM1) & 1;
     RETURN();
 }
 
-PPC_OP(setcrfbit)
+void OPPROTO op_setcrfbit (void)
 {
-    T1 = (T1 & PARAM(1)) | (T0 << PARAM(2)); 
+    T1 = (T1 & PARAM1) | (T0 << PARAM2);
     RETURN();
 }
 
 /* Branch */
-#define EIP regs->nip
+#define EIP env->nip
 
-PPC_OP(setlr)
+void OPPROTO op_setlr (void)
 {
-    regs->lr = PARAM1;
+    env->lr = (uint32_t)PARAM1;
+    RETURN();
 }
 
-PPC_OP(goto_tb0)
+#if defined (TARGET_PPC64)
+void OPPROTO op_setlr_64 (void)
+{
+    env->lr = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_goto_tb0 (void)
 {
     GOTO_TB(op_goto_tb0, PARAM1, 0);
 }
 
-PPC_OP(goto_tb1)
+void OPPROTO op_goto_tb1 (void)
 {
     GOTO_TB(op_goto_tb1, PARAM1, 1);
 }
 
-PPC_OP(b_T1)
+void OPPROTO op_b_T1 (void)
 {
-    regs->nip = T1 & ~3;
+    env->nip = (uint32_t)(T1 & ~3);
+    RETURN();
 }
 
-PPC_OP(jz_T0)
+#if defined (TARGET_PPC64)
+void OPPROTO op_b_T1_64 (void)
+{
+    env->nip = (uint64_t)(T1 & ~3);
+    RETURN();
+}
+#endif
+
+void OPPROTO op_jz_T0 (void)
 {
     if (!T0)
         GOTO_LABEL_PARAM(1);
     RETURN();
 }
 
-PPC_OP(btest_T1) 
+void OPPROTO op_btest_T1 (void)
 {
     if (T0) {
-        regs->nip = T1 & ~3;
+        env->nip = (uint32_t)(T1 & ~3);
     } else {
-        regs->nip = PARAM1;
+        env->nip = (uint32_t)PARAM1;
     }
     RETURN();
 }
 
-PPC_OP(movl_T1_ctr)
+#if defined (TARGET_PPC64)
+void OPPROTO op_btest_T1_64 (void)
 {
-    T1 = regs->ctr;
+    if (T0) {
+        env->nip = (uint64_t)(T1 & ~3);
+    } else {
+        env->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
+    }
+    RETURN();
+}
+#endif
+
+void OPPROTO op_movl_T1_ctr (void)
+{
+    T1 = env->ctr;
+    RETURN();
 }
 
-PPC_OP(movl_T1_lr)
+void OPPROTO op_movl_T1_lr (void)
 {
-    T1 = regs->lr;
+    T1 = env->lr;
+    RETURN();
 }
 
 /* tests with result in T0 */
-
-PPC_OP(test_ctr)
+void OPPROTO op_test_ctr (void)
 {
-    T0 = regs->ctr;
+    T0 = (uint32_t)env->ctr;
+    RETURN();
 }
 
-PPC_OP(test_ctr_true)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctr_64 (void)
 {
-    T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0);
+    T0 = (uint64_t)env->ctr;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_test_ctr_true (void)
+{
+    T0 = ((uint32_t)env->ctr != 0 && (T0 & PARAM1) != 0);
+    RETURN();
 }
 
-PPC_OP(test_ctr_false)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctr_true_64 (void)
 {
-    T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0);
+    T0 = ((uint64_t)env->ctr != 0 && (T0 & PARAM1) != 0);
+    RETURN();
+}
+#endif
+
+void OPPROTO op_test_ctr_false (void)
+{
+    T0 = ((uint32_t)env->ctr != 0 && (T0 & PARAM1) == 0);
+    RETURN();
 }
 
-PPC_OP(test_ctrz)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctr_false_64 (void)
 {
-    T0 = (regs->ctr == 0);
+    T0 = ((uint64_t)env->ctr != 0 && (T0 & PARAM1) == 0);
+    RETURN();
+}
+#endif
+
+void OPPROTO op_test_ctrz (void)
+{
+    T0 = ((uint32_t)env->ctr == 0);
+    RETURN();
 }
 
-PPC_OP(test_ctrz_true)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctrz_64 (void)
 {
-    T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0);
+    T0 = ((uint64_t)env->ctr == 0);
+    RETURN();
+}
+#endif
+
+void OPPROTO op_test_ctrz_true (void)
+{
+    T0 = ((uint32_t)env->ctr == 0 && (T0 & PARAM1) != 0);
+    RETURN();
 }
 
-PPC_OP(test_ctrz_false)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctrz_true_64 (void)
 {
-    T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0);
+    T0 = ((uint64_t)env->ctr == 0 && (T0 & PARAM1) != 0);
+    RETURN();
+}
+#endif
+
+void OPPROTO op_test_ctrz_false (void)
+{
+    T0 = ((uint32_t)env->ctr == 0 && (T0 & PARAM1) == 0);
+    RETURN();
 }
 
-PPC_OP(test_true)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctrz_false_64 (void)
 {
-    T0 = (T0 & PARAM(1));
+    T0 = ((uint64_t)env->ctr == 0 && (T0 & PARAM1) == 0);
+    RETURN();
+}
+#endif
+
+void OPPROTO op_test_true (void)
+{
+    T0 = (T0 & PARAM1);
+    RETURN();
 }
 
-PPC_OP(test_false)
+void OPPROTO op_test_false (void)
 {
-    T0 = ((T0 & PARAM(1)) == 0);
+    T0 = ((T0 & PARAM1) == 0);
+    RETURN();
 }
 
 /* CTR maintenance */
-PPC_OP(dec_ctr)
+void OPPROTO op_dec_ctr (void)
 {
-    regs->ctr--;
+    env->ctr--;
     RETURN();
 }
 
 /***                           Integer arithmetic                          ***/
 /* add */
-PPC_OP(add)
+void OPPROTO op_add (void)
 {
     T0 += T1;
     RETURN();
 }
 
-void do_addo (void);
-void op_addo (void)
+void OPPROTO op_check_addo (void)
 {
-    do_addo();
+    if (likely(!(((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) &
+                 ((uint32_t)T2 ^ (uint32_t)T0) & (1UL << 31)))) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_addo_64 (void)
+{
+    if (likely(!(((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) &
+                 ((uint64_t)T2 ^ (uint64_t)T0) & (1ULL << 63)))) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
+    RETURN();
+}
+#endif
+
 /* add carrying */
-PPC_OP(addc)
+void OPPROTO op_check_addc (void)
 {
-    T2 = T0;
-    T0 += T1;
-    if (T0 < T2) {
-        xer_ca = 1;
-    } else {
+    if (likely((uint32_t)T0 >= (uint32_t)T2)) {
         xer_ca = 0;
+    } else {
+        xer_ca = 1;
     }
     RETURN();
 }
 
-void do_addco (void);
-void op_addco (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_addc_64 (void)
 {
-    do_addco();
+    if (likely((uint64_t)T0 >= (uint64_t)T2)) {
+        xer_ca = 0;
+    } else {
+        xer_ca = 1;
+    }
     RETURN();
 }
+#endif
 
 /* add extended */
-void do_adde (void);
-void op_adde (void)
+void OPPROTO op_adde (void)
 {
     do_adde();
-}
-
-void do_addeo (void);
-PPC_OP(addeo)
-{
-    do_addeo();
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_adde_64 (void)
+{
+    do_adde_64();
+    RETURN();
+}
+#endif
+
 /* add immediate */
-PPC_OP(addi)
+void OPPROTO op_addi (void)
 {
-    T0 += PARAM(1);
-    RETURN();
-}
-
-/* add immediate carrying */
-PPC_OP(addic)
-{
-    T1 = T0;
-    T0 += PARAM(1);
-    if (T0 < T1) {
-        xer_ca = 1;
-    } else {
-        xer_ca = 0;
-    }
+    T0 += (int32_t)PARAM1;
     RETURN();
 }
 
 /* add to minus one extended */
-PPC_OP(addme)
+void OPPROTO op_add_me (void)
 {
-    T1 = T0;
     T0 += xer_ca + (-1);
-    if (T1 != 0)
+    if (likely((uint32_t)T1 != 0))
         xer_ca = 1;
     RETURN();
 }
 
-void do_addmeo (void);
-void op_addmeo (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_add_me_64 (void)
+{
+    T0 += xer_ca + (-1);
+    if (likely((uint64_t)T1 != 0))
+        xer_ca = 1;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_addmeo (void)
+{
+    do_addmeo();
+    RETURN();
+}
+
+void OPPROTO op_addmeo_64 (void)
 {
     do_addmeo();
     RETURN();
 }
 
 /* add to zero extended */
-PPC_OP(addze)
+void OPPROTO op_add_ze (void)
 {
-    T1 = T0;
     T0 += xer_ca;
-    if (T0 < T1) {
-        xer_ca = 1;
-    } else {
-        xer_ca = 0;
-    }
-    RETURN();
-}
-
-void do_addzeo (void);
-void op_addzeo (void)
-{
-    do_addzeo();
     RETURN();
 }
 
 /* divide word */
-PPC_OP(divw)
+void OPPROTO op_divw (void)
 {
-    if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
-        T0 = (int32_t)((-1) * (T0 >> 31));
+    if (unlikely(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) ||
+                 (int32_t)T1 == 0)) {
+        T0 = (int32_t)((-1) * ((uint32_t)T0 >> 31));
     } else {
-        T0 = (Ts0 / Ts1);
+        T0 = (int32_t)T0 / (int32_t)T1;
     }
     RETURN();
 }
 
-void do_divwo (void);
-void op_divwo (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_divd (void)
+{
+    if (unlikely(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1) ||
+                 (int64_t)T1 == 0)) {
+        T0 = (int64_t)((-1ULL) * ((uint64_t)T0 >> 63));
+    } else {
+        T0 = (int64_t)T0 / (int64_t)T1;
+    }
+    RETURN();
+}
+#endif
+
+void OPPROTO op_divwo (void)
 {
     do_divwo();
     RETURN();
 }
 
-/* divide word unsigned */
-PPC_OP(divwu)
+#if defined(TARGET_PPC64)
+void OPPROTO op_divdo (void)
 {
-    if (T1 == 0) {
+    do_divdo();
+    RETURN();
+}
+#endif
+
+/* divide word unsigned */
+void OPPROTO op_divwu (void)
+{
+    if (unlikely(T1 == 0)) {
+        T0 = 0;
+    } else {
+        T0 = (uint32_t)T0 / (uint32_t)T1;
+    }
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_divdu (void)
+{
+    if (unlikely(T1 == 0)) {
         T0 = 0;
     } else {
         T0 /= T1;
     }
     RETURN();
 }
+#endif
 
-void do_divwuo (void);
-void op_divwuo (void)
+void OPPROTO op_divwuo (void)
 {
     do_divwuo();
     RETURN();
 }
 
-/* multiply high word */
-PPC_OP(mulhw)
+#if defined(TARGET_PPC64)
+void OPPROTO op_divduo (void)
 {
-    T0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32;
+    do_divduo();
     RETURN();
 }
+#endif
+
+/* multiply high word */
+void OPPROTO op_mulhw (void)
+{
+    T0 = ((int64_t)((int32_t)T0) * (int64_t)((int32_t)T1)) >> 32;
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_mulhd (void)
+{
+    uint64_t tl, th;
+
+    do_imul64(&tl, &th);
+    T0 = th;
+    RETURN();
+}
+#endif
 
 /* multiply high word unsigned */
-PPC_OP(mulhwu)
+void OPPROTO op_mulhwu (void)
 {
-    T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32;
+    T0 = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1) >> 32;
     RETURN();
 }
 
-/* multiply low immediate */
-PPC_OP(mulli)
+#if defined(TARGET_PPC64)
+void OPPROTO op_mulhdu (void)
 {
-    T0 = (Ts0 * SPARAM(1));
+    uint64_t tl, th;
+
+    do_mul64(&tl, &th);
+    T0 = th;
+    RETURN();
+}
+#endif
+
+/* multiply low immediate */
+void OPPROTO op_mulli (void)
+{
+    T0 = ((int32_t)T0 * (int32_t)PARAM1);
     RETURN();
 }
 
 /* multiply low word */
-PPC_OP(mullw)
+void OPPROTO op_mullw (void)
+{
+    T0 = (int32_t)(T0 * T1);
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_mulld (void)
 {
     T0 *= T1;
     RETURN();
 }
+#endif
 
-void do_mullwo (void);
-void op_mullwo (void)
+void OPPROTO op_mullwo (void)
 {
     do_mullwo();
     RETURN();
 }
 
-/* negate */
-PPC_OP(neg)
+#if defined(TARGET_PPC64)
+void OPPROTO op_mulldo (void)
 {
-    if (T0 != 0x80000000) {
-        T0 = -Ts0;
+    do_mulldo();
+    RETURN();
+}
+#endif
+
+/* negate */
+void OPPROTO op_neg (void)
+{
+    if (likely(T0 != INT32_MIN)) {
+        T0 = -(int32_t)T0;
     }
     RETURN();
 }
 
-void do_nego (void);
-void op_nego (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_neg_64 (void)
+{
+    if (likely(T0 != INT64_MIN)) {
+        T0 = -(int64_t)T0;
+    }
+    RETURN();
+}
+#endif
+
+void OPPROTO op_nego (void)
 {
     do_nego();
     RETURN();
 }
 
-/* substract from */
-PPC_OP(subf)
+#if defined(TARGET_PPC64)
+void OPPROTO op_nego_64 (void)
+{
+    do_nego_64();
+    RETURN();
+}
+#endif
+
+/* subtract from */
+void OPPROTO op_subf (void)
 {
     T0 = T1 - T0;
     RETURN();
 }
 
-void do_subfo (void);
-void op_subfo (void)
+void OPPROTO op_check_subfo (void)
 {
-    do_subfo();
-    RETURN();
-}
-
-/* substract from carrying */
-PPC_OP(subfc)
-{
-    T0 = T1 - T0;
-    if (T0 <= T1) {
-        xer_ca = 1;
+    if (likely(!(((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
+                 ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)))) {
+        xer_ov = 0;
     } else {
-        xer_ca = 0;
+        xer_ov = 1;
+        xer_so = 1;
     }
     RETURN();
 }
 
-void do_subfco (void);
-void op_subfco (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_subfo_64 (void)
 {
-    do_subfco();
+    if (likely(!(((uint64_t)(~T2) ^ (uint64_t)T1 ^ UINT64_MAX) &
+                 ((uint64_t)(~T2) ^ (uint64_t)T0) & (1ULL << 63)))) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
+    RETURN();
+}
+#endif
+
+/* subtract from carrying */
+void OPPROTO op_check_subfc (void)
+{
+    if (likely((uint32_t)T0 > (uint32_t)T1)) {
+        xer_ca = 0;
+    } else {
+        xer_ca = 1;
+    }
     RETURN();
 }
 
-/* substract from extended */
-void do_subfe (void);
-void op_subfe (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_subfc_64 (void)
+{
+    if (likely((uint64_t)T0 > (uint64_t)T1)) {
+        xer_ca = 0;
+    } else {
+        xer_ca = 1;
+    }
+    RETURN();
+}
+#endif
+
+/* subtract from extended */
+void OPPROTO op_subfe (void)
 {
     do_subfe();
     RETURN();
 }
 
-void do_subfeo (void);
-PPC_OP(subfeo)
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfe_64 (void)
 {
-    do_subfeo();
+    do_subfe_64();
     RETURN();
 }
+#endif
 
-/* substract from immediate carrying */
-PPC_OP(subfic)
+/* subtract from immediate carrying */
+void OPPROTO op_subfic (void)
 {
-    T0 = PARAM(1) + ~T0 + 1;
-    if (T0 <= PARAM(1)) {
+    T0 = (int32_t)PARAM1 + ~T0 + 1;
+    if ((uint32_t)T0 <= (uint32_t)PARAM1) {
         xer_ca = 1;
     } else {
         xer_ca = 0;
@@ -800,29 +1137,58 @@
     RETURN();
 }
 
-/* substract from minus one extended */
-PPC_OP(subfme)
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfic_64 (void)
+{
+    T0 = PARAM1 + ~T0 + 1;
+    if ((uint64_t)T0 <= (uint64_t)PARAM1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+#endif
+
+/* subtract from minus one extended */
+void OPPROTO op_subfme (void)
 {
     T0 = ~T0 + xer_ca - 1;
-
-    if (T0 != -1)
+    if (likely((uint32_t)T0 != (uint32_t)-1))
         xer_ca = 1;
     RETURN();
 }
 
-void do_subfmeo (void);
-void op_subfmeo (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfme_64 (void)
+{
+    T0 = ~T0 + xer_ca - 1;
+    if (likely((uint64_t)T0 != (uint64_t)-1))
+        xer_ca = 1;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_subfmeo (void)
 {
     do_subfmeo();
     RETURN();
 }
 
-/* substract from zero extended */
-PPC_OP(subfze)
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfmeo_64 (void)
+{
+    do_subfmeo_64();
+    RETURN();
+}
+#endif
+
+/* subtract from zero extended */
+void OPPROTO op_subfze (void)
 {
     T1 = ~T0;
     T0 = T1 + xer_ca;
-    if (T0 < T1) {
+    if ((uint32_t)T0 < (uint32_t)T1) {
         xer_ca = 1;
     } else {
         xer_ca = 0;
@@ -830,238 +1196,391 @@
     RETURN();
 }
 
-void do_subfzeo (void);
-void op_subfzeo (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfze_64 (void)
+{
+    T1 = ~T0;
+    T0 = T1 + xer_ca;
+    if ((uint64_t)T0 < (uint64_t)T1) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+#endif
+
+void OPPROTO op_subfzeo (void)
 {
     do_subfzeo();
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfzeo_64 (void)
+{
+    do_subfzeo_64();
+    RETURN();
+}
+#endif
+
 /***                           Integer comparison                          ***/
 /* compare */
-PPC_OP(cmp)
+void OPPROTO op_cmp (void)
 {
-    if (Ts0 < Ts1) {
+    if ((int32_t)T0 < (int32_t)T1) {
         T0 = 0x08;
-    } else if (Ts0 > Ts1) {
+    } else if ((int32_t)T0 > (int32_t)T1) {
         T0 = 0x04;
     } else {
         T0 = 0x02;
     }
+    T0 |= xer_so;
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_cmp_64 (void)
+{
+    if ((int64_t)T0 < (int64_t)T1) {
+        T0 = 0x08;
+    } else if ((int64_t)T0 > (int64_t)T1) {
+        T0 = 0x04;
+    } else {
+        T0 = 0x02;
+    }
+    T0 |= xer_so;
+    RETURN();
+}
+#endif
+
 /* compare immediate */
-PPC_OP(cmpi)
+void OPPROTO op_cmpi (void)
 {
-    if (Ts0 < SPARAM(1)) {
+    if ((int32_t)T0 < (int32_t)PARAM1) {
         T0 = 0x08;
-    } else if (Ts0 > SPARAM(1)) {
+    } else if ((int32_t)T0 > (int32_t)PARAM1) {
         T0 = 0x04;
     } else {
         T0 = 0x02;
     }
+    T0 |= xer_so;
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_cmpi_64 (void)
+{
+    if ((int64_t)T0 < (int64_t)((int32_t)PARAM1)) {
+        T0 = 0x08;
+    } else if ((int64_t)T0 > (int64_t)((int32_t)PARAM1)) {
+        T0 = 0x04;
+    } else {
+        T0 = 0x02;
+    }
+    T0 |= xer_so;
+    RETURN();
+}
+#endif
+
 /* compare logical */
-PPC_OP(cmpl)
+void OPPROTO op_cmpl (void)
 {
-    if (T0 < T1) {
+    if ((uint32_t)T0 < (uint32_t)T1) {
         T0 = 0x08;
-    } else if (T0 > T1) {
+    } else if ((uint32_t)T0 > (uint32_t)T1) {
         T0 = 0x04;
     } else {
         T0 = 0x02;
     }
+    T0 |= xer_so;
     RETURN();
 }
 
-/* compare logical immediate */
-PPC_OP(cmpli)
+#if defined(TARGET_PPC64)
+void OPPROTO op_cmpl_64 (void)
 {
-    if (T0 < PARAM(1)) {
+    if ((uint64_t)T0 < (uint64_t)T1) {
         T0 = 0x08;
-    } else if (T0 > PARAM(1)) {
+    } else if ((uint64_t)T0 > (uint64_t)T1) {
         T0 = 0x04;
     } else {
         T0 = 0x02;
     }
+    T0 |= xer_so;
     RETURN();
 }
+#endif
+
+/* compare logical immediate */
+void OPPROTO op_cmpli (void)
+{
+    if ((uint32_t)T0 < (uint32_t)PARAM1) {
+        T0 = 0x08;
+    } else if ((uint32_t)T0 > (uint32_t)PARAM1) {
+        T0 = 0x04;
+    } else {
+        T0 = 0x02;
+    }
+    T0 |= xer_so;
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_cmpli_64 (void)
+{
+    if ((uint64_t)T0 < (uint64_t)PARAM1) {
+        T0 = 0x08;
+    } else if ((uint64_t)T0 > (uint64_t)PARAM1) {
+        T0 = 0x04;
+    } else {
+        T0 = 0x02;
+    }
+    T0 |= xer_so;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_isel (void)
+{
+    if (T0)
+        T0 = T1;
+    else
+        T0 = T2;
+    RETURN();
+}
+
+void OPPROTO op_popcntb (void)
+{
+    do_popcntb();
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_popcntb_64 (void)
+{
+    do_popcntb_64();
+    RETURN();
+}
+#endif
 
 /***                            Integer logical                            ***/
 /* and */
-PPC_OP(and)
+void OPPROTO op_and (void)
 {
     T0 &= T1;
     RETURN();
 }
 
 /* andc */
-PPC_OP(andc)
+void OPPROTO op_andc (void)
 {
     T0 &= ~T1;
     RETURN();
 }
 
 /* andi. */
-PPC_OP(andi_)
+void OPPROTO op_andi_T0 (void)
 {
-    T0 &= PARAM(1);
+    T0 &= PARAM1;
     RETURN();
 }
 
+void OPPROTO op_andi_T1 (void)
+{
+    T1 &= PARAM1;
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_andi_T0_64 (void)
+{
+    T0 &= ((uint64_t)PARAM1 << 32) | PARAM2;
+    RETURN();
+}
+
+void OPPROTO op_andi_T1_64 (void)
+{
+    T1 &= ((uint64_t)PARAM1 << 32) | PARAM2;
+    RETURN();
+}
+#endif
+
+
 /* count leading zero */
-PPC_OP(cntlzw)
+void OPPROTO op_cntlzw (void)
 {
-    T1 = T0;
-    for (T0 = 32; T1 > 0; T0--)
-        T1 = T1 >> 1;
+    T0 = _do_cntlzw(T0);
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_cntlzd (void)
+{
+    T0 = _do_cntlzd(T0);
+    RETURN();
+}
+#endif
+
 /* eqv */
-PPC_OP(eqv)
+void OPPROTO op_eqv (void)
 {
     T0 = ~(T0 ^ T1);
     RETURN();
 }
 
 /* extend sign byte */
-PPC_OP(extsb)
+void OPPROTO op_extsb (void)
 {
-    T0 = (int32_t)((int8_t)(Ts0));
+#if defined (TARGET_PPC64)
+    T0 = (int64_t)((int8_t)T0);
+#else
+    T0 = (int32_t)((int8_t)T0);
+#endif
     RETURN();
 }
 
 /* extend sign half word */
-PPC_OP(extsh)
+void OPPROTO op_extsh (void)
 {
-    T0 = (int32_t)((int16_t)(Ts0));
+#if defined (TARGET_PPC64)
+    T0 = (int64_t)((int16_t)T0);
+#else
+    T0 = (int32_t)((int16_t)T0);
+#endif
     RETURN();
 }
 
+#if defined (TARGET_PPC64)
+void OPPROTO op_extsw (void)
+{
+    T0 = (int64_t)((int32_t)T0);
+    RETURN();
+}
+#endif
+
 /* nand */
-PPC_OP(nand)
+void OPPROTO op_nand (void)
 {
     T0 = ~(T0 & T1);
     RETURN();
 }
 
 /* nor */
-PPC_OP(nor)
+void OPPROTO op_nor (void)
 {
     T0 = ~(T0 | T1);
     RETURN();
 }
 
 /* or */
-PPC_OP(or)
+void OPPROTO op_or (void)
 {
     T0 |= T1;
     RETURN();
 }
 
 /* orc */
-PPC_OP(orc)
+void OPPROTO op_orc (void)
 {
     T0 |= ~T1;
     RETURN();
 }
 
 /* ori */
-PPC_OP(ori)
+void OPPROTO op_ori (void)
 {
-    T0 |= PARAM(1);
+    T0 |= PARAM1;
     RETURN();
 }
 
 /* xor */
-PPC_OP(xor)
+void OPPROTO op_xor (void)
 {
     T0 ^= T1;
     RETURN();
 }
 
 /* xori */
-PPC_OP(xori)
+void OPPROTO op_xori (void)
 {
-    T0 ^= PARAM(1);
+    T0 ^= PARAM1;
     RETURN();
 }
 
 /***                             Integer rotate                            ***/
-/* rotate left word immediate then mask insert */
-PPC_OP(rlwimi)
+void OPPROTO op_rotl32_T0_T1 (void)
 {
-    T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3));
+    T0 = rotl32(T0, T1 & 0x1F);
     RETURN();
 }
 
-/* rotate left immediate then and with mask insert */
-PPC_OP(rotlwi)
+void OPPROTO op_rotli32_T0 (void)
 {
-    T0 = rotl(T0, PARAM(1));
+    T0 = rotl32(T0, PARAM1);
     RETURN();
 }
 
-PPC_OP(slwi)
+#if defined(TARGET_PPC64)
+void OPPROTO op_rotl64_T0_T1 (void)
 {
-    T0 = T0 << PARAM(1);
+    T0 = rotl64(T0, T1 & 0x3F);
     RETURN();
 }
 
-PPC_OP(srwi)
+void OPPROTO op_rotli64_T0 (void)
 {
-    T0 = T0 >> PARAM(1);
+    T0 = rotl64(T0, PARAM1);
     RETURN();
 }
-
-/* rotate left word then and with mask insert */
-PPC_OP(rlwinm)
-{
-    T0 = rotl(T0, PARAM(1)) & PARAM(2);
-    RETURN();
-}
-
-PPC_OP(rotl)
-{
-    T0 = rotl(T0, T1);
-    RETURN();
-}
-
-PPC_OP(rlwnm)
-{
-    T0 = rotl(T0, T1) & PARAM(1);
-    RETURN();
-}
+#endif
 
 /***                             Integer shift                             ***/
 /* shift left word */
-PPC_OP(slw)
+void OPPROTO op_slw (void)
 {
     if (T1 & 0x20) {
         T0 = 0;
     } else {
+        T0 = (uint32_t)(T0 << T1);
+    }
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_sld (void)
+{
+    if (T1 & 0x40) {
+        T0 = 0;
+    } else {
         T0 = T0 << T1;
     }
     RETURN();
 }
+#endif
 
 /* shift right algebraic word */
-void op_sraw (void)
+void OPPROTO op_sraw (void)
 {
     do_sraw();
     RETURN();
 }
 
-/* shift right algebraic word immediate */
-PPC_OP(srawi)
+#if defined(TARGET_PPC64)
+void OPPROTO op_srad (void)
 {
-    T1 = T0;
-    T0 = (Ts0 >> PARAM(1));
-    if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) {
+    do_srad();
+    RETURN();
+}
+#endif
+
+/* shift right algebraic word immediate */
+void OPPROTO op_srawi (void)
+{
+    uint32_t mask = (uint32_t)PARAM2;
+
+    T0 = (int32_t)T0 >> PARAM1;
+    if ((int32_t)T1 < 0 && (T1 & mask) != 0) {
         xer_ca = 1;
     } else {
         xer_ca = 0;
@@ -1069,69 +1588,157 @@
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_sradi (void)
+{
+    uint64_t mask = ((uint64_t)PARAM2 << 32) | (uint64_t)PARAM3;
+
+    T0 = (int64_t)T0 >> PARAM1;
+    if ((int64_t)T1 < 0 && ((uint64_t)T1 & mask) != 0) {
+        xer_ca = 1;
+    } else {
+        xer_ca = 0;
+    }
+    RETURN();
+}
+#endif
+
 /* shift right word */
-PPC_OP(srw)
+void OPPROTO op_srw (void)
 {
     if (T1 & 0x20) {
         T0 = 0;
     } else {
-        T0 = T0 >> T1;
+        T0 = (uint32_t)T0 >> T1;
     }
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_srd (void)
+{
+    if (T1 & 0x40) {
+        T0 = 0;
+    } else {
+        T0 = (uint64_t)T0 >> T1;
+    }
+    RETURN();
+}
+#endif
+
+void OPPROTO op_sl_T0_T1 (void)
+{
+    T0 = T0 << T1;
+    RETURN();
+}
+
+void OPPROTO op_sli_T0 (void)
+{
+    T0 = T0 << PARAM1;
+    RETURN();
+}
+
+void OPPROTO op_srl_T0_T1 (void)
+{
+    T0 = (uint32_t)T0 >> T1;
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_srl_T0_T1_64 (void)
+{
+    T0 = (uint32_t)T0 >> T1;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_srli_T0 (void)
+{
+    T0 = (uint32_t)T0 >> PARAM1;
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_srli_T0_64 (void)
+{
+    T0 = (uint64_t)T0 >> PARAM1;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_srli_T1 (void)
+{
+    T1 = (uint32_t)T1 >> PARAM1;
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_srli_T1_64 (void)
+{
+    T1 = (uint64_t)T1 >> PARAM1;
+    RETURN();
+}
+#endif
+
 /***                       Floating-Point arithmetic                       ***/
 /* fadd - fadd. */
-PPC_OP(fadd)
+void OPPROTO op_fadd (void)
 {
-    FT0 += FT1;
+    FT0 = float64_add(FT0, FT1, &env->fp_status);
     RETURN();
 }
 
 /* fsub - fsub. */
-PPC_OP(fsub)
+void OPPROTO op_fsub (void)
 {
-    FT0 -= FT1;
+    FT0 = float64_sub(FT0, FT1, &env->fp_status);
     RETURN();
 }
 
 /* fmul - fmul. */
-PPC_OP(fmul)
+void OPPROTO op_fmul (void)
 {
-    FT0 *= FT1;
+    FT0 = float64_mul(FT0, FT1, &env->fp_status);
     RETURN();
 }
 
 /* fdiv - fdiv. */
-PPC_OP(fdiv)
+void OPPROTO op_fdiv (void)
 {
     FT0 = float64_div(FT0, FT1, &env->fp_status);
     RETURN();
 }
 
 /* fsqrt - fsqrt. */
-PPC_OP(fsqrt)
+void OPPROTO op_fsqrt (void)
 {
     do_fsqrt();
     RETURN();
 }
 
+/* fre - fre. */
+void OPPROTO op_fre (void)
+{
+    do_fre();
+    RETURN();
+}
+
 /* fres - fres. */
-PPC_OP(fres)
+void OPPROTO op_fres (void)
 {
     do_fres();
     RETURN();
 }
 
 /* frsqrte  - frsqrte. */
-PPC_OP(frsqrte)
+void OPPROTO op_frsqrte (void)
 {
     do_frsqrte();
     RETURN();
 }
 
 /* fsel - fsel. */
-PPC_OP(fsel)
+void OPPROTO op_fsel (void)
 {
     do_fsel();
     RETURN();
@@ -1139,28 +1746,38 @@
 
 /***                     Floating-Point multiply-and-add                   ***/
 /* fmadd - fmadd. */
-PPC_OP(fmadd)
+void OPPROTO op_fmadd (void)
 {
-    FT0 = (FT0 * FT1) + FT2;
+#if USE_PRECISE_EMULATION
+    do_fmadd();
+#else
+    FT0 = float64_mul(FT0, FT1, &env->fp_status);
+    FT0 = float64_add(FT0, FT2, &env->fp_status);
+#endif
     RETURN();
 }
 
 /* fmsub - fmsub. */
-PPC_OP(fmsub)
+void OPPROTO op_fmsub (void)
 {
-    FT0 = (FT0 * FT1) - FT2;
+#if USE_PRECISE_EMULATION
+    do_fmsub();
+#else
+    FT0 = float64_mul(FT0, FT1, &env->fp_status);
+    FT0 = float64_sub(FT0, FT2, &env->fp_status);
+#endif
     RETURN();
 }
 
 /* fnmadd - fnmadd. - fnmadds - fnmadds. */
-PPC_OP(fnmadd)
+void OPPROTO op_fnmadd (void)
 {
     do_fnmadd();
     RETURN();
 }
 
 /* fnmsub - fnmsub. */
-PPC_OP(fnmsub)
+void OPPROTO op_fnmsub (void)
 {
     do_fnmsub();
     RETURN();
@@ -1168,37 +1785,83 @@
 
 /***                     Floating-Point round & convert                    ***/
 /* frsp - frsp. */
-PPC_OP(frsp)
+void OPPROTO op_frsp (void)
 {
-    FT0 = (float)FT0;
+    FT0 = float64_to_float32(FT0, &env->fp_status);
     RETURN();
 }
 
 /* fctiw - fctiw. */
-PPC_OP(fctiw)
+void OPPROTO op_fctiw (void)
 {
     do_fctiw();
     RETURN();
 }
 
 /* fctiwz - fctiwz. */
-PPC_OP(fctiwz)
+void OPPROTO op_fctiwz (void)
 {
     do_fctiwz();
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+/* fcfid - fcfid. */
+void OPPROTO op_fcfid (void)
+{
+    do_fcfid();
+    RETURN();
+}
+
+/* fctid - fctid. */
+void OPPROTO op_fctid (void)
+{
+    do_fctid();
+    RETURN();
+}
+
+/* fctidz - fctidz. */
+void OPPROTO op_fctidz (void)
+{
+    do_fctidz();
+    RETURN();
+}
+#endif
+
+void OPPROTO op_frin (void)
+{
+    do_frin();
+    RETURN();
+}
+
+void OPPROTO op_friz (void)
+{
+    do_friz();
+    RETURN();
+}
+
+void OPPROTO op_frip (void)
+{
+    do_frip();
+    RETURN();
+}
+
+void OPPROTO op_frim (void)
+{
+    do_frim();
+    RETURN();
+}
 
 /***                         Floating-Point compare                        ***/
 /* fcmpu */
-PPC_OP(fcmpu)
+void OPPROTO op_fcmpu (void)
 {
     do_fcmpu();
     RETURN();
 }
 
 /* fcmpo */
-PPC_OP(fcmpo)
+void OPPROTO op_fcmpo (void)
 {
     do_fcmpo();
     RETURN();
@@ -1206,14 +1869,14 @@
 
 /***                         Floating-point move                           ***/
 /* fabs */
-PPC_OP(fabs)
+void OPPROTO op_fabs (void)
 {
     FT0 = float64_abs(FT0);
     RETURN();
 }
 
 /* fnabs */
-PPC_OP(fnabs)
+void OPPROTO op_fnabs (void)
 {
     FT0 = float64_abs(FT0);
     FT0 = float64_chs(FT0);
@@ -1221,7 +1884,7 @@
 }
 
 /* fneg */
-PPC_OP(fneg)
+void OPPROTO op_fneg (void)
 {
     FT0 = float64_chs(FT0);
     RETURN();
@@ -1229,68 +1892,1464 @@
 
 /* Load and store */
 #define MEMSUFFIX _raw
+#include "op_helper.h"
 #include "op_mem.h"
 #if !defined(CONFIG_USER_ONLY)
 #define MEMSUFFIX _user
+#include "op_helper.h"
 #include "op_mem.h"
-
 #define MEMSUFFIX _kernel
+#include "op_helper.h"
 #include "op_mem.h"
 #endif
 
 /* Special op to check and maybe clear reservation */
-PPC_OP(check_reservation)
+void OPPROTO op_check_reservation (void)
 {
     if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003))
         env->reserve = -1;
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_reservation_64 (void)
+{
+    if ((uint64_t)env->reserve == (uint64_t)(T0 & ~0x00000003))
+        env->reserve = -1;
+    RETURN();
+}
+#endif
+
+void OPPROTO op_wait (void)
+{
+    env->halted = 1;
+    RETURN();
+}
+
 /* Return from interrupt */
-void do_rfi (void);
-void op_rfi (void)
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_rfi (void)
 {
     do_rfi();
     RETURN();
 }
 
+#if defined(TARGET_PPC64)
+void OPPROTO op_rfid (void)
+{
+    do_rfid();
+    RETURN();
+}
+#endif
+
+#if defined(TARGET_PPC64H)
+void OPPROTO op_hrfid (void)
+{
+    do_hrfid();
+    RETURN();
+}
+#endif
+
+/* Exception vectors */
+void OPPROTO op_store_excp_prefix (void)
+{
+    T0 &= env->ivpr_mask;
+    env->excp_prefix = T0;
+    RETURN();
+}
+
+void OPPROTO op_store_excp_vector (void)
+{
+    T0 &= env->ivor_mask;
+    env->excp_vectors[PARAM1] = T0;
+    RETURN();
+}
+#endif
+
 /* Trap word */
-void do_tw (uint32_t cmp, int flags);
-void op_tw (void)
+void OPPROTO op_tw (void)
 {
-    do_tw(T1, PARAM(1));
+    do_tw(PARAM1);
     RETURN();
 }
 
-void op_twi (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_td (void)
 {
-    do_tw(PARAM(1), PARAM(2));
+    do_td(PARAM1);
     RETURN();
 }
+#endif
 
-/* Instruction cache block invalidate */
-PPC_OP(icbi)
-{
-    do_icbi();
-    RETURN();
-}
-
+#if !defined(CONFIG_USER_ONLY)
 /* tlbia */
-PPC_OP(tlbia)
+void OPPROTO op_tlbia (void)
 {
-    do_tlbia();
+    ppc_tlb_invalidate_all(env);
     RETURN();
 }
 
 /* tlbie */
-PPC_OP(tlbie)
+void OPPROTO op_tlbie (void)
 {
-    do_tlbie();
+    ppc_tlb_invalidate_one(env, (uint32_t)T0);
     RETURN();
 }
 
-void op_store_pir (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_tlbie_64 (void)
+{
+    ppc_tlb_invalidate_one(env, T0);
+    RETURN();
+}
+#endif
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_slbia (void)
+{
+    ppc_slb_invalidate_all(env);
+    RETURN();
+}
+
+void OPPROTO op_slbie (void)
+{
+    ppc_slb_invalidate_one(env, (uint32_t)T0);
+    RETURN();
+}
+
+void OPPROTO op_slbie_64 (void)
+{
+    ppc_slb_invalidate_one(env, T0);
+    RETURN();
+}
+#endif
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
+/* PowerPC 602/603/755 software TLB load instructions */
+void OPPROTO op_6xx_tlbld (void)
+{
+    do_load_6xx_tlb(0);
+    RETURN();
+}
+
+void OPPROTO op_6xx_tlbli (void)
+{
+    do_load_6xx_tlb(1);
+    RETURN();
+}
+
+/* PowerPC 74xx software TLB load instructions */
+void OPPROTO op_74xx_tlbld (void)
+{
+    do_load_74xx_tlb(0);
+    RETURN();
+}
+
+void OPPROTO op_74xx_tlbli (void)
+{
+    do_load_74xx_tlb(1);
+    RETURN();
+}
+#endif
+
+/* 601 specific */
+void OPPROTO op_load_601_rtcl (void)
+{
+    T0 = cpu_ppc601_load_rtcl(env);
+    RETURN();
+}
+
+void OPPROTO op_load_601_rtcu (void)
+{
+    T0 = cpu_ppc601_load_rtcu(env);
+    RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_601_rtcl (void)
+{
+    cpu_ppc601_store_rtcl(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_store_601_rtcu (void)
+{
+    cpu_ppc601_store_rtcu(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_load_601_bat (void)
+{
+    T0 = env->IBAT[PARAM1][PARAM2];
+    RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* 601 unified BATs store.
+ * To avoid using specific MMU code for 601, we store BATs in
+ * IBAT and DBAT simultaneously, then emulate unified BATs.
+ */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_601_batl (void)
+{
+    int nr = PARAM1;
+
+    env->IBAT[1][nr] = T0;
+    env->DBAT[1][nr] = T0;
+    RETURN();
+}
+
+void OPPROTO op_store_601_batu (void)
+{
+    do_store_601_batu(PARAM1);
+    RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* PowerPC 601 specific instructions (POWER bridge) */
+/* XXX: those micro-ops need tests ! */
+void OPPROTO op_POWER_abs (void)
+{
+    if (T0 == INT32_MIN)
+        T0 = INT32_MAX;
+    else if (T0 < 0)
+        T0 = -T0;
+    RETURN();
+}
+
+void OPPROTO op_POWER_abso (void)
+{
+    do_POWER_abso();
+    RETURN();
+}
+
+void OPPROTO op_POWER_clcs (void)
+{
+    do_POWER_clcs();
+    RETURN();
+}
+
+void OPPROTO op_POWER_div (void)
+{
+    do_POWER_div();
+    RETURN();
+}
+
+void OPPROTO op_POWER_divo (void)
+{
+    do_POWER_divo();
+    RETURN();
+}
+
+void OPPROTO op_POWER_divs (void)
+{
+    do_POWER_divs();
+    RETURN();
+}
+
+void OPPROTO op_POWER_divso (void)
+{
+    do_POWER_divso();
+    RETURN();
+}
+
+void OPPROTO op_POWER_doz (void)
+{
+    if ((int32_t)T1 > (int32_t)T0)
+        T0 = T1 - T0;
+    else
+        T0 = 0;
+    RETURN();
+}
+
+void OPPROTO op_POWER_dozo (void)
+{
+    do_POWER_dozo();
+    RETURN();
+}
+
+void OPPROTO op_load_xer_cmp (void)
+{
+    T2 = xer_cmp;
+    RETURN();
+}
+
+void OPPROTO op_POWER_maskg (void)
+{
+    do_POWER_maskg();
+    RETURN();
+}
+
+void OPPROTO op_POWER_maskir (void)
+{
+    T0 = (T0 & ~T2) | (T1 & T2);
+    RETURN();
+}
+
+void OPPROTO op_POWER_mul (void)
+{
+    uint64_t tmp;
+
+    tmp = (uint64_t)T0 * (uint64_t)T1;
+    env->spr[SPR_MQ] = tmp >> 32;
+    T0 = tmp;
+    RETURN();
+}
+
+void OPPROTO op_POWER_mulo (void)
+{
+    do_POWER_mulo();
+    RETURN();
+}
+
+void OPPROTO op_POWER_nabs (void)
+{
+    if (T0 > 0)
+        T0 = -T0;
+    RETURN();
+}
+
+void OPPROTO op_POWER_nabso (void)
+{
+    /* nabs never overflows */
+    if (T0 > 0)
+        T0 = -T0;
+    xer_ov = 0;
+    RETURN();
+}
+
+/* XXX: factorise POWER rotates... */
+void OPPROTO op_POWER_rlmi (void)
+{
+    T0 = rotl32(T0, T2) & PARAM1;
+    T0 |= T1 & PARAM2;
+    RETURN();
+}
+
+void OPPROTO op_POWER_rrib (void)
+{
+    T2 &= 0x1FUL;
+    T0 = rotl32(T0 & INT32_MIN, T2);
+    T0 |= T1 & ~rotl32(INT32_MIN, T2);
+    RETURN();
+}
+
+void OPPROTO op_POWER_sle (void)
+{
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = rotl32(T0, T1);
+    T0 = T0 << T1;
+    RETURN();
+}
+
+void OPPROTO op_POWER_sleq (void)
+{
+    uint32_t tmp = env->spr[SPR_MQ];
+
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = rotl32(T0, T1);
+    T0 = T0 << T1;
+    T0 |= tmp >> (32 - T1);
+    RETURN();
+}
+
+void OPPROTO op_POWER_sllq (void)
+{
+    uint32_t msk = -1;
+
+    msk = msk << (T1 & 0x1FUL);
+    if (T1 & 0x20UL)
+        msk = ~msk;
+    T1 &= 0x1FUL;
+    T0 = (T0 << T1) & msk;
+    T0 |= env->spr[SPR_MQ] & ~msk;
+    RETURN();
+}
+
+void OPPROTO op_POWER_slq (void)
+{
+    uint32_t msk = -1, tmp;
+
+    msk = msk << (T1 & 0x1FUL);
+    if (T1 & 0x20UL)
+        msk = ~msk;
+    T1 &= 0x1FUL;
+    tmp = rotl32(T0, T1);
+    T0 = tmp & msk;
+    env->spr[SPR_MQ] = tmp;
+    RETURN();
+}
+
+void OPPROTO op_POWER_sraq (void)
+{
+    env->spr[SPR_MQ] = rotl32(T0, 32 - (T1 & 0x1FUL));
+    if (T1 & 0x20UL)
+        T0 = -1L;
+    else
+        T0 = (int32_t)T0 >> T1;
+    RETURN();
+}
+
+void OPPROTO op_POWER_sre (void)
+{
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+    T0 = (int32_t)T0 >> T1;
+    RETURN();
+}
+
+void OPPROTO op_POWER_srea (void)
+{
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = T0 >> T1;
+    T0 = (int32_t)T0 >> T1;
+    RETURN();
+}
+
+void OPPROTO op_POWER_sreq (void)
+{
+    uint32_t tmp;
+    int32_t msk;
+
+    T1 &= 0x1FUL;
+    msk = INT32_MIN >> T1;
+    tmp = env->spr[SPR_MQ];
+    env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+    T0 = T0 >> T1;
+    T0 |= tmp & msk;
+    RETURN();
+}
+
+void OPPROTO op_POWER_srlq (void)
+{
+    uint32_t tmp;
+    int32_t msk;
+
+    msk = INT32_MIN >> (T1 & 0x1FUL);
+    if (T1 & 0x20UL)
+        msk = ~msk;
+    T1 &= 0x1FUL;
+    tmp = env->spr[SPR_MQ];
+    env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+    T0 = T0 >> T1;
+    T0 &= msk;
+    T0 |= tmp & ~msk;
+    RETURN();
+}
+
+void OPPROTO op_POWER_srq (void)
+{
+    T1 &= 0x1FUL;
+    env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+    T0 = T0 >> T1;
+    RETURN();
+}
+
+/* POWER instructions not implemented in PowerPC 601 */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_POWER_mfsri (void)
+{
+    T1 = T0 >> 28;
+    T0 = env->sr[T1];
+    RETURN();
+}
+
+void OPPROTO op_POWER_rac (void)
+{
+    do_POWER_rac();
+    RETURN();
+}
+
+void OPPROTO op_POWER_rfsvc (void)
+{
+    do_POWER_rfsvc();
+    RETURN();
+}
+#endif
+
+/* PowerPC 602 specific instruction */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_602_mfrom (void)
+{
+    do_op_602_mfrom();
+    RETURN();
+}
+#endif
+
+/* PowerPC 4xx specific micro-ops */
+void OPPROTO op_405_add_T0_T2 (void)
+{
+    T0 = (int32_t)T0 + (int32_t)T2;
+    RETURN();
+}
+
+void OPPROTO op_405_mulchw (void)
+{
+    T0 = ((int16_t)T0) * ((int16_t)(T1 >> 16));
+    RETURN();
+}
+
+void OPPROTO op_405_mulchwu (void)
+{
+    T0 = ((uint16_t)T0) * ((uint16_t)(T1 >> 16));
+    RETURN();
+}
+
+void OPPROTO op_405_mulhhw (void)
+{
+    T0 = ((int16_t)(T0 >> 16)) * ((int16_t)(T1 >> 16));
+    RETURN();
+}
+
+void OPPROTO op_405_mulhhwu (void)
+{
+    T0 = ((uint16_t)(T0 >> 16)) * ((uint16_t)(T1 >> 16));
+    RETURN();
+}
+
+void OPPROTO op_405_mullhw (void)
+{
+    T0 = ((int16_t)T0) * ((int16_t)T1);
+    RETURN();
+}
+
+void OPPROTO op_405_mullhwu (void)
+{
+    T0 = ((uint16_t)T0) * ((uint16_t)T1);
+    RETURN();
+}
+
+void OPPROTO op_405_check_ov (void)
+{
+    do_405_check_ov();
+    RETURN();
+}
+
+void OPPROTO op_405_check_sat (void)
+{
+    do_405_check_sat();
+    RETURN();
+}
+
+void OPPROTO op_405_check_ovu (void)
+{
+    if (likely(T0 >= T2)) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
+    RETURN();
+}
+
+void OPPROTO op_405_check_satu (void)
+{
+    if (unlikely(T0 < T2)) {
+        /* Saturate result */
+        T0 = -1;
+    }
+    RETURN();
+}
+
+void OPPROTO op_load_dcr (void)
+{
+    do_load_dcr();
+    RETURN();
+}
+
+void OPPROTO op_store_dcr (void)
+{
+    do_store_dcr();
+    RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+/* Return from critical interrupt :
+ * same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1
+ */
+void OPPROTO op_40x_rfci (void)
+{
+    do_40x_rfci();
+    RETURN();
+}
+
+void OPPROTO op_rfci (void)
+{
+    do_rfci();
+    RETURN();
+}
+
+void OPPROTO op_rfdi (void)
+{
+    do_rfdi();
+    RETURN();
+}
+
+void OPPROTO op_rfmci (void)
+{
+    do_rfmci();
+    RETURN();
+}
+
+void OPPROTO op_wrte (void)
+{
+    msr_ee = T0 >> 16;
+    RETURN();
+}
+
+void OPPROTO op_440_tlbre (void)
+{
+    do_440_tlbre(PARAM1);
+    RETURN();
+}
+
+void OPPROTO op_440_tlbsx (void)
+{
+    T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_440_MMUCR] & 0xFF);
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbsx_check (void)
+{
+    int tmp;
+
+    tmp = xer_so;
+    if (T0 != -1)
+        tmp |= 0x02;
+    env->crf[0] = tmp;
+    RETURN();
+}
+
+void OPPROTO op_440_tlbwe (void)
+{
+    do_440_tlbwe(PARAM1);
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbre_lo (void)
+{
+    do_4xx_tlbre_lo();
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbre_hi (void)
+{
+    do_4xx_tlbre_hi();
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbsx (void)
+{
+    T0 = ppcemb_tlb_search(env, T0, env->spr[SPR_40x_PID]);
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbwe_lo (void)
+{
+    do_4xx_tlbwe_lo();
+    RETURN();
+}
+
+void OPPROTO op_4xx_tlbwe_hi (void)
+{
+    do_4xx_tlbwe_hi();
+    RETURN();
+}
+#endif
+
+/* SPR micro-ops */
+/* 440 specific */
+void OPPROTO op_440_dlmzb (void)
+{
+    do_440_dlmzb();
+    RETURN();
+}
+
+void OPPROTO op_440_dlmzb_update_Rc (void)
+{
+    if (T0 == 8)
+        T0 = 0x2;
+    else if (T0 < 4)
+        T0 = 0x4;
+    else
+        T0 = 0x8;
+    RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_pir (void)
 {
     env->spr[SPR_PIR] = T0 & 0x0000000FUL;
     RETURN();
 }
+
+void OPPROTO op_load_403_pb (void)
+{
+    do_load_403_pb(PARAM1);
+    RETURN();
+}
+
+void OPPROTO op_store_403_pb (void)
+{
+    do_store_403_pb(PARAM1);
+    RETURN();
+}
+
+void OPPROTO op_load_40x_pit (void)
+{
+    T0 = load_40x_pit(env);
+    RETURN();
+}
+
+void OPPROTO op_store_40x_pit (void)
+{
+    store_40x_pit(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_store_40x_dbcr0 (void)
+{
+    store_40x_dbcr0(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_store_40x_sler (void)
+{
+    store_40x_sler(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_store_booke_tcr (void)
+{
+    store_booke_tcr(env, T0);
+    RETURN();
+}
+
+void OPPROTO op_store_booke_tsr (void)
+{
+    store_booke_tsr(env, T0);
+    RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension */
+void OPPROTO op_splatw_T1_64 (void)
+{
+    T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL);
+    RETURN();
+}
+
+void OPPROTO op_splatwi_T0_64 (void)
+{
+    uint64_t tmp = PARAM1;
+
+    T0_64 = (tmp << 32) | tmp;
+    RETURN();
+}
+
+void OPPROTO op_splatwi_T1_64 (void)
+{
+    uint64_t tmp = PARAM1;
+
+    T1_64 = (tmp << 32) | tmp;
+    RETURN();
+}
+
+void OPPROTO op_extsh_T1_64 (void)
+{
+    T1_64 = (int32_t)((int16_t)T1_64);
+    RETURN();
+}
+
+void OPPROTO op_sli16_T1_64 (void)
+{
+    T1_64 = T1_64 << 16;
+    RETURN();
+}
+
+void OPPROTO op_sli32_T1_64 (void)
+{
+    T1_64 = T1_64 << 32;
+    RETURN();
+}
+
+void OPPROTO op_srli32_T1_64 (void)
+{
+    T1_64 = T1_64 >> 32;
+    RETURN();
+}
+
+void OPPROTO op_evsel (void)
+{
+    do_evsel();
+    RETURN();
+}
+
+void OPPROTO op_evaddw (void)
+{
+    do_evaddw();
+    RETURN();
+}
+
+void OPPROTO op_evsubfw (void)
+{
+    do_evsubfw();
+    RETURN();
+}
+
+void OPPROTO op_evneg (void)
+{
+    do_evneg();
+    RETURN();
+}
+
+void OPPROTO op_evabs (void)
+{
+    do_evabs();
+    RETURN();
+}
+
+void OPPROTO op_evextsh (void)
+{
+    T0_64 = ((uint64_t)((int32_t)(int16_t)(T0_64 >> 32)) << 32) |
+        (uint64_t)((int32_t)(int16_t)T0_64);
+    RETURN();
+}
+
+void OPPROTO op_evextsb (void)
+{
+    T0_64 = ((uint64_t)((int32_t)(int8_t)(T0_64 >> 32)) << 32) |
+        (uint64_t)((int32_t)(int8_t)T0_64);
+    RETURN();
+}
+
+void OPPROTO op_evcntlzw (void)
+{
+    do_evcntlzw();
+    RETURN();
+}
+
+void OPPROTO op_evrndw (void)
+{
+    do_evrndw();
+    RETURN();
+}
+
+void OPPROTO op_brinc (void)
+{
+    do_brinc();
+    RETURN();
+}
+
+void OPPROTO op_evcntlsw (void)
+{
+    do_evcntlsw();
+    RETURN();
+}
+
+void OPPROTO op_evand (void)
+{
+    T0_64 &= T1_64;
+    RETURN();
+}
+
+void OPPROTO op_evandc (void)
+{
+    T0_64 &= ~T1_64;
+    RETURN();
+}
+
+void OPPROTO op_evor (void)
+{
+    T0_64 |= T1_64;
+    RETURN();
+}
+
+void OPPROTO op_evxor (void)
+{
+    T0_64 ^= T1_64;
+    RETURN();
+}
+
+void OPPROTO op_eveqv (void)
+{
+    T0_64 = ~(T0_64 ^ T1_64);
+    RETURN();
+}
+
+void OPPROTO op_evnor (void)
+{
+    T0_64 = ~(T0_64 | T1_64);
+    RETURN();
+}
+
+void OPPROTO op_evorc (void)
+{
+    T0_64 |= ~T1_64;
+    RETURN();
+}
+
+void OPPROTO op_evnand (void)
+{
+    T0_64 = ~(T0_64 & T1_64);
+    RETURN();
+}
+
+void OPPROTO op_evsrws (void)
+{
+    do_evsrws();
+    RETURN();
+}
+
+void OPPROTO op_evsrwu (void)
+{
+    do_evsrwu();
+    RETURN();
+}
+
+void OPPROTO op_evslw (void)
+{
+    do_evslw();
+    RETURN();
+}
+
+void OPPROTO op_evrlw (void)
+{
+    do_evrlw();
+    RETURN();
+}
+
+void OPPROTO op_evmergelo (void)
+{
+    T0_64 = (T0_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL);
+    RETURN();
+}
+
+void OPPROTO op_evmergehi (void)
+{
+    T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 >> 32);
+    RETURN();
+}
+
+void OPPROTO op_evmergelohi (void)
+{
+    T0_64 = (T0_64 << 32) | (T1_64 >> 32);
+    RETURN();
+}
+
+void OPPROTO op_evmergehilo (void)
+{
+    T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 & 0x00000000FFFFFFFFULL);
+    RETURN();
+}
+
+void OPPROTO op_evcmpgts (void)
+{
+    do_evcmpgts();
+    RETURN();
+}
+
+void OPPROTO op_evcmpgtu (void)
+{
+    do_evcmpgtu();
+    RETURN();
+}
+
+void OPPROTO op_evcmplts (void)
+{
+    do_evcmplts();
+    RETURN();
+}
+
+void OPPROTO op_evcmpltu (void)
+{
+    do_evcmpltu();
+    RETURN();
+}
+
+void OPPROTO op_evcmpeq (void)
+{
+    do_evcmpeq();
+    RETURN();
+}
+
+void OPPROTO op_evfssub (void)
+{
+    do_evfssub();
+    RETURN();
+}
+
+void OPPROTO op_evfsadd (void)
+{
+    do_evfsadd();
+    RETURN();
+}
+
+void OPPROTO op_evfsnabs (void)
+{
+    do_evfsnabs();
+    RETURN();
+}
+
+void OPPROTO op_evfsabs (void)
+{
+    do_evfsabs();
+    RETURN();
+}
+
+void OPPROTO op_evfsneg (void)
+{
+    do_evfsneg();
+    RETURN();
+}
+
+void OPPROTO op_evfsdiv (void)
+{
+    do_evfsdiv();
+    RETURN();
+}
+
+void OPPROTO op_evfsmul (void)
+{
+    do_evfsmul();
+    RETURN();
+}
+
+void OPPROTO op_evfscmplt (void)
+{
+    do_evfscmplt();
+    RETURN();
+}
+
+void OPPROTO op_evfscmpgt (void)
+{
+    do_evfscmpgt();
+    RETURN();
+}
+
+void OPPROTO op_evfscmpeq (void)
+{
+    do_evfscmpeq();
+    RETURN();
+}
+
+void OPPROTO op_evfscfsi (void)
+{
+    do_evfscfsi();
+    RETURN();
+}
+
+void OPPROTO op_evfscfui (void)
+{
+    do_evfscfui();
+    RETURN();
+}
+
+void OPPROTO op_evfscfsf (void)
+{
+    do_evfscfsf();
+    RETURN();
+}
+
+void OPPROTO op_evfscfuf (void)
+{
+    do_evfscfuf();
+    RETURN();
+}
+
+void OPPROTO op_evfsctsi (void)
+{
+    do_evfsctsi();
+    RETURN();
+}
+
+void OPPROTO op_evfsctui (void)
+{
+    do_evfsctui();
+    RETURN();
+}
+
+void OPPROTO op_evfsctsf (void)
+{
+    do_evfsctsf();
+    RETURN();
+}
+
+void OPPROTO op_evfsctuf (void)
+{
+    do_evfsctuf();
+    RETURN();
+}
+
+void OPPROTO op_evfsctuiz (void)
+{
+    do_evfsctuiz();
+    RETURN();
+}
+
+void OPPROTO op_evfsctsiz (void)
+{
+    do_evfsctsiz();
+    RETURN();
+}
+
+void OPPROTO op_evfststlt (void)
+{
+    do_evfststlt();
+    RETURN();
+}
+
+void OPPROTO op_evfststgt (void)
+{
+    do_evfststgt();
+    RETURN();
+}
+
+void OPPROTO op_evfststeq (void)
+{
+    do_evfststeq();
+    RETURN();
+}
+
+void OPPROTO op_efssub (void)
+{
+    T0_64 = _do_efssub(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efsadd (void)
+{
+    T0_64 = _do_efsadd(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efsnabs (void)
+{
+    T0_64 = _do_efsnabs(T0_64);
+    RETURN();
+}
+
+void OPPROTO op_efsabs (void)
+{
+    T0_64 = _do_efsabs(T0_64);
+    RETURN();
+}
+
+void OPPROTO op_efsneg (void)
+{
+    T0_64 = _do_efsneg(T0_64);
+    RETURN();
+}
+
+void OPPROTO op_efsdiv (void)
+{
+    T0_64 = _do_efsdiv(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efsmul (void)
+{
+    T0_64 = _do_efsmul(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efscmplt (void)
+{
+    do_efscmplt();
+    RETURN();
+}
+
+void OPPROTO op_efscmpgt (void)
+{
+    do_efscmpgt();
+    RETURN();
+}
+
+void OPPROTO op_efscfd (void)
+{
+    do_efscfd();
+    RETURN();
+}
+
+void OPPROTO op_efscmpeq (void)
+{
+    do_efscmpeq();
+    RETURN();
+}
+
+void OPPROTO op_efscfsi (void)
+{
+    do_efscfsi();
+    RETURN();
+}
+
+void OPPROTO op_efscfui (void)
+{
+    do_efscfui();
+    RETURN();
+}
+
+void OPPROTO op_efscfsf (void)
+{
+    do_efscfsf();
+    RETURN();
+}
+
+void OPPROTO op_efscfuf (void)
+{
+    do_efscfuf();
+    RETURN();
+}
+
+void OPPROTO op_efsctsi (void)
+{
+    do_efsctsi();
+    RETURN();
+}
+
+void OPPROTO op_efsctui (void)
+{
+    do_efsctui();
+    RETURN();
+}
+
+void OPPROTO op_efsctsf (void)
+{
+    do_efsctsf();
+    RETURN();
+}
+
+void OPPROTO op_efsctuf (void)
+{
+    do_efsctuf();
+    RETURN();
+}
+
+void OPPROTO op_efsctsiz (void)
+{
+    do_efsctsiz();
+    RETURN();
+}
+
+void OPPROTO op_efsctuiz (void)
+{
+    do_efsctuiz();
+    RETURN();
+}
+
+void OPPROTO op_efststlt (void)
+{
+    T0 = _do_efststlt(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efststgt (void)
+{
+    T0 = _do_efststgt(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efststeq (void)
+{
+    T0 = _do_efststeq(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efdsub (void)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = T0_64;
+    u2.u = T1_64;
+    u1.f = float64_sub(u1.f, u2.f, &env->spe_status);
+    T0_64 = u1.u;
+    RETURN();
+}
+
+void OPPROTO op_efdadd (void)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = T0_64;
+    u2.u = T1_64;
+    u1.f = float64_add(u1.f, u2.f, &env->spe_status);
+    T0_64 = u1.u;
+    RETURN();
+}
+
+void OPPROTO op_efdcfsid (void)
+{
+    do_efdcfsi();
+    RETURN();
+}
+
+void OPPROTO op_efdcfuid (void)
+{
+    do_efdcfui();
+    RETURN();
+}
+
+void OPPROTO op_efdnabs (void)
+{
+    T0_64 |= 0x8000000000000000ULL;
+    RETURN();
+}
+
+void OPPROTO op_efdabs (void)
+{
+    T0_64 &= ~0x8000000000000000ULL;
+    RETURN();
+}
+
+void OPPROTO op_efdneg (void)
+{
+    T0_64 ^= 0x8000000000000000ULL;
+    RETURN();
+}
+
+void OPPROTO op_efddiv (void)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = T0_64;
+    u2.u = T1_64;
+    u1.f = float64_div(u1.f, u2.f, &env->spe_status);
+    T0_64 = u1.u;
+    RETURN();
+}
+
+void OPPROTO op_efdmul (void)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = T0_64;
+    u2.u = T1_64;
+    u1.f = float64_mul(u1.f, u2.f, &env->spe_status);
+    T0_64 = u1.u;
+    RETURN();
+}
+
+void OPPROTO op_efdctsidz (void)
+{
+    do_efdctsiz();
+    RETURN();
+}
+
+void OPPROTO op_efdctuidz (void)
+{
+    do_efdctuiz();
+    RETURN();
+}
+
+void OPPROTO op_efdcmplt (void)
+{
+    do_efdcmplt();
+    RETURN();
+}
+
+void OPPROTO op_efdcmpgt (void)
+{
+    do_efdcmpgt();
+    RETURN();
+}
+
+void OPPROTO op_efdcfs (void)
+{
+    do_efdcfs();
+    RETURN();
+}
+
+void OPPROTO op_efdcmpeq (void)
+{
+    do_efdcmpeq();
+    RETURN();
+}
+
+void OPPROTO op_efdcfsi (void)
+{
+    do_efdcfsi();
+    RETURN();
+}
+
+void OPPROTO op_efdcfui (void)
+{
+    do_efdcfui();
+    RETURN();
+}
+
+void OPPROTO op_efdcfsf (void)
+{
+    do_efdcfsf();
+    RETURN();
+}
+
+void OPPROTO op_efdcfuf (void)
+{
+    do_efdcfuf();
+    RETURN();
+}
+
+void OPPROTO op_efdctsi (void)
+{
+    do_efdctsi();
+    RETURN();
+}
+
+void OPPROTO op_efdctui (void)
+{
+    do_efdctui();
+    RETURN();
+}
+
+void OPPROTO op_efdctsf (void)
+{
+    do_efdctsf();
+    RETURN();
+}
+
+void OPPROTO op_efdctuf (void)
+{
+    do_efdctuf();
+    RETURN();
+}
+
+void OPPROTO op_efdctuiz (void)
+{
+    do_efdctuiz();
+    RETURN();
+}
+
+void OPPROTO op_efdctsiz (void)
+{
+    do_efdctsiz();
+    RETURN();
+}
+
+void OPPROTO op_efdtstlt (void)
+{
+    T0 = _do_efdtstlt(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efdtstgt (void)
+{
+    T0 = _do_efdtstgt(T0_64, T1_64);
+    RETURN();
+}
+
+void OPPROTO op_efdtsteq (void)
+{
+    T0 = _do_efdtsteq(T0_64, T1_64);
+    RETURN();
+}
+#endif /* defined(TARGET_PPCEMB) */
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index e949eb4..8bb93ed 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation helpers for qemu.
- * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,29 +19,26 @@
  */
 #include "exec.h"
 
+#include "op_helper.h"
+
 #define MEMSUFFIX _raw
+#include "op_helper.h"
 #include "op_helper_mem.h"
 #if !defined(CONFIG_USER_ONLY)
 #define MEMSUFFIX _user
+#include "op_helper.h"
 #include "op_helper_mem.h"
 #define MEMSUFFIX _kernel
+#include "op_helper.h"
 #include "op_helper_mem.h"
 #endif
 
 //#define DEBUG_OP
 //#define DEBUG_EXCEPTIONS
-//#define FLUSH_ALL_TLBS
-
-#define Ts0 (long)((target_long)T0)
-#define Ts1 (long)((target_long)T1)
-#define Ts2 (long)((target_long)T2)
+//#define DEBUG_SOFTWARE_TLB
 
 /*****************************************************************************/
 /* Exceptions processing helpers */
-void cpu_loop_exit(void)
-{
-    longjmp(env->jmp_env, 1);
-}
 
 void do_raise_exception_err (uint32_t exception, int error_code)
 {
@@ -49,140 +46,359 @@
     printf("Raise exception %3x code : %d\n", exception, error_code);
 #endif
     switch (exception) {
-    case EXCP_PROGRAM:
-	if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
-	    return;
-	break;
+    case POWERPC_EXCP_PROGRAM:
+        if (error_code == POWERPC_EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
+            return;
+        break;
     default:
-	break;
-}
+        break;
+    }
     env->exception_index = exception;
     env->error_code = error_code;
-        cpu_loop_exit();
-    }
+    cpu_loop_exit();
+}
 
 void do_raise_exception (uint32_t exception)
 {
     do_raise_exception_err(exception, 0);
 }
 
-/*****************************************************************************/
-/* Fixed point operations helpers */
-void do_addo (void)
+void cpu_dump_EA (target_ulong EA);
+void do_print_mem_EA (target_ulong EA)
 {
-    T2 = T0;
-    T0 += T1;
-    if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
-        xer_ov = 0;
-    } else {
-        xer_so = 1;
-        xer_ov = 1;
+    cpu_dump_EA(EA);
+}
+
+/*****************************************************************************/
+/* Registers load and stores */
+void do_load_cr (void)
+{
+    T0 = (env->crf[0] << 28) |
+        (env->crf[1] << 24) |
+        (env->crf[2] << 20) |
+        (env->crf[3] << 16) |
+        (env->crf[4] << 12) |
+        (env->crf[5] << 8) |
+        (env->crf[6] << 4) |
+        (env->crf[7] << 0);
+}
+
+void do_store_cr (uint32_t mask)
+{
+    int i, sh;
+
+    for (i = 0, sh = 7; i < 8; i++, sh--) {
+        if (mask & (1 << sh))
+            env->crf[i] = (T0 >> (sh * 4)) & 0xFUL;
     }
 }
 
-void do_addco (void)
+void do_load_xer (void)
 {
-    T2 = T0;
-    T0 += T1;
-    if (likely(T0 >= T2)) {
-        xer_ca = 0;
-    } else {
-        xer_ca = 1;
+    T0 = (xer_so << XER_SO) |
+        (xer_ov << XER_OV) |
+        (xer_ca << XER_CA) |
+        (xer_bc << XER_BC) |
+        (xer_cmp << XER_CMP);
+}
+
+void do_store_xer (void)
+{
+    xer_so = (T0 >> XER_SO) & 0x01;
+    xer_ov = (T0 >> XER_OV) & 0x01;
+    xer_ca = (T0 >> XER_CA) & 0x01;
+    xer_cmp = (T0 >> XER_CMP) & 0xFF;
+    xer_bc = (T0 >> XER_BC) & 0x7F;
+}
+
+#if defined(TARGET_PPC64)
+void do_store_pri (int prio)
+{
+    env->spr[SPR_PPR] &= ~0x001C000000000000ULL;
+    env->spr[SPR_PPR] |= ((uint64_t)prio & 0x7) << 50;
+}
+#endif
+
+void do_load_fpscr (void)
+{
+    /* The 32 MSB of the target fpr are undefined.
+     * They'll be zero...
+     */
+    union {
+        float64 d;
+        struct {
+            uint32_t u[2];
+        } s;
+    } u;
+    int i;
+
+#if defined(WORDS_BIGENDIAN)
+#define WORD0 0
+#define WORD1 1
+#else
+#define WORD0 1
+#define WORD1 0
+#endif
+    u.s.u[WORD0] = 0;
+    u.s.u[WORD1] = 0;
+    for (i = 0; i < 8; i++)
+        u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
+    FT0 = u.d;
+}
+
+void do_store_fpscr (uint32_t mask)
+{
+    /*
+     * We use only the 32 LSB of the incoming fpr
+     */
+    union {
+        double d;
+        struct {
+            uint32_t u[2];
+        } s;
+    } u;
+    int i, rnd_type;
+
+    u.d = FT0;
+    if (mask & 0x80)
+        env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
+    for (i = 1; i < 7; i++) {
+        if (mask & (1 << (7 - i)))
+            env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
     }
-    if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
-        xer_ov = 0;
-    } else {
-        xer_so = 1;
-        xer_ov = 1;
+    /* TODO: update FEX & VX */
+    /* Set rounding mode */
+    switch (env->fpscr[0] & 0x3) {
+    case 0:
+        /* Best approximation (round to nearest) */
+        rnd_type = float_round_nearest_even;
+        break;
+    case 1:
+        /* Smaller magnitude (round toward zero) */
+        rnd_type = float_round_to_zero;
+        break;
+    case 2:
+        /* Round toward +infinite */
+        rnd_type = float_round_up;
+        break;
+    default:
+    case 3:
+        /* Round toward -infinite */
+        rnd_type = float_round_down;
+        break;
+    }
+    set_float_rounding_mode(rnd_type, &env->fp_status);
+}
+
+target_ulong ppc_load_dump_spr (int sprn)
+{
+    if (loglevel != 0) {
+        fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
+                sprn, sprn, env->spr[sprn]);
+    }
+
+    return env->spr[sprn];
+}
+
+void ppc_store_dump_spr (int sprn, target_ulong val)
+{
+    if (loglevel != 0) {
+        fprintf(logfile, "Write SPR %d %03x => " ADDRX " <= " ADDRX "\n",
+                sprn, sprn, env->spr[sprn], val);
+    }
+    env->spr[sprn] = val;
+}
+
+/*****************************************************************************/
+/* Fixed point operations helpers */
+#if defined(TARGET_PPC64)
+static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
+{
+    *plow += a;
+    /* carry test */
+    if (*plow < a)
+        (*phigh)++;
+    *phigh += b;
+}
+
+static void neg128 (uint64_t *plow, uint64_t *phigh)
+{
+    *plow = ~*plow;
+    *phigh = ~*phigh;
+    add128(plow, phigh, 1, 0);
+}
+
+static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
+{
+    uint32_t a0, a1, b0, b1;
+    uint64_t v;
+
+    a0 = a;
+    a1 = a >> 32;
+
+    b0 = b;
+    b1 = b >> 32;
+
+    v = (uint64_t)a0 * (uint64_t)b0;
+    *plow = v;
+    *phigh = 0;
+
+    v = (uint64_t)a0 * (uint64_t)b1;
+    add128(plow, phigh, v << 32, v >> 32);
+
+    v = (uint64_t)a1 * (uint64_t)b0;
+    add128(plow, phigh, v << 32, v >> 32);
+
+    v = (uint64_t)a1 * (uint64_t)b1;
+    *phigh += v;
+#if defined(DEBUG_MULDIV)
+    printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
+           a, b, *phigh, *plow);
+#endif
+}
+
+void do_mul64 (uint64_t *plow, uint64_t *phigh)
+{
+    mul64(plow, phigh, T0, T1);
+}
+
+static void imul64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
+{
+    int sa, sb;
+
+    sa = (a < 0);
+    if (sa)
+        a = -a;
+    sb = (b < 0);
+    if (sb)
+        b = -b;
+    mul64(plow, phigh, a, b);
+    if (sa ^ sb) {
+        neg128(plow, phigh);
     }
 }
 
+void do_imul64 (uint64_t *plow, uint64_t *phigh)
+{
+    imul64(plow, phigh, T0, T1);
+}
+#endif
+
 void do_adde (void)
 {
     T2 = T0;
     T0 += T1 + xer_ca;
-    if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
+    if (likely(!((uint32_t)T0 < (uint32_t)T2 ||
+                 (xer_ca == 1 && (uint32_t)T0 == (uint32_t)T2)))) {
         xer_ca = 0;
     } else {
         xer_ca = 1;
     }
 }
 
-void do_addeo (void)
+#if defined(TARGET_PPC64)
+void do_adde_64 (void)
 {
     T2 = T0;
     T0 += T1 + xer_ca;
-    if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
+    if (likely(!((uint64_t)T0 < (uint64_t)T2 ||
+                 (xer_ca == 1 && (uint64_t)T0 == (uint64_t)T2)))) {
         xer_ca = 0;
     } else {
         xer_ca = 1;
     }
-    if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
-        xer_ov = 0;
-    } else {
-        xer_so = 1;
-        xer_ov = 1;
-    }
 }
+#endif
 
 void do_addmeo (void)
 {
     T1 = T0;
     T0 += xer_ca + (-1);
-    if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) {
+    if (likely(!((uint32_t)T1 &
+                 ((uint32_t)T1 ^ (uint32_t)T0) & (1UL << 31)))) {
         xer_ov = 0;
     } else {
-        xer_so = 1;
         xer_ov = 1;
+        xer_so = 1;
     }
     if (likely(T1 != 0))
         xer_ca = 1;
 }
 
-void do_addzeo (void)
+#if defined(TARGET_PPC64)
+void do_addmeo_64 (void)
 {
     T1 = T0;
-    T0 += xer_ca;
-    if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) {
+    T0 += xer_ca + (-1);
+    if (likely(!((uint64_t)T1 &
+                 ((uint64_t)T1 ^ (uint64_t)T0) & (1ULL << 63)))) {
         xer_ov = 0;
     } else {
-        xer_so = 1;
         xer_ov = 1;
+        xer_so = 1;
     }
-    if (likely(T0 >= T1)) {
-        xer_ca = 0;
-    } else {
+    if (likely(T1 != 0))
         xer_ca = 1;
-    }
 }
+#endif
 
 void do_divwo (void)
 {
-    if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) {
+    if (likely(!(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) ||
+                 (int32_t)T1 == 0))) {
         xer_ov = 0;
-        T0 = (Ts0 / Ts1);
+        T0 = (int32_t)T0 / (int32_t)T1;
     } else {
-        xer_so = 1;
         xer_ov = 1;
+        xer_so = 1;
         T0 = (-1) * ((uint32_t)T0 >> 31);
     }
 }
 
+#if defined(TARGET_PPC64)
+void do_divdo (void)
+{
+    if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1ULL) ||
+                 (int64_t)T1 == 0))) {
+        xer_ov = 0;
+        T0 = (int64_t)T0 / (int64_t)T1;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+        T0 = (-1ULL) * ((uint64_t)T0 >> 63);
+    }
+}
+#endif
+
 void do_divwuo (void)
 {
     if (likely((uint32_t)T1 != 0)) {
         xer_ov = 0;
         T0 = (uint32_t)T0 / (uint32_t)T1;
     } else {
-        xer_so = 1;
         xer_ov = 1;
+        xer_so = 1;
         T0 = 0;
     }
 }
 
+#if defined(TARGET_PPC64)
+void do_divduo (void)
+{
+    if (likely((uint64_t)T1 != 0)) {
+        xer_ov = 0;
+        T0 = (uint64_t)T0 / (uint64_t)T1;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+        T0 = 0;
+    }
+}
+#endif
+
 void do_mullwo (void)
 {
-    int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
+    int64_t res = (int64_t)T0 * (int64_t)T1;
 
     if (likely((int32_t)res == res)) {
         xer_ov = 0;
@@ -193,133 +409,232 @@
     T0 = (int32_t)res;
 }
 
+#if defined(TARGET_PPC64)
+void do_mulldo (void)
+{
+    int64_t th;
+    uint64_t tl;
+
+    do_imul64(&tl, &th);
+    if (likely(th == 0)) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
+    T0 = (int64_t)tl;
+}
+#endif
+
 void do_nego (void)
 {
-    if (likely(T0 != INT32_MIN)) {
+    if (likely((int32_t)T0 != INT32_MIN)) {
         xer_ov = 0;
-        T0 = -Ts0;
+        T0 = -(int32_t)T0;
     } else {
         xer_ov = 1;
         xer_so = 1;
     }
 }
 
-void do_subfo (void)
+#if defined(TARGET_PPC64)
+void do_nego_64 (void)
 {
-    T2 = T0;
-    T0 = T1 - T0;
-    if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
+    if (likely((int64_t)T0 != INT64_MIN)) {
         xer_ov = 0;
+        T0 = -(int64_t)T0;
     } else {
-        xer_so = 1;
         xer_ov = 1;
-    }
-    RETURN();
-}
-
-void do_subfco (void)
-{
-    T2 = T0;
-    T0 = T1 - T0;
-    if (likely(T0 > T1)) {
-        xer_ca = 0;
-    } else {
-        xer_ca = 1;
-    }
-    if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
-        xer_ov = 0;
-    } else {
         xer_so = 1;
-        xer_ov = 1;
     }
 }
+#endif
 
 void do_subfe (void)
 {
     T0 = T1 + ~T0 + xer_ca;
-    if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
+    if (likely((uint32_t)T0 >= (uint32_t)T1 &&
+               (xer_ca == 0 || (uint32_t)T0 != (uint32_t)T1))) {
         xer_ca = 0;
     } else {
         xer_ca = 1;
     }
 }
 
-void do_subfeo (void)
+#if defined(TARGET_PPC64)
+void do_subfe_64 (void)
 {
-    T2 = T0;
     T0 = T1 + ~T0 + xer_ca;
-    if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) {
-        xer_ov = 0;
-    } else {
-        xer_so = 1;
-        xer_ov = 1;
-    }
-    if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
+    if (likely((uint64_t)T0 >= (uint64_t)T1 &&
+               (xer_ca == 0 || (uint64_t)T0 != (uint64_t)T1))) {
         xer_ca = 0;
     } else {
         xer_ca = 1;
     }
 }
+#endif
 
 void do_subfmeo (void)
 {
     T1 = T0;
     T0 = ~T0 + xer_ca - 1;
-    if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) {
+    if (likely(!((uint32_t)~T1 & ((uint32_t)~T1 ^ (uint32_t)T0) &
+                 (1UL << 31)))) {
         xer_ov = 0;
     } else {
-        xer_so = 1;
         xer_ov = 1;
+        xer_so = 1;
     }
-    if (likely(T1 != -1))
+    if (likely((uint32_t)T1 != UINT32_MAX))
         xer_ca = 1;
 }
 
+#if defined(TARGET_PPC64)
+void do_subfmeo_64 (void)
+{
+    T1 = T0;
+    T0 = ~T0 + xer_ca - 1;
+    if (likely(!((uint64_t)~T1 & ((uint64_t)~T1 ^ (uint64_t)T0) &
+                 (1ULL << 63)))) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
+    if (likely((uint64_t)T1 != UINT64_MAX))
+        xer_ca = 1;
+}
+#endif
+
 void do_subfzeo (void)
 {
     T1 = T0;
     T0 = ~T0 + xer_ca;
-    if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) {
+    if (likely(!(((uint32_t)~T1 ^ UINT32_MAX) &
+                 ((uint32_t)(~T1) ^ (uint32_t)T0) & (1UL << 31)))) {
         xer_ov = 0;
     } else {
         xer_ov = 1;
         xer_so = 1;
     }
-    if (likely(T0 >= ~T1)) {
+    if (likely((uint32_t)T0 >= (uint32_t)~T1)) {
         xer_ca = 0;
     } else {
         xer_ca = 1;
     }
 }
 
+#if defined(TARGET_PPC64)
+void do_subfzeo_64 (void)
+{
+    T1 = T0;
+    T0 = ~T0 + xer_ca;
+    if (likely(!(((uint64_t)~T1 ^ UINT64_MAX) &
+                 ((uint64_t)(~T1) ^ (uint64_t)T0) & (1ULL << 63)))) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
+    if (likely((uint64_t)T0 >= (uint64_t)~T1)) {
+        xer_ca = 0;
+    } else {
+        xer_ca = 1;
+    }
+}
+#endif
+
 /* shift right arithmetic helper */
 void do_sraw (void)
 {
     int32_t ret;
 
     if (likely(!(T1 & 0x20UL))) {
-        if (likely(T1 != 0)) {
+        if (likely((uint32_t)T1 != 0)) {
             ret = (int32_t)T0 >> (T1 & 0x1fUL);
             if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
-    xer_ca = 0;
+                xer_ca = 0;
             } else {
-            xer_ca = 1;
+                xer_ca = 1;
             }
         } else {
-        ret = T0;
+            ret = T0;
             xer_ca = 0;
         }
     } else {
         ret = (-1) * ((uint32_t)T0 >> 31);
         if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
             xer_ca = 0;
-    } else {
+        } else {
             xer_ca = 1;
-    }
+        }
     }
     T0 = ret;
 }
 
+#if defined(TARGET_PPC64)
+void do_srad (void)
+{
+    int64_t ret;
+
+    if (likely(!(T1 & 0x40UL))) {
+        if (likely((uint64_t)T1 != 0)) {
+            ret = (int64_t)T0 >> (T1 & 0x3FUL);
+            if (likely(ret >= 0 || ((int64_t)T0 & ((1 << T1) - 1)) == 0)) {
+                xer_ca = 0;
+            } else {
+                xer_ca = 1;
+            }
+        } else {
+            ret = T0;
+            xer_ca = 0;
+        }
+    } else {
+        ret = (-1) * ((uint64_t)T0 >> 63);
+        if (likely(ret >= 0 || ((uint64_t)T0 & ~0x8000000000000000ULL) == 0)) {
+            xer_ca = 0;
+        } else {
+            xer_ca = 1;
+        }
+    }
+    T0 = ret;
+}
+#endif
+
+static inline int popcnt (uint32_t val)
+{
+    int i;
+
+    for (i = 0; val != 0;)
+        val = val ^ (val - 1);
+
+    return i;
+}
+
+void do_popcntb (void)
+{
+    uint32_t ret;
+    int i;
+
+    ret = 0;
+    for (i = 0; i < 32; i += 8)
+        ret |= popcnt((T0 >> i) & 0xFF) << i;
+    T0 = ret;
+}
+
+#if defined(TARGET_PPC64)
+void do_popcntb_64 (void)
+{
+    uint64_t ret;
+    int i;
+
+    ret = 0;
+    for (i = 0; i < 64; i += 8)
+        ret |= popcnt((T0 >> i) & 0xFF) << i;
+    T0 = ret;
+}
+#endif
+
 /*****************************************************************************/
 /* Floating point operations helpers */
 void do_fctiw (void)
@@ -329,11 +644,13 @@
         uint64_t i;
     } p;
 
-    /* XXX: higher bits are not supposed to be significant.
-     *      to make tests easier, return the same as a real PowerPC 750 (aka G3)
-     */
     p.i = float64_to_int32(FT0, &env->fp_status);
+#if USE_PRECISE_EMULATION
+    /* XXX: higher bits are not supposed to be significant.
+     *     to make tests easier, return the same as a real PowerPC 750 (aka G3)
+     */
     p.i |= 0xFFF80000ULL << 32;
+#endif
     FT0 = p.d;
 }
 
@@ -344,26 +661,162 @@
         uint64_t i;
     } p;
 
-    /* XXX: higher bits are not supposed to be significant.
-     *      to make tests easier, return the same as a real PowerPC 750 (aka G3)
-     */
     p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
+#if USE_PRECISE_EMULATION
+    /* XXX: higher bits are not supposed to be significant.
+     *     to make tests easier, return the same as a real PowerPC 750 (aka G3)
+     */
     p.i |= 0xFFF80000ULL << 32;
+#endif
     FT0 = p.d;
 }
 
+#if defined(TARGET_PPC64)
+void do_fcfid (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.d = FT0;
+    FT0 = int64_to_float64(p.i, &env->fp_status);
+}
+
+void do_fctid (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = float64_to_int64(FT0, &env->fp_status);
+    FT0 = p.d;
+}
+
+void do_fctidz (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status);
+    FT0 = p.d;
+}
+
+#endif
+
+static inline void do_fri (int rounding_mode)
+{
+    int curmode;
+
+    curmode = env->fp_status.float_rounding_mode;
+    set_float_rounding_mode(rounding_mode, &env->fp_status);
+    FT0 = float64_round_to_int(FT0, &env->fp_status);
+    set_float_rounding_mode(curmode, &env->fp_status);
+}
+
+void do_frin (void)
+{
+    do_fri(float_round_nearest_even);
+}
+
+void do_friz (void)
+{
+    do_fri(float_round_to_zero);
+}
+
+void do_frip (void)
+{
+    do_fri(float_round_up);
+}
+
+void do_frim (void)
+{
+    do_fri(float_round_down);
+}
+
+#if USE_PRECISE_EMULATION
+void do_fmadd (void)
+{
+#ifdef FLOAT128
+    float128 ft0_128, ft1_128;
+
+    ft0_128 = float64_to_float128(FT0, &env->fp_status);
+    ft1_128 = float64_to_float128(FT1, &env->fp_status);
+    ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+    ft1_128 = float64_to_float128(FT2, &env->fp_status);
+    ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+    FT0 = float128_to_float64(ft0_128, &env->fp_status);
+#else
+    /* This is OK on x86 hosts */
+    FT0 = (FT0 * FT1) + FT2;
+#endif
+}
+
+void do_fmsub (void)
+{
+#ifdef FLOAT128
+    float128 ft0_128, ft1_128;
+
+    ft0_128 = float64_to_float128(FT0, &env->fp_status);
+    ft1_128 = float64_to_float128(FT1, &env->fp_status);
+    ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+    ft1_128 = float64_to_float128(FT2, &env->fp_status);
+    ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+    FT0 = float128_to_float64(ft0_128, &env->fp_status);
+#else
+    /* This is OK on x86 hosts */
+    FT0 = (FT0 * FT1) - FT2;
+#endif
+}
+#endif /* USE_PRECISE_EMULATION */
+
 void do_fnmadd (void)
 {
+#if USE_PRECISE_EMULATION
+#ifdef FLOAT128
+    float128 ft0_128, ft1_128;
+
+    ft0_128 = float64_to_float128(FT0, &env->fp_status);
+    ft1_128 = float64_to_float128(FT1, &env->fp_status);
+    ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+    ft1_128 = float64_to_float128(FT2, &env->fp_status);
+    ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+    FT0 = float128_to_float64(ft0_128, &env->fp_status);
+#else
+    /* This is OK on x86 hosts */
+    FT0 = (FT0 * FT1) + FT2;
+#endif
+#else
     FT0 = float64_mul(FT0, FT1, &env->fp_status);
     FT0 = float64_add(FT0, FT2, &env->fp_status);
+#endif
     if (likely(!isnan(FT0)))
         FT0 = float64_chs(FT0);
 }
 
 void do_fnmsub (void)
 {
+#if USE_PRECISE_EMULATION
+#ifdef FLOAT128
+    float128 ft0_128, ft1_128;
+
+    ft0_128 = float64_to_float128(FT0, &env->fp_status);
+    ft1_128 = float64_to_float128(FT1, &env->fp_status);
+    ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+    ft1_128 = float64_to_float128(FT2, &env->fp_status);
+    ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+    FT0 = float128_to_float64(ft0_128, &env->fp_status);
+#else
+    /* This is OK on x86 hosts */
+    FT0 = (FT0 * FT1) - FT2;
+#endif
+#else
     FT0 = float64_mul(FT0, FT1, &env->fp_status);
     FT0 = float64_sub(FT0, FT2, &env->fp_status);
+#endif
     if (likely(!isnan(FT0)))
         FT0 = float64_chs(FT0);
 }
@@ -373,6 +826,32 @@
     FT0 = float64_sqrt(FT0, &env->fp_status);
 }
 
+void do_fre (void)
+{
+    union {
+        double d;
+        uint64_t i;
+    } p;
+
+    if (likely(isnormal(FT0))) {
+        FT0 = float64_div(1.0, FT0, &env->fp_status);
+    } else {
+        p.d = FT0;
+        if (p.i == 0x8000000000000000ULL) {
+            p.i = 0xFFF0000000000000ULL;
+        } else if (p.i == 0x0000000000000000ULL) {
+            p.i = 0x7FF0000000000000ULL;
+        } else if (isnan(FT0)) {
+            p.i = 0x7FF8000000000000ULL;
+        } else if (FT0 < 0.0) {
+            p.i = 0x8000000000000000ULL;
+        } else {
+            p.i = 0x0000000000000000ULL;
+        }
+        FT0 = p.d;
+    }
+}
+
 void do_fres (void)
 {
     union {
@@ -381,7 +860,12 @@
     } p;
 
     if (likely(isnormal(FT0))) {
-        FT0 = (float)(1.0 / FT0);
+#if USE_PRECISE_EMULATION
+        FT0 = float64_div(1.0, FT0, &env->fp_status);
+        FT0 = float64_to_float32(FT0, &env->fp_status);
+#else
+        FT0 = float32_div(1.0, FT0, &env->fp_status);
+#endif
     } else {
         p.d = FT0;
         if (p.i == 0x8000000000000000ULL) {
@@ -467,8 +951,8 @@
     } else {
         T0 = 0x01UL;
         env->fpscr[4] |= 0x1;
-        /* I don't know how to test "quiet" nan... */
-        if (0 /* || ! quiet_nan(...) */) {
+        if (!float64_is_signaling_nan(FT0) || !float64_is_signaling_nan(FT1)) {
+            /* Quiet NaN case */
             env->fpscr[6] |= 0x1;
             if (!(env->fpscr[1] & 0x8))
                 env->fpscr[4] |= 0x8;
@@ -479,62 +963,1327 @@
     env->fpscr[3] = T0;
 }
 
+#if !defined (CONFIG_USER_ONLY)
+void cpu_dump_rfi (target_ulong RA, target_ulong msr);
 void do_rfi (void)
 {
-    env->nip = env->spr[SPR_SRR0] & ~0x00000003;
-    T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
-    do_store_msr(env, T0);
+#if defined(TARGET_PPC64)
+    if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) {
+        env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003);
+        do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+    } else {
+        env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
+        ppc_store_msr_32(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+    }
+#else
+    env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
+    do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+#endif
 #if defined (DEBUG_OP)
-    dump_rfi();
+    cpu_dump_rfi(env->nip, do_load_msr(env));
 #endif
     env->interrupt_request |= CPU_INTERRUPT_EXITTB;
 }
 
-void do_tw (uint32_t cmp, int flags)
+#if defined(TARGET_PPC64)
+void do_rfid (void)
 {
-    if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
-                  (Ts0 > (int32_t)cmp && (flags & 0x08)) ||
-                  (Ts0 == (int32_t)cmp && (flags & 0x04)) ||
-                  (T0 < cmp && (flags & 0x02)) ||
-                  (T0 > cmp && (flags & 0x01)))))
-        do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
+    if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) {
+        env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003);
+        do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+    } else {
+        env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
+        do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+    }
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+#endif
+#if defined(TARGET_PPC64H)
+void do_hrfid (void)
+{
+    if (env->spr[SPR_HSRR1] & (1ULL << MSR_SF)) {
+        env->nip = (uint64_t)(env->spr[SPR_HSRR0] & ~0x00000003);
+        do_store_msr(env, (uint64_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL));
+    } else {
+        env->nip = (uint32_t)(env->spr[SPR_HSRR0] & ~0x00000003);
+        do_store_msr(env, (uint32_t)(env->spr[SPR_HSRR1] & ~0xFFFF0000UL));
+    }
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+#endif
+#endif
+
+void do_tw (int flags)
+{
+    if (!likely(!(((int32_t)T0 < (int32_t)T1 && (flags & 0x10)) ||
+                  ((int32_t)T0 > (int32_t)T1 && (flags & 0x08)) ||
+                  ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) ||
+                  ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) ||
+                  ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) {
+        do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+    }
 }
 
-/* Instruction cache invalidation helper */
-void do_icbi (void)
-{
-    uint32_t tmp;
-    /* Invalidate one cache line :
-     * PowerPC specification says this is to be treated like a load
-     * (not a fetch) by the MMU. To be sure it will be so,
-     * do the load "by hand".
-     */
 #if defined(TARGET_PPC64)
-    if (!msr_sf)
-        T0 &= 0xFFFFFFFFULL;
+void do_td (int flags)
+{
+    if (!likely(!(((int64_t)T0 < (int64_t)T1 && (flags & 0x10)) ||
+                  ((int64_t)T0 > (int64_t)T1 && (flags & 0x08)) ||
+                  ((int64_t)T0 == (int64_t)T1 && (flags & 0x04)) ||
+                  ((uint64_t)T0 < (uint64_t)T1 && (flags & 0x02)) ||
+                  ((uint64_t)T0 > (uint64_t)T1 && (flags & 0x01)))))
+        do_raise_exception_err(POWERPC_EXCP_PROGRAM, POWERPC_EXCP_TRAP);
+}
 #endif
-    tmp = ldl_kernel(T0);
-    T0 &= ~(ICACHE_LINE_SIZE - 1);
-    tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
+
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+void do_POWER_abso (void)
+{
+    if ((uint32_t)T0 == INT32_MIN) {
+        T0 = INT32_MAX;
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        T0 = -T0;
+        xer_ov = 0;
+    }
+}
+
+void do_POWER_clcs (void)
+{
+    switch (T0) {
+    case 0x0CUL:
+        /* Instruction cache line size */
+        T0 = ICACHE_LINE_SIZE;
+        break;
+    case 0x0DUL:
+        /* Data cache line size */
+        T0 = DCACHE_LINE_SIZE;
+        break;
+    case 0x0EUL:
+        /* Minimum cache line size */
+        T0 = ICACHE_LINE_SIZE < DCACHE_LINE_SIZE ?
+            ICACHE_LINE_SIZE : DCACHE_LINE_SIZE;
+        break;
+    case 0x0FUL:
+        /* Maximum cache line size */
+        T0 = ICACHE_LINE_SIZE > DCACHE_LINE_SIZE ?
+            ICACHE_LINE_SIZE : DCACHE_LINE_SIZE;
+        break;
+    default:
+        /* Undefined */
+        break;
+    }
+}
+
+void do_POWER_div (void)
+{
+    uint64_t tmp;
+
+    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) {
+        T0 = (long)((-1) * (T0 >> 31));
+        env->spr[SPR_MQ] = 0;
+    } else {
+        tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
+        env->spr[SPR_MQ] = tmp % T1;
+        T0 = tmp / (int32_t)T1;
+    }
+}
+
+void do_POWER_divo (void)
+{
+    int64_t tmp;
+
+    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) {
+        T0 = (long)((-1) * (T0 >> 31));
+        env->spr[SPR_MQ] = 0;
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
+        env->spr[SPR_MQ] = tmp % T1;
+        tmp /= (int32_t)T1;
+        if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
+            xer_ov = 1;
+            xer_so = 1;
+        } else {
+            xer_ov = 0;
+        }
+        T0 = tmp;
+    }
+}
+
+void do_POWER_divs (void)
+{
+    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) {
+        T0 = (long)((-1) * (T0 >> 31));
+        env->spr[SPR_MQ] = 0;
+    } else {
+        env->spr[SPR_MQ] = T0 % T1;
+        T0 = (int32_t)T0 / (int32_t)T1;
+    }
+}
+
+void do_POWER_divso (void)
+{
+    if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) {
+        T0 = (long)((-1) * (T0 >> 31));
+        env->spr[SPR_MQ] = 0;
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        T0 = (int32_t)T0 / (int32_t)T1;
+        env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
+        xer_ov = 0;
+    }
+}
+
+void do_POWER_dozo (void)
+{
+    if ((int32_t)T1 > (int32_t)T0) {
+        T2 = T0;
+        T0 = T1 - T0;
+        if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
+            ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) {
+            xer_ov = 1;
+            xer_so = 1;
+        } else {
+            xer_ov = 0;
+        }
+    } else {
+        T0 = 0;
+        xer_ov = 0;
+    }
+}
+
+void do_POWER_maskg (void)
+{
+    uint32_t ret;
+
+    if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
+        ret = -1;
+    } else {
+        ret = (((uint32_t)(-1)) >> ((uint32_t)T0)) ^
+            (((uint32_t)(-1) >> ((uint32_t)T1)) >> 1);
+        if ((uint32_t)T0 > (uint32_t)T1)
+            ret = ~ret;
+    }
+    T0 = ret;
+}
+
+void do_POWER_mulo (void)
+{
+    uint64_t tmp;
+
+    tmp = (uint64_t)T0 * (uint64_t)T1;
+    env->spr[SPR_MQ] = tmp >> 32;
+    T0 = tmp;
+    if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
+        xer_ov = 1;
+        xer_so = 1;
+    } else {
+        xer_ov = 0;
+    }
+}
+
+#if !defined (CONFIG_USER_ONLY)
+void do_POWER_rac (void)
+{
+#if 0
+    mmu_ctx_t ctx;
+
+    /* We don't have to generate many instances of this instruction,
+     * as rac is supervisor only.
+     */
+    if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT, 1) == 0)
+        T0 = ctx.raddr;
+#endif
+}
+
+void do_POWER_rfsvc (void)
+{
+    env->nip = env->lr & ~0x00000003UL;
+    T0 = env->ctr & 0x0000FFFFUL;
+    do_store_msr(env, T0);
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+    env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+
+/* PowerPC 601 BAT management helper */
+void do_store_601_batu (int nr)
+{
+    do_store_ibatu(env, nr, (uint32_t)T0);
+    env->DBAT[0][nr] = env->IBAT[0][nr];
+    env->DBAT[1][nr] = env->IBAT[1][nr];
+}
+#endif
+
+/*****************************************************************************/
+/* 602 specific instructions */
+/* mfrom is the most crazy instruction ever seen, imho ! */
+/* Real implementation uses a ROM table. Do the same */
+#define USE_MFROM_ROM_TABLE
+void do_op_602_mfrom (void)
+{
+    if (likely(T0 < 602)) {
+#if defined(USE_MFROM_ROM_TABLE)
+#include "mfrom_table.c"
+        T0 = mfrom_ROM_table[T0];
+#else
+        double d;
+        /* Extremly decomposed:
+         *                    -T0 / 256
+         * T0 = 256 * log10(10          + 1.0) + 0.5
+         */
+        d = T0;
+        d = float64_div(d, 256, &env->fp_status);
+        d = float64_chs(d);
+        d = exp10(d); // XXX: use float emulation function
+        d = float64_add(d, 1.0, &env->fp_status);
+        d = log10(d); // XXX: use float emulation function
+        d = float64_mul(d, 256, &env->fp_status);
+        d = float64_add(d, 0.5, &env->fp_status);
+        T0 = float64_round_to_int(d, &env->fp_status);
+#endif
+    } else {
+        T0 = 0;
+    }
 }
 
 /*****************************************************************************/
-/* MMU related helpers */
-/* TLB invalidation helpers */
-void do_tlbia (void)
+/* Embedded PowerPC specific helpers */
+void do_405_check_ov (void)
 {
-    tlb_flush(env, 1);
+    if (likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) ||
+               !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) {
+        xer_ov = 0;
+    } else {
+        xer_ov = 1;
+        xer_so = 1;
+    }
 }
 
-void do_tlbie (void)
+void do_405_check_sat (void)
 {
-#if !defined(FLUSH_ALL_TLBS)
-    tlb_flush_page(env, T0);
-#else
-    do_tlbia();
-#endif
+    if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) ||
+                !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) {
+        /* Saturate result */
+        if (T2 >> 31) {
+            T0 = INT32_MIN;
+        } else {
+            T0 = INT32_MAX;
+        }
+    }
 }
 
+/* XXX: to be improved to check access rights when in user-mode */
+void do_load_dcr (void)
+{
+    target_ulong val;
+
+    if (unlikely(env->dcr_env == NULL)) {
+        if (loglevel != 0) {
+            fprintf(logfile, "No DCR environment\n");
+        }
+        do_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
+    } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) {
+        if (loglevel != 0) {
+            fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0);
+        }
+        do_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+    } else {
+        T0 = val;
+    }
+}
+
+void do_store_dcr (void)
+{
+    if (unlikely(env->dcr_env == NULL)) {
+        if (loglevel != 0) {
+            fprintf(logfile, "No DCR environment\n");
+        }
+        do_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL);
+    } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) {
+        if (loglevel != 0) {
+            fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0);
+        }
+        do_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                               POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG);
+    }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void do_40x_rfci (void)
+{
+    env->nip = env->spr[SPR_40x_SRR2];
+    do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000);
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+    env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_rfci (void)
+{
+#if defined(TARGET_PPC64)
+    if (env->spr[SPR_BOOKE_CSRR1] & (1 << MSR_CM)) {
+        env->nip = (uint64_t)env->spr[SPR_BOOKE_CSRR0];
+    } else
+#endif
+    {
+        env->nip = (uint32_t)env->spr[SPR_BOOKE_CSRR0];
+    }
+    do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_CSRR1] & ~0x3FFF0000);
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+    env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_rfdi (void)
+{
+#if defined(TARGET_PPC64)
+    if (env->spr[SPR_BOOKE_DSRR1] & (1 << MSR_CM)) {
+        env->nip = (uint64_t)env->spr[SPR_BOOKE_DSRR0];
+    } else
+#endif
+    {
+        env->nip = (uint32_t)env->spr[SPR_BOOKE_DSRR0];
+    }
+    do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_DSRR1] & ~0x3FFF0000);
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+    env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_rfmci (void)
+{
+#if defined(TARGET_PPC64)
+    if (env->spr[SPR_BOOKE_MCSRR1] & (1 << MSR_CM)) {
+        env->nip = (uint64_t)env->spr[SPR_BOOKE_MCSRR0];
+    } else
+#endif
+    {
+        env->nip = (uint32_t)env->spr[SPR_BOOKE_MCSRR0];
+    }
+    do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_MCSRR1] & ~0x3FFF0000);
+#if defined (DEBUG_OP)
+    cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+    env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_load_403_pb (int num)
+{
+    T0 = env->pb[num];
+}
+
+void do_store_403_pb (int num)
+{
+    if (likely(env->pb[num] != T0)) {
+        env->pb[num] = T0;
+        /* Should be optimized */
+        tlb_flush(env, 1);
+    }
+}
+#endif
+
+/* 440 specific */
+void do_440_dlmzb (void)
+{
+    target_ulong mask;
+    int i;
+
+    i = 1;
+    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+        if ((T0 & mask) == 0)
+            goto done;
+        i++;
+    }
+    for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+        if ((T1 & mask) == 0)
+            break;
+        i++;
+    }
+ done:
+    T0 = i;
+}
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension helpers */
+/* Use a table to make this quicker */
+static uint8_t hbrev[16] = {
+    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
+    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
+};
+
+static inline uint8_t byte_reverse (uint8_t val)
+{
+    return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
+}
+
+static inline uint32_t word_reverse (uint32_t val)
+{
+    return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
+        (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
+}
+
+#define MASKBITS 16 // Random value - to be fixed
+void do_brinc (void)
+{
+    uint32_t a, b, d, mask;
+
+    mask = (uint32_t)(-1UL) >> MASKBITS;
+    b = T1_64 & mask;
+    a = T0_64 & mask;
+    d = word_reverse(1 + word_reverse(a | ~mask));
+    T0_64 = (T0_64 & ~mask) | (d & mask);
+}
+
+#define DO_SPE_OP2(name)                                                      \
+void do_ev##name (void)                                                       \
+{                                                                             \
+    T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) |         \
+        (uint64_t)_do_e##name(T0_64, T1_64);                                  \
+}
+
+#define DO_SPE_OP1(name)                                                      \
+void do_ev##name (void)                                                       \
+{                                                                             \
+    T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) |                      \
+        (uint64_t)_do_e##name(T0_64);                                         \
+}
+
+/* Fixed-point vector arithmetic */
+static inline uint32_t _do_eabs (uint32_t val)
+{
+    if (val != 0x80000000)
+        val &= ~0x80000000;
+
+    return val;
+}
+
+static inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2)
+{
+    return op1 + op2;
+}
+
+static inline int _do_ecntlsw (uint32_t val)
+{
+    if (val & 0x80000000)
+        return _do_cntlzw(~val);
+    else
+        return _do_cntlzw(val);
+}
+
+static inline int _do_ecntlzw (uint32_t val)
+{
+    return _do_cntlzw(val);
+}
+
+static inline uint32_t _do_eneg (uint32_t val)
+{
+    if (val != 0x80000000)
+        val ^= 0x80000000;
+
+    return val;
+}
+
+static inline uint32_t _do_erlw (uint32_t op1, uint32_t op2)
+{
+    return rotl32(op1, op2);
+}
+
+static inline uint32_t _do_erndw (uint32_t val)
+{
+    return (val + 0x000080000000) & 0xFFFF0000;
+}
+
+static inline uint32_t _do_eslw (uint32_t op1, uint32_t op2)
+{
+    /* No error here: 6 bits are used */
+    return op1 << (op2 & 0x3F);
+}
+
+static inline int32_t _do_esrws (int32_t op1, uint32_t op2)
+{
+    /* No error here: 6 bits are used */
+    return op1 >> (op2 & 0x3F);
+}
+
+static inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2)
+{
+    /* No error here: 6 bits are used */
+    return op1 >> (op2 & 0x3F);
+}
+
+static inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2)
+{
+    return op2 - op1;
+}
+
+/* evabs */
+DO_SPE_OP1(abs);
+/* evaddw */
+DO_SPE_OP2(addw);
+/* evcntlsw */
+DO_SPE_OP1(cntlsw);
+/* evcntlzw */
+DO_SPE_OP1(cntlzw);
+/* evneg */
+DO_SPE_OP1(neg);
+/* evrlw */
+DO_SPE_OP2(rlw);
+/* evrnd */
+DO_SPE_OP1(rndw);
+/* evslw */
+DO_SPE_OP2(slw);
+/* evsrws */
+DO_SPE_OP2(srws);
+/* evsrwu */
+DO_SPE_OP2(srwu);
+/* evsubfw */
+DO_SPE_OP2(subfw);
+
+/* evsel is a little bit more complicated... */
+static inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n)
+{
+    if (n)
+        return op1;
+    else
+        return op2;
+}
+
+void do_evsel (void)
+{
+    T0_64 = ((uint64_t)_do_esel(T0_64 >> 32, T1_64 >> 32, T0 >> 3) << 32) |
+        (uint64_t)_do_esel(T0_64, T1_64, (T0 >> 2) & 1);
+}
+
+/* Fixed-point vector comparisons */
+#define DO_SPE_CMP(name)                                                      \
+void do_ev##name (void)                                                       \
+{                                                                             \
+    T0 = _do_evcmp_merge((uint64_t)_do_e##name(T0_64 >> 32,                   \
+                                               T1_64 >> 32) << 32,            \
+                         _do_e##name(T0_64, T1_64));                          \
+}
+
+static inline uint32_t _do_evcmp_merge (int t0, int t1)
+{
+    return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
+}
+static inline int _do_ecmpeq (uint32_t op1, uint32_t op2)
+{
+    return op1 == op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpgts (int32_t op1, int32_t op2)
+{
+    return op1 > op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpgtu (uint32_t op1, uint32_t op2)
+{
+    return op1 > op2 ? 1 : 0;
+}
+
+static inline int _do_ecmplts (int32_t op1, int32_t op2)
+{
+    return op1 < op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpltu (uint32_t op1, uint32_t op2)
+{
+    return op1 < op2 ? 1 : 0;
+}
+
+/* evcmpeq */
+DO_SPE_CMP(cmpeq);
+/* evcmpgts */
+DO_SPE_CMP(cmpgts);
+/* evcmpgtu */
+DO_SPE_CMP(cmpgtu);
+/* evcmplts */
+DO_SPE_CMP(cmplts);
+/* evcmpltu */
+DO_SPE_CMP(cmpltu);
+
+/* Single precision floating-point conversions from/to integer */
+static inline uint32_t _do_efscfsi (int32_t val)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u;
+
+    u.f = int32_to_float32(val, &env->spe_status);
+
+    return u.u;
+}
+
+static inline uint32_t _do_efscfui (uint32_t val)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u;
+
+    u.f = uint32_to_float32(val, &env->spe_status);
+
+    return u.u;
+}
+
+static inline int32_t _do_efsctsi (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float32_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctui (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float32_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int32_t _do_efsctsiz (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctuiz (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efscfsi (void)
+{
+    T0_64 = _do_efscfsi(T0_64);
+}
+
+void do_efscfui (void)
+{
+    T0_64 = _do_efscfui(T0_64);
+}
+
+void do_efsctsi (void)
+{
+    T0_64 = _do_efsctsi(T0_64);
+}
+
+void do_efsctui (void)
+{
+    T0_64 = _do_efsctui(T0_64);
+}
+
+void do_efsctsiz (void)
+{
+    T0_64 = _do_efsctsiz(T0_64);
+}
+
+void do_efsctuiz (void)
+{
+    T0_64 = _do_efsctuiz(T0_64);
+}
+
+/* Single precision floating-point conversion to/from fractional */
+static inline uint32_t _do_efscfsf (uint32_t val)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.f = int32_to_float32(val, &env->spe_status);
+    tmp = int64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_div(u.f, tmp, &env->spe_status);
+
+    return u.u;
+}
+
+static inline uint32_t _do_efscfuf (uint32_t val)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.f = uint32_to_float32(val, &env->spe_status);
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_div(u.f, tmp, &env->spe_status);
+
+    return u.u;
+}
+
+static inline int32_t _do_efsctsf (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+    return float32_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctuf (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+    return float32_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int32_t _do_efsctsfz (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+    return float32_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctufz (uint32_t val)
+{
+    union {
+        int32_t u;
+        float32 f;
+    } u;
+    float32 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+    u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+    return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efscfsf (void)
+{
+    T0_64 = _do_efscfsf(T0_64);
+}
+
+void do_efscfuf (void)
+{
+    T0_64 = _do_efscfuf(T0_64);
+}
+
+void do_efsctsf (void)
+{
+    T0_64 = _do_efsctsf(T0_64);
+}
+
+void do_efsctuf (void)
+{
+    T0_64 = _do_efsctuf(T0_64);
+}
+
+void do_efsctsfz (void)
+{
+    T0_64 = _do_efsctsfz(T0_64);
+}
+
+void do_efsctufz (void)
+{
+    T0_64 = _do_efsctufz(T0_64);
+}
+
+/* Double precision floating point helpers */
+static inline int _do_efdcmplt (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efdtstlt(op1, op2);
+}
+
+static inline int _do_efdcmpgt (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efdtstgt(op1, op2);
+}
+
+static inline int _do_efdcmpeq (uint64_t op1, uint64_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efdtsteq(op1, op2);
+}
+
+void do_efdcmplt (void)
+{
+    T0 = _do_efdcmplt(T0_64, T1_64);
+}
+
+void do_efdcmpgt (void)
+{
+    T0 = _do_efdcmpgt(T0_64, T1_64);
+}
+
+void do_efdcmpeq (void)
+{
+    T0 = _do_efdcmpeq(T0_64, T1_64);
+}
+
+/* Double precision floating-point conversion to/from integer */
+static inline uint64_t _do_efdcfsi (int64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u;
+
+    u.f = int64_to_float64(val, &env->spe_status);
+
+    return u.u;
+}
+
+static inline uint64_t _do_efdcfui (uint64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u;
+
+    u.f = uint64_to_float64(val, &env->spe_status);
+
+    return u.u;
+}
+
+static inline int64_t _do_efdctsi (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float64_to_int64(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctui (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float64_to_uint64(u.f, &env->spe_status);
+}
+
+static inline int64_t _do_efdctsiz (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float64_to_int64_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctuiz (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+
+    return float64_to_uint64_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efdcfsi (void)
+{
+    T0_64 = _do_efdcfsi(T0_64);
+}
+
+void do_efdcfui (void)
+{
+    T0_64 = _do_efdcfui(T0_64);
+}
+
+void do_efdctsi (void)
+{
+    T0_64 = _do_efdctsi(T0_64);
+}
+
+void do_efdctui (void)
+{
+    T0_64 = _do_efdctui(T0_64);
+}
+
+void do_efdctsiz (void)
+{
+    T0_64 = _do_efdctsiz(T0_64);
+}
+
+void do_efdctuiz (void)
+{
+    T0_64 = _do_efdctuiz(T0_64);
+}
+
+/* Double precision floating-point conversion to/from fractional */
+static inline uint64_t _do_efdcfsf (int64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.f = int32_to_float64(val, &env->spe_status);
+    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_div(u.f, tmp, &env->spe_status);
+
+    return u.u;
+}
+
+static inline uint64_t _do_efdcfuf (uint64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.f = uint32_to_float64(val, &env->spe_status);
+    tmp = int64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_div(u.f, tmp, &env->spe_status);
+
+    return u.u;
+}
+
+static inline int64_t _do_efdctsf (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+    return float64_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctuf (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+    return float64_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int64_t _do_efdctsfz (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+    return float64_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctufz (uint64_t val)
+{
+    union {
+        int64_t u;
+        float64 f;
+    } u;
+    float64 tmp;
+
+    u.u = val;
+    /* NaN are not treated the same way IEEE 754 does */
+    if (unlikely(isnan(u.f)))
+        return 0;
+    tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+    u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+    return float64_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efdcfsf (void)
+{
+    T0_64 = _do_efdcfsf(T0_64);
+}
+
+void do_efdcfuf (void)
+{
+    T0_64 = _do_efdcfuf(T0_64);
+}
+
+void do_efdctsf (void)
+{
+    T0_64 = _do_efdctsf(T0_64);
+}
+
+void do_efdctuf (void)
+{
+    T0_64 = _do_efdctuf(T0_64);
+}
+
+void do_efdctsfz (void)
+{
+    T0_64 = _do_efdctsfz(T0_64);
+}
+
+void do_efdctufz (void)
+{
+    T0_64 = _do_efdctufz(T0_64);
+}
+
+/* Floating point conversion between single and double precision */
+static inline uint32_t _do_efscfd (uint64_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1;
+    union {
+        uint32_t u;
+        float32 f;
+    } u2;
+
+    u1.u = val;
+    u2.f = float64_to_float32(u1.f, &env->spe_status);
+
+    return u2.u;
+}
+
+static inline uint64_t _do_efdcfs (uint32_t val)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u2;
+    union {
+        uint32_t u;
+        float32 f;
+    } u1;
+
+    u1.u = val;
+    u2.f = float32_to_float64(u1.f, &env->spe_status);
+
+    return u2.u;
+}
+
+void do_efscfd (void)
+{
+    T0_64 = _do_efscfd(T0_64);
+}
+
+void do_efdcfs (void)
+{
+    T0_64 = _do_efdcfs(T0_64);
+}
+
+/* Single precision fixed-point vector arithmetic */
+/* evfsabs */
+DO_SPE_OP1(fsabs);
+/* evfsnabs */
+DO_SPE_OP1(fsnabs);
+/* evfsneg */
+DO_SPE_OP1(fsneg);
+/* evfsadd */
+DO_SPE_OP2(fsadd);
+/* evfssub */
+DO_SPE_OP2(fssub);
+/* evfsmul */
+DO_SPE_OP2(fsmul);
+/* evfsdiv */
+DO_SPE_OP2(fsdiv);
+
+/* Single-precision floating-point comparisons */
+static inline int _do_efscmplt (uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efststlt(op1, op2);
+}
+
+static inline int _do_efscmpgt (uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efststgt(op1, op2);
+}
+
+static inline int _do_efscmpeq (uint32_t op1, uint32_t op2)
+{
+    /* XXX: TODO: test special values (NaN, infinites, ...) */
+    return _do_efststeq(op1, op2);
+}
+
+void do_efscmplt (void)
+{
+    T0 = _do_efscmplt(T0_64, T1_64);
+}
+
+void do_efscmpgt (void)
+{
+    T0 = _do_efscmpgt(T0_64, T1_64);
+}
+
+void do_efscmpeq (void)
+{
+    T0 = _do_efscmpeq(T0_64, T1_64);
+}
+
+/* Single-precision floating-point vector comparisons */
+/* evfscmplt */
+DO_SPE_CMP(fscmplt);
+/* evfscmpgt */
+DO_SPE_CMP(fscmpgt);
+/* evfscmpeq */
+DO_SPE_CMP(fscmpeq);
+/* evfststlt */
+DO_SPE_CMP(fststlt);
+/* evfststgt */
+DO_SPE_CMP(fststgt);
+/* evfststeq */
+DO_SPE_CMP(fststeq);
+
+/* Single-precision floating-point vector conversions */
+/* evfscfsi */
+DO_SPE_OP1(fscfsi);
+/* evfscfui */
+DO_SPE_OP1(fscfui);
+/* evfscfuf */
+DO_SPE_OP1(fscfuf);
+/* evfscfsf */
+DO_SPE_OP1(fscfsf);
+/* evfsctsi */
+DO_SPE_OP1(fsctsi);
+/* evfsctui */
+DO_SPE_OP1(fsctui);
+/* evfsctsiz */
+DO_SPE_OP1(fsctsiz);
+/* evfsctuiz */
+DO_SPE_OP1(fsctuiz);
+/* evfsctsf */
+DO_SPE_OP1(fsctsf);
+/* evfsctuf */
+DO_SPE_OP1(fsctuf);
+#endif /* defined(TARGET_PPCEMB) */
+
 /*****************************************************************************/
 /* Softmmu support */
 #if !defined (CONFIG_USER_ONLY)
@@ -570,20 +2319,378 @@
     saved_env = env;
     env = cpu_single_env;
     ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
-    if (!likely(ret == 0)) {
+    if (unlikely(ret != 0)) {
         if (likely(retaddr)) {
             /* now we have a real cpu fault */
-            pc = (target_phys_addr_t)retaddr;
+            pc = (target_phys_addr_t)(unsigned long)retaddr;
             tb = tb_find_pc(pc);
             if (likely(tb)) {
                 /* the PC is inside the translated code. It means that we have
                    a virtual CPU fault */
                 cpu_restore_state(tb, env, pc, NULL);
-}
+            }
         }
         do_raise_exception_err(env->exception_index, env->error_code);
     }
     env = saved_env;
 }
-#endif /* !CONFIG_USER_ONLY */
 
+/* Software driven TLBs management */
+/* PowerPC 602/603 software TLB load instructions helpers */
+void do_load_6xx_tlb (int is_code)
+{
+    target_ulong RPN, CMP, EPN;
+    int way;
+
+    RPN = env->spr[SPR_RPA];
+    if (is_code) {
+        CMP = env->spr[SPR_ICMP];
+        EPN = env->spr[SPR_IMISS];
+    } else {
+        CMP = env->spr[SPR_DCMP];
+        EPN = env->spr[SPR_DMISS];
+    }
+    way = (env->spr[SPR_SRR1] >> 17) & 1;
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
+                __func__, (unsigned long)T0, (unsigned long)EPN,
+                (unsigned long)CMP, (unsigned long)RPN, way);
+    }
+#endif
+    /* Store this TLB */
+    ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
+                     way, is_code, CMP, RPN);
+}
+
+void do_load_74xx_tlb (int is_code)
+{
+    target_ulong RPN, CMP, EPN;
+    int way;
+
+    RPN = env->spr[SPR_PTELO];
+    CMP = env->spr[SPR_PTEHI];
+    EPN = env->spr[SPR_TLBMISS] & ~0x3;
+    way = env->spr[SPR_TLBMISS] & 0x3;
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
+                __func__, (unsigned long)T0, (unsigned long)EPN,
+                (unsigned long)CMP, (unsigned long)RPN, way);
+    }
+#endif
+    /* Store this TLB */
+    ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
+                     way, is_code, CMP, RPN);
+}
+
+static target_ulong booke_tlb_to_page_size (int size)
+{
+    return 1024 << (2 * size);
+}
+
+static int booke_page_size_to_tlb (target_ulong page_size)
+{
+    int size;
+
+    switch (page_size) {
+    case 0x00000400UL:
+        size = 0x0;
+        break;
+    case 0x00001000UL:
+        size = 0x1;
+        break;
+    case 0x00004000UL:
+        size = 0x2;
+        break;
+    case 0x00010000UL:
+        size = 0x3;
+        break;
+    case 0x00040000UL:
+        size = 0x4;
+        break;
+    case 0x00100000UL:
+        size = 0x5;
+        break;
+    case 0x00400000UL:
+        size = 0x6;
+        break;
+    case 0x01000000UL:
+        size = 0x7;
+        break;
+    case 0x04000000UL:
+        size = 0x8;
+        break;
+    case 0x10000000UL:
+        size = 0x9;
+        break;
+    case 0x40000000UL:
+        size = 0xA;
+        break;
+#if defined (TARGET_PPC64)
+    case 0x000100000000ULL:
+        size = 0xB;
+        break;
+    case 0x000400000000ULL:
+        size = 0xC;
+        break;
+    case 0x001000000000ULL:
+        size = 0xD;
+        break;
+    case 0x004000000000ULL:
+        size = 0xE;
+        break;
+    case 0x010000000000ULL:
+        size = 0xF;
+        break;
+#endif
+    default:
+        size = -1;
+        break;
+    }
+
+    return size;
+}
+
+/* Helpers for 4xx TLB management */
+void do_4xx_tlbre_lo (void)
+{
+    ppcemb_tlb_t *tlb;
+    int size;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    T0 = tlb->EPN;
+    if (tlb->prot & PAGE_VALID)
+        T0 |= 0x400;
+    size = booke_page_size_to_tlb(tlb->size);
+    if (size < 0 || size > 0x7)
+        size = 1;
+    T0 |= size << 7;
+    env->spr[SPR_40x_PID] = tlb->PID;
+}
+
+void do_4xx_tlbre_hi (void)
+{
+    ppcemb_tlb_t *tlb;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    T0 = tlb->RPN;
+    if (tlb->prot & PAGE_EXEC)
+        T0 |= 0x200;
+    if (tlb->prot & PAGE_WRITE)
+        T0 |= 0x100;
+}
+
+void do_4xx_tlbwe_hi (void)
+{
+    ppcemb_tlb_t *tlb;
+    target_ulong page, end;
+
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
+    }
+#endif
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    /* Invalidate previous TLB (if it's valid) */
+    if (tlb->prot & PAGE_VALID) {
+        end = tlb->EPN + tlb->size;
+#if defined (DEBUG_SOFTWARE_TLB)
+        if (loglevel != 0) {
+            fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
+                    " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
+        }
+#endif
+        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+            tlb_flush_page(env, page);
+    }
+    tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
+    /* We cannot handle TLB size < TARGET_PAGE_SIZE.
+     * If this ever occurs, one should use the ppcemb target instead
+     * of the ppc or ppc64 one
+     */
+    if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
+        cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
+                  "are not supported (%d)\n",
+                  tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
+    }
+    tlb->EPN = T1 & ~(tlb->size - 1);
+    if (T1 & 0x40)
+        tlb->prot |= PAGE_VALID;
+    else
+        tlb->prot &= ~PAGE_VALID;
+    if (T1 & 0x20) {
+        /* XXX: TO BE FIXED */
+        cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
+    }
+    tlb->PID = env->spr[SPR_40x_PID]; /* PID */
+    tlb->attr = T1 & 0xFF;
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
+                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
+                (int)T0, tlb->RPN, tlb->EPN, tlb->size,
+                tlb->prot & PAGE_READ ? 'r' : '-',
+                tlb->prot & PAGE_WRITE ? 'w' : '-',
+                tlb->prot & PAGE_EXEC ? 'x' : '-',
+                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+    }
+#endif
+    /* Invalidate new TLB (if valid) */
+    if (tlb->prot & PAGE_VALID) {
+        end = tlb->EPN + tlb->size;
+#if defined (DEBUG_SOFTWARE_TLB)
+        if (loglevel != 0) {
+            fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
+                    " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
+        }
+#endif
+        for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+            tlb_flush_page(env, page);
+    }
+}
+
+void do_4xx_tlbwe_lo (void)
+{
+    ppcemb_tlb_t *tlb;
+
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
+    }
+#endif
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    tlb->RPN = T1 & 0xFFFFFC00;
+    tlb->prot = PAGE_READ;
+    if (T1 & 0x200)
+        tlb->prot |= PAGE_EXEC;
+    if (T1 & 0x100)
+        tlb->prot |= PAGE_WRITE;
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
+                " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
+                (int)T0, tlb->RPN, tlb->EPN, tlb->size,
+                tlb->prot & PAGE_READ ? 'r' : '-',
+                tlb->prot & PAGE_WRITE ? 'w' : '-',
+                tlb->prot & PAGE_EXEC ? 'x' : '-',
+                tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+    }
+#endif
+}
+
+/* PowerPC 440 TLB management */
+void do_440_tlbwe (int word)
+{
+    ppcemb_tlb_t *tlb;
+    target_ulong EPN, RPN, size;
+    int do_flush_tlbs;
+
+#if defined (DEBUG_SOFTWARE_TLB)
+    if (loglevel != 0) {
+        fprintf(logfile, "%s word %d T0 " REGX " T1 " REGX "\n",
+                __func__, word, T0, T1);
+    }
+#endif
+    do_flush_tlbs = 0;
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    switch (word) {
+    default:
+        /* Just here to please gcc */
+    case 0:
+        EPN = T1 & 0xFFFFFC00;
+        if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN)
+            do_flush_tlbs = 1;
+        tlb->EPN = EPN;
+        size = booke_tlb_to_page_size((T1 >> 4) & 0xF);
+        if ((tlb->prot & PAGE_VALID) && tlb->size < size)
+            do_flush_tlbs = 1;
+        tlb->size = size;
+        tlb->attr &= ~0x1;
+        tlb->attr |= (T1 >> 8) & 1;
+        if (T1 & 0x200) {
+            tlb->prot |= PAGE_VALID;
+        } else {
+            if (tlb->prot & PAGE_VALID) {
+                tlb->prot &= ~PAGE_VALID;
+                do_flush_tlbs = 1;
+            }
+        }
+        tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
+        if (do_flush_tlbs)
+            tlb_flush(env, 1);
+        break;
+    case 1:
+        RPN = T1 & 0xFFFFFC0F;
+        if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN)
+            tlb_flush(env, 1);
+        tlb->RPN = RPN;
+        break;
+    case 2:
+        tlb->attr = (tlb->attr & 0x1) | (T1 & 0x0000FF00);
+        tlb->prot = tlb->prot & PAGE_VALID;
+        if (T1 & 0x1)
+            tlb->prot |= PAGE_READ << 4;
+        if (T1 & 0x2)
+            tlb->prot |= PAGE_WRITE << 4;
+        if (T1 & 0x4)
+            tlb->prot |= PAGE_EXEC << 4;
+        if (T1 & 0x8)
+            tlb->prot |= PAGE_READ;
+        if (T1 & 0x10)
+            tlb->prot |= PAGE_WRITE;
+        if (T1 & 0x20)
+            tlb->prot |= PAGE_EXEC;
+        break;
+    }
+}
+
+void do_440_tlbre (int word)
+{
+    ppcemb_tlb_t *tlb;
+    int size;
+
+    T0 &= 0x3F;
+    tlb = &env->tlb[T0].tlbe;
+    switch (word) {
+    default:
+        /* Just here to please gcc */
+    case 0:
+        T0 = tlb->EPN;
+        size = booke_page_size_to_tlb(tlb->size);
+        if (size < 0 || size > 0xF)
+            size = 1;
+        T0 |= size << 4;
+        if (tlb->attr & 0x1)
+            T0 |= 0x100;
+        if (tlb->prot & PAGE_VALID)
+            T0 |= 0x200;
+        env->spr[SPR_440_MMUCR] &= ~0x000000FF;
+        env->spr[SPR_440_MMUCR] |= tlb->PID;
+        break;
+    case 1:
+        T0 = tlb->RPN;
+        break;
+    case 2:
+        T0 = tlb->attr & ~0x1;
+        if (tlb->prot & (PAGE_READ << 4))
+            T0 |= 0x1;
+        if (tlb->prot & (PAGE_WRITE << 4))
+            T0 |= 0x2;
+        if (tlb->prot & (PAGE_EXEC << 4))
+            T0 |= 0x4;
+        if (tlb->prot & PAGE_READ)
+            T0 |= 0x8;
+        if (tlb->prot & PAGE_WRITE)
+            T0 |= 0x10;
+        if (tlb->prot & PAGE_EXEC)
+            T0 |= 0x20;
+        break;
+    }
+}
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/op_helper.h b/target-ppc/op_helper.h
new file mode 100644
index 0000000..0406682
--- /dev/null
+++ b/target-ppc/op_helper.h
@@ -0,0 +1,470 @@
+/*
+ *  PowerPC emulation helpers header for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+#if defined(MEMSUFFIX)
+
+/* Memory load/store helpers */
+void glue(do_lsw, MEMSUFFIX) (int dst);
+void glue(do_lsw_le, MEMSUFFIX) (int dst);
+void glue(do_stsw, MEMSUFFIX) (int src);
+void glue(do_stsw_le, MEMSUFFIX) (int src);
+void glue(do_lmw, MEMSUFFIX) (int dst);
+void glue(do_lmw_le, MEMSUFFIX) (int dst);
+void glue(do_stmw, MEMSUFFIX) (int src);
+void glue(do_stmw_le, MEMSUFFIX) (int src);
+void glue(do_icbi, MEMSUFFIX) (void);
+void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb);
+void glue(do_POWER2_lfq, MEMSUFFIX) (void);
+void glue(do_POWER2_lfq_le, MEMSUFFIX) (void);
+void glue(do_POWER2_stfq, MEMSUFFIX) (void);
+void glue(do_POWER2_stfq_le, MEMSUFFIX) (void);
+
+#if defined(TARGET_PPC64)
+void glue(do_lsw_64, MEMSUFFIX) (int dst);
+void glue(do_lsw_le_64, MEMSUFFIX) (int dst);
+void glue(do_stsw_64, MEMSUFFIX) (int src);
+void glue(do_stsw_le_64, MEMSUFFIX) (int src);
+void glue(do_lmw_64, MEMSUFFIX) (int dst);
+void glue(do_lmw_le_64, MEMSUFFIX) (int dst);
+void glue(do_stmw_64, MEMSUFFIX) (int src);
+void glue(do_stmw_le_64, MEMSUFFIX) (int src);
+void glue(do_icbi_64, MEMSUFFIX) (void);
+#endif
+
+#else
+
+void do_print_mem_EA (target_ulong EA);
+
+/* Registers load and stores */
+void do_load_cr (void);
+void do_store_cr (uint32_t mask);
+void do_load_xer (void);
+void do_store_xer (void);
+#if defined(TARGET_PPC64)
+void do_store_pri (int prio);
+#endif
+void do_load_fpscr (void);
+void do_store_fpscr (uint32_t mask);
+target_ulong ppc_load_dump_spr (int sprn);
+void ppc_store_dump_spr (int sprn, target_ulong val);
+
+/* Integer arithmetic helpers */
+void do_adde (void);
+void do_addmeo (void);
+void do_divwo (void);
+void do_divwuo (void);
+void do_mullwo (void);
+void do_nego (void);
+void do_subfe (void);
+void do_subfmeo (void);
+void do_subfzeo (void);
+void do_sraw (void);
+#if defined(TARGET_PPC64)
+void do_adde_64 (void);
+void do_addmeo_64 (void);
+void do_imul64 (uint64_t *tl, uint64_t *th);
+void do_mul64 (uint64_t *tl, uint64_t *th);
+void do_divdo (void);
+void do_divduo (void);
+void do_mulldo (void);
+void do_nego_64 (void);
+void do_subfe_64 (void);
+void do_subfmeo_64 (void);
+void do_subfzeo_64 (void);
+void do_srad (void);
+#endif
+void do_popcntb (void);
+#if defined(TARGET_PPC64)
+void do_popcntb_64 (void);
+#endif
+
+/* Floating-point arithmetic helpers */
+void do_fsqrt (void);
+void do_fre (void);
+void do_fres (void);
+void do_frsqrte (void);
+void do_fsel (void);
+#if USE_PRECISE_EMULATION
+void do_fmadd (void);
+void do_fmsub (void);
+#endif
+void do_fnmadd (void);
+void do_fnmsub (void);
+void do_fctiw (void);
+void do_fctiwz (void);
+#if defined(TARGET_PPC64)
+void do_fcfid (void);
+void do_fctid (void);
+void do_fctidz (void);
+#endif
+void do_frin (void);
+void do_friz (void);
+void do_frip (void);
+void do_frim (void);
+void do_fcmpu (void);
+void do_fcmpo (void);
+
+/* Misc */
+void do_tw (int flags);
+#if defined(TARGET_PPC64)
+void do_td (int flags);
+#endif
+#if !defined(CONFIG_USER_ONLY)
+void do_rfi (void);
+#if defined(TARGET_PPC64)
+void do_rfid (void);
+#endif
+#if defined(TARGET_PPC64H)
+void do_hrfid (void);
+#endif
+void do_load_6xx_tlb (int is_code);
+void do_load_74xx_tlb (int is_code);
+#endif
+
+/* POWER / PowerPC 601 specific helpers */
+void do_store_601_batu (int nr);
+void do_POWER_abso (void);
+void do_POWER_clcs (void);
+void do_POWER_div (void);
+void do_POWER_divo (void);
+void do_POWER_divs (void);
+void do_POWER_divso (void);
+void do_POWER_dozo (void);
+void do_POWER_maskg (void);
+void do_POWER_mulo (void);
+#if !defined(CONFIG_USER_ONLY)
+void do_POWER_rac (void);
+void do_POWER_rfsvc (void);
+#endif
+
+/* PowerPC 602 specific helper */
+#if !defined(CONFIG_USER_ONLY)
+void do_op_602_mfrom (void);
+#endif
+
+/* PowerPC 440 specific helpers */
+#if !defined(CONFIG_USER_ONLY)
+void do_440_tlbre (int word);
+void do_440_tlbwe (int word);
+#endif
+
+/* PowerPC 4xx specific helpers */
+void do_405_check_ov (void);
+void do_405_check_sat (void);
+void do_load_dcr (void);
+void do_store_dcr (void);
+#if !defined(CONFIG_USER_ONLY)
+void do_40x_rfci (void);
+void do_rfci (void);
+void do_rfdi (void);
+void do_rfmci (void);
+void do_4xx_tlbre_lo (void);
+void do_4xx_tlbre_hi (void);
+void do_4xx_tlbwe_lo (void);
+void do_4xx_tlbwe_hi (void);
+#endif
+
+/* PowerPC 440 specific helpers */
+void do_440_dlmzb (void);
+
+/* PowerPC 403 specific helpers */
+#if !defined(CONFIG_USER_ONLY)
+void do_load_403_pb (int num);
+void do_store_403_pb (int num);
+#endif
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension helpers */
+void do_brinc (void);
+/* Fixed-point vector helpers */
+void do_evabs (void);
+void do_evaddw (void);
+void do_evcntlsw (void);
+void do_evcntlzw (void);
+void do_evneg (void);
+void do_evrlw (void);
+void do_evsel (void);
+void do_evrndw (void);
+void do_evslw (void);
+void do_evsrws (void);
+void do_evsrwu (void);
+void do_evsubfw (void);
+void do_evcmpeq (void);
+void do_evcmpgts (void);
+void do_evcmpgtu (void);
+void do_evcmplts (void);
+void do_evcmpltu (void);
+
+/* Single precision floating-point helpers */
+void do_efscmplt (void);
+void do_efscmpgt (void);
+void do_efscmpeq (void);
+void do_efscfsf (void);
+void do_efscfuf (void);
+void do_efsctsf (void);
+void do_efsctuf (void);
+
+void do_efscfsi (void);
+void do_efscfui (void);
+void do_efsctsi (void);
+void do_efsctui (void);
+void do_efsctsiz (void);
+void do_efsctuiz (void);
+
+/* Double precision floating-point helpers */
+void do_efdcmplt (void);
+void do_efdcmpgt (void);
+void do_efdcmpeq (void);
+void do_efdcfsf (void);
+void do_efdcfuf (void);
+void do_efdctsf (void);
+void do_efdctuf (void);
+
+void do_efdcfsi (void);
+void do_efdcfui (void);
+void do_efdctsi (void);
+void do_efdctui (void);
+void do_efdctsiz (void);
+void do_efdctuiz (void);
+
+void do_efdcfs (void);
+void do_efscfd (void);
+
+/* Floating-point vector helpers */
+void do_evfsabs (void);
+void do_evfsnabs (void);
+void do_evfsneg (void);
+void do_evfsadd (void);
+void do_evfssub (void);
+void do_evfsmul (void);
+void do_evfsdiv (void);
+void do_evfscmplt (void);
+void do_evfscmpgt (void);
+void do_evfscmpeq (void);
+void do_evfststlt (void);
+void do_evfststgt (void);
+void do_evfststeq (void);
+void do_evfscfsi (void);
+void do_evfscfui (void);
+void do_evfscfsf (void);
+void do_evfscfuf (void);
+void do_evfsctsf (void);
+void do_evfsctuf (void);
+void do_evfsctsi (void);
+void do_evfsctui (void);
+void do_evfsctsiz (void);
+void do_evfsctuiz (void);
+#endif /* defined(TARGET_PPCEMB) */
+
+/* Inlined helpers: used in micro-operation as well as helpers */
+/* Generic fixed-point helpers */
+static inline int _do_cntlzw (uint32_t val)
+{
+    int cnt = 0;
+    if (!(val & 0xFFFF0000UL)) {
+        cnt += 16;
+        val <<= 16;
+    }
+    if (!(val & 0xFF000000UL)) {
+        cnt += 8;
+        val <<= 8;
+    }
+    if (!(val & 0xF0000000UL)) {
+        cnt += 4;
+        val <<= 4;
+    }
+    if (!(val & 0xC0000000UL)) {
+        cnt += 2;
+        val <<= 2;
+    }
+    if (!(val & 0x80000000UL)) {
+        cnt++;
+        val <<= 1;
+    }
+    if (!(val & 0x80000000UL)) {
+        cnt++;
+    }
+    return cnt;
+}
+
+static inline int _do_cntlzd (uint64_t val)
+{
+    int cnt = 0;
+#if HOST_LONG_BITS == 64
+    if (!(val & 0xFFFFFFFF00000000ULL)) {
+        cnt += 32;
+        val <<= 32;
+    }
+    if (!(val & 0xFFFF000000000000ULL)) {
+        cnt += 16;
+        val <<= 16;
+    }
+    if (!(val & 0xFF00000000000000ULL)) {
+        cnt += 8;
+        val <<= 8;
+    }
+    if (!(val & 0xF000000000000000ULL)) {
+        cnt += 4;
+        val <<= 4;
+    }
+    if (!(val & 0xC000000000000000ULL)) {
+        cnt += 2;
+        val <<= 2;
+    }
+    if (!(val & 0x8000000000000000ULL)) {
+        cnt++;
+        val <<= 1;
+    }
+    if (!(val & 0x8000000000000000ULL)) {
+        cnt++;
+    }
+#else
+    /* Make it easier on 32 bits host machines */
+    if (!(val >> 32))
+        cnt = _do_cntlzw(val) + 32;
+    else
+        cnt = _do_cntlzw(val >> 32);
+#endif
+    return cnt;
+}
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension */
+/* Single precision floating-point helpers */
+static inline uint32_t _do_efsabs (uint32_t val)
+{
+    return val & ~0x80000000;
+}
+static inline uint32_t _do_efsnabs (uint32_t val)
+{
+    return val | 0x80000000;
+}
+static inline uint32_t _do_efsneg (uint32_t val)
+{
+    return val ^ 0x80000000;
+}
+static inline uint32_t _do_efsadd (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    u1.f = float32_add(u1.f, u2.f, &env->spe_status);
+    return u1.u;
+}
+static inline uint32_t _do_efssub (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
+    return u1.u;
+}
+static inline uint32_t _do_efsmul (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
+    return u1.u;
+}
+static inline uint32_t _do_efsdiv (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    u1.f = float32_div(u1.f, u2.f, &env->spe_status);
+    return u1.u;
+}
+
+static inline int _do_efststlt (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float32_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+static inline int _do_efststgt (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 1;
+}
+static inline int _do_efststeq (uint32_t op1, uint32_t op2)
+{
+    union {
+        uint32_t u;
+        float32 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float32_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+/* Double precision floating-point helpers */
+static inline int _do_efdtstlt (uint64_t op1, uint64_t op2)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float64_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+static inline int _do_efdtstgt (uint64_t op1, uint64_t op2)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float64_le(u1.f, u2.f, &env->spe_status) ? 0 : 1;
+}
+static inline int _do_efdtsteq (uint64_t op1, uint64_t op2)
+{
+    union {
+        uint64_t u;
+        float64 f;
+    } u1, u2;
+    u1.u = op1;
+    u2.u = op2;
+    return float64_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+#endif /* defined(TARGET_PPCEMB) */
+#endif
diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h
index fb90691..e8cca09 100644
--- a/target-ppc/op_helper_mem.h
+++ b/target-ppc/op_helper_mem.h
@@ -1,100 +1,365 @@
+/*
+ *  PowerPC emulation micro-operations helpers for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * 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
+ */
+
+/* Multiple word / string load and store */
+static inline target_ulong glue(ld32r, MEMSUFFIX) (target_ulong EA)
+{
+    uint32_t tmp = glue(ldl, MEMSUFFIX)(EA);
+    return ((tmp & 0xFF000000UL) >> 24) | ((tmp & 0x00FF0000UL) >> 8) |
+        ((tmp & 0x0000FF00UL) << 8) | ((tmp & 0x000000FFUL) << 24);
+}
+
+static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, target_ulong data)
+{
+    uint32_t tmp =
+        ((data & 0xFF000000UL) >> 24) | ((data & 0x00FF0000UL) >> 8) |
+        ((data & 0x0000FF00UL) << 8) | ((data & 0x000000FFUL) << 24);
+    glue(stl, MEMSUFFIX)(EA, tmp);
+}
+
+void glue(do_lmw, MEMSUFFIX) (int dst)
+{
+    for (; dst < 32; dst++, T0 += 4) {
+        env->gpr[dst] = glue(ldl, MEMSUFFIX)((uint32_t)T0);
+    }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_lmw_64, MEMSUFFIX) (int dst)
+{
+    for (; dst < 32; dst++, T0 += 4) {
+        env->gpr[dst] = glue(ldl, MEMSUFFIX)((uint64_t)T0);
+    }
+}
+#endif
+
+void glue(do_stmw, MEMSUFFIX) (int src)
+{
+    for (; src < 32; src++, T0 += 4) {
+        glue(stl, MEMSUFFIX)((uint32_t)T0, env->gpr[src]);
+    }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_stmw_64, MEMSUFFIX) (int src)
+{
+    for (; src < 32; src++, T0 += 4) {
+        glue(stl, MEMSUFFIX)((uint64_t)T0, env->gpr[src]);
+    }
+}
+#endif
+
+void glue(do_lmw_le, MEMSUFFIX) (int dst)
+{
+    for (; dst < 32; dst++, T0 += 4) {
+        env->gpr[dst] = glue(ld32r, MEMSUFFIX)((uint32_t)T0);
+    }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_lmw_le_64, MEMSUFFIX) (int dst)
+{
+    for (; dst < 32; dst++, T0 += 4) {
+        env->gpr[dst] = glue(ld32r, MEMSUFFIX)((uint64_t)T0);
+    }
+}
+#endif
+
+void glue(do_stmw_le, MEMSUFFIX) (int src)
+{
+    for (; src < 32; src++, T0 += 4) {
+        glue(st32r, MEMSUFFIX)((uint32_t)T0, env->gpr[src]);
+    }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_stmw_le_64, MEMSUFFIX) (int src)
+{
+    for (; src < 32; src++, T0 += 4) {
+        glue(st32r, MEMSUFFIX)((uint64_t)T0, env->gpr[src]);
+    }
+}
+#endif
+
 void glue(do_lsw, MEMSUFFIX) (int dst)
 {
     uint32_t tmp;
     int sh;
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
-                __func__, T0, T1, dst);
-    }
-#endif
     for (; T1 > 3; T1 -= 4, T0 += 4) {
-        ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0);
-        if (dst == 32)
+        env->gpr[dst++] = glue(ldl, MEMSUFFIX)((uint32_t)T0);
+        if (unlikely(dst == 32))
             dst = 0;
     }
-    if (T1 > 0) {
+    if (unlikely(T1 != 0)) {
         tmp = 0;
         for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {
-            tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
+            tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh;
         }
-        ugpr(dst) = tmp;
+        env->gpr[dst] = tmp;
     }
 }
 
+#if defined(TARGET_PPC64)
+void glue(do_lsw_64, MEMSUFFIX) (int dst)
+{
+    uint32_t tmp;
+    int sh;
+
+    for (; T1 > 3; T1 -= 4, T0 += 4) {
+        env->gpr[dst++] = glue(ldl, MEMSUFFIX)((uint64_t)T0);
+        if (unlikely(dst == 32))
+            dst = 0;
+    }
+    if (unlikely(T1 != 0)) {
+        tmp = 0;
+        for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {
+            tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh;
+        }
+        env->gpr[dst] = tmp;
+    }
+}
+#endif
+
 void glue(do_stsw, MEMSUFFIX) (int src)
 {
     int sh;
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
-                __func__, T0, T1, src);
-    }
-#endif
     for (; T1 > 3; T1 -= 4, T0 += 4) {
-        glue(stl, MEMSUFFIX)(T0, ugpr(src++));
-        if (src == 32)
+        glue(stl, MEMSUFFIX)((uint32_t)T0, env->gpr[src++]);
+        if (unlikely(src == 32))
             src = 0;
     }
-    if (T1 > 0) {
+    if (unlikely(T1 != 0)) {
         for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)
-            glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
+            glue(stb, MEMSUFFIX)((uint32_t)T0, (env->gpr[src] >> sh) & 0xFF);
     }
 }
 
+#if defined(TARGET_PPC64)
+void glue(do_stsw_64, MEMSUFFIX) (int src)
+{
+    int sh;
+
+    for (; T1 > 3; T1 -= 4, T0 += 4) {
+        glue(stl, MEMSUFFIX)((uint64_t)T0, env->gpr[src++]);
+        if (unlikely(src == 32))
+            src = 0;
+    }
+    if (unlikely(T1 != 0)) {
+        for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)
+            glue(stb, MEMSUFFIX)((uint64_t)T0, (env->gpr[src] >> sh) & 0xFF);
+    }
+}
+#endif
+
 void glue(do_lsw_le, MEMSUFFIX) (int dst)
 {
     uint32_t tmp;
     int sh;
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
-                __func__, T0, T1, dst);
-    }
-#endif
     for (; T1 > 3; T1 -= 4, T0 += 4) {
-        tmp = glue(ldl, MEMSUFFIX)(T0);
-        ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
-            ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
-        if (dst == 32)
+        env->gpr[dst++] = glue(ld32r, MEMSUFFIX)((uint32_t)T0);
+        if (unlikely(dst == 32))
             dst = 0;
     }
-    if (T1 > 0) {
+    if (unlikely(T1 != 0)) {
         tmp = 0;
         for (sh = 0; T1 > 0; T1--, T0++, sh += 8) {
-            tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
+            tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh;
         }
-        ugpr(dst) = tmp;
+        env->gpr[dst] = tmp;
     }
 }
 
-void glue(do_stsw_le, MEMSUFFIX) (int src)
+#if defined(TARGET_PPC64)
+void glue(do_lsw_le_64, MEMSUFFIX) (int dst)
 {
     uint32_t tmp;
     int sh;
 
-#if 0
-    if (loglevel > 0) {
-        fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
-                __func__, T0, T1, src);
-    }
-#endif
     for (; T1 > 3; T1 -= 4, T0 += 4) {
-        tmp = ((ugpr(src++) & 0xFF000000) >> 24);
-        tmp |= ((ugpr(src++) & 0x00FF0000) >> 8);
-        tmp |= ((ugpr(src++) & 0x0000FF00) << 8);
-        tmp |= ((ugpr(src++) & 0x000000FF) << 24);
-        glue(stl, MEMSUFFIX)(T0, tmp);
-        if (src == 32)
+        env->gpr[dst++] = glue(ld32r, MEMSUFFIX)((uint64_t)T0);
+        if (unlikely(dst == 32))
+            dst = 0;
+    }
+    if (unlikely(T1 != 0)) {
+        tmp = 0;
+        for (sh = 0; T1 > 0; T1--, T0++, sh += 8) {
+            tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh;
+        }
+        env->gpr[dst] = tmp;
+    }
+}
+#endif
+
+void glue(do_stsw_le, MEMSUFFIX) (int src)
+{
+    int sh;
+
+    for (; T1 > 3; T1 -= 4, T0 += 4) {
+        glue(st32r, MEMSUFFIX)((uint32_t)T0, env->gpr[src++]);
+        if (unlikely(src == 32))
             src = 0;
     }
-    if (T1 > 0) {
+    if (unlikely(T1 != 0)) {
         for (sh = 0; T1 > 0; T1--, T0++, sh += 8)
-            glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
+            glue(stb, MEMSUFFIX)((uint32_t)T0, (env->gpr[src] >> sh) & 0xFF);
     }
 }
 
+#if defined(TARGET_PPC64)
+void glue(do_stsw_le_64, MEMSUFFIX) (int src)
+{
+    int sh;
+
+    for (; T1 > 3; T1 -= 4, T0 += 4) {
+        glue(st32r, MEMSUFFIX)((uint64_t)T0, env->gpr[src++]);
+        if (unlikely(src == 32))
+            src = 0;
+    }
+    if (unlikely(T1 != 0)) {
+        for (sh = 0; T1 > 0; T1--, T0++, sh += 8)
+            glue(stb, MEMSUFFIX)((uint64_t)T0, (env->gpr[src] >> sh) & 0xFF);
+    }
+}
+#endif
+
+/* Instruction cache invalidation helper */
+void glue(do_icbi, MEMSUFFIX) (void)
+{
+    uint32_t tmp;
+    /* Invalidate one cache line :
+     * PowerPC specification says this is to be treated like a load
+     * (not a fetch) by the MMU. To be sure it will be so,
+     * do the load "by hand".
+     */
+    tmp = glue(ldl, MEMSUFFIX)((uint32_t)T0);
+    T0 &= ~(ICACHE_LINE_SIZE - 1);
+    tb_invalidate_page_range((uint32_t)T0, (uint32_t)(T0 + ICACHE_LINE_SIZE));
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_icbi_64, MEMSUFFIX) (void)
+{
+    uint64_t tmp;
+    /* Invalidate one cache line :
+     * PowerPC specification says this is to be treated like a load
+     * (not a fetch) by the MMU. To be sure it will be so,
+     * do the load "by hand".
+     */
+    tmp = glue(ldq, MEMSUFFIX)((uint64_t)T0);
+    T0 &= ~(ICACHE_LINE_SIZE - 1);
+    tb_invalidate_page_range((uint64_t)T0, (uint64_t)(T0 + ICACHE_LINE_SIZE));
+}
+#endif
+
+/* PowerPC 601 specific instructions (POWER bridge) */
+// XXX: to be tested
+void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb)
+{
+    int i, c, d, reg;
+
+    d = 24;
+    reg = dest;
+    for (i = 0; i < T1; i++) {
+        c = glue(ldub, MEMSUFFIX)((uint32_t)T0++);
+        /* ra (if not 0) and rb are never modified */
+        if (likely(reg != rb && (ra == 0 || reg != ra))) {
+            env->gpr[reg] = (env->gpr[reg] & ~(0xFF << d)) | (c << d);
+        }
+        if (unlikely(c == T2))
+            break;
+        if (likely(d != 0)) {
+            d -= 8;
+        } else {
+            d = 24;
+            reg++;
+            reg = reg & 0x1F;
+        }
+    }
+    T0 = i;
+}
+
+/* XXX: TAGs are not managed */
+void glue(do_POWER2_lfq, MEMSUFFIX) (void)
+{
+    FT0 = glue(ldfq, MEMSUFFIX)((uint32_t)T0);
+    FT1 = glue(ldfq, MEMSUFFIX)((uint32_t)(T0 + 4));
+}
+
+static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA)
+{
+    union {
+        double d;
+        uint64_t u;
+    } u;
+
+    u.d = glue(ldfq, MEMSUFFIX)(EA);
+    u.u = ((u.u & 0xFF00000000000000ULL) >> 56) |
+        ((u.u & 0x00FF000000000000ULL) >> 40) |
+        ((u.u & 0x0000FF0000000000ULL) >> 24) |
+        ((u.u & 0x000000FF00000000ULL) >> 8) |
+        ((u.u & 0x00000000FF000000ULL) << 8) |
+        ((u.u & 0x0000000000FF0000ULL) << 24) |
+        ((u.u & 0x000000000000FF00ULL) << 40) |
+        ((u.u & 0x00000000000000FFULL) << 56);
+
+    return u.d;
+}
+
+void glue(do_POWER2_lfq_le, MEMSUFFIX) (void)
+{
+    FT0 = glue(ldfqr, MEMSUFFIX)((uint32_t)(T0 + 4));
+    FT1 = glue(ldfqr, MEMSUFFIX)((uint32_t)T0);
+}
+
+void glue(do_POWER2_stfq, MEMSUFFIX) (void)
+{
+    glue(stfq, MEMSUFFIX)((uint32_t)T0, FT0);
+    glue(stfq, MEMSUFFIX)((uint32_t)(T0 + 4), FT1);
+}
+
+static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d)
+{
+    union {
+        double d;
+        uint64_t u;
+    } u;
+
+    u.d = d;
+    u.u = ((u.u & 0xFF00000000000000ULL) >> 56) |
+        ((u.u & 0x00FF000000000000ULL) >> 40) |
+        ((u.u & 0x0000FF0000000000ULL) >> 24) |
+        ((u.u & 0x000000FF00000000ULL) >> 8) |
+        ((u.u & 0x00000000FF000000ULL) << 8) |
+        ((u.u & 0x0000000000FF0000ULL) << 24) |
+        ((u.u & 0x000000000000FF00ULL) << 40) |
+        ((u.u & 0x00000000000000FFULL) << 56);
+    glue(stfq, MEMSUFFIX)(EA, u.d);
+}
+
+void glue(do_POWER2_stfq_le, MEMSUFFIX) (void)
+{
+    glue(stfqr, MEMSUFFIX)((uint32_t)(T0 + 4), FT0);
+    glue(stfqr, MEMSUFFIX)((uint32_t)T0, FT1);
+}
+
 #undef MEMSUFFIX
diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h
index 9b3f721..71dfb1e 100644
--- a/target-ppc/op_mem.h
+++ b/target-ppc/op_mem.h
@@ -1,6 +1,22 @@
-/* External helpers */
-void glue(do_lsw, MEMSUFFIX) (int dst);
-void glue(do_stsw, MEMSUFFIX) (int src);
+/*
+ *  PowerPC emulation micro-operations for qemu.
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * 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
+ */
 
 static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
 {
@@ -11,7 +27,7 @@
 static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA)
 {
     int16_t tmp = glue(lduw, MEMSUFFIX)(EA);
-    return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
+    return (int16_t)((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
 }
 
 static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA)
@@ -21,6 +37,35 @@
         ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
 }
 
+#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB)
+static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t tmp = glue(ldq, MEMSUFFIX)(EA);
+    return ((tmp & 0xFF00000000000000ULL) >> 56) |
+        ((tmp & 0x00FF000000000000ULL) >> 40) |
+        ((tmp & 0x0000FF0000000000ULL) >> 24) |
+        ((tmp & 0x000000FF00000000ULL) >> 8) |
+        ((tmp & 0x00000000FF000000ULL) << 8) |
+        ((tmp & 0x0000000000FF0000ULL) << 24) |
+        ((tmp & 0x000000000000FF00ULL) << 40) |
+        ((tmp & 0x00000000000000FFULL) << 54);
+}
+#endif
+
+#if defined(TARGET_PPC64)
+static inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA)
+{
+    return (int32_t)glue(ldl, MEMSUFFIX)(EA);
+}
+
+static inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA)
+{
+    uint32_t tmp = glue(ldl, MEMSUFFIX)(EA);
+    return (int32_t)((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
+        ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
+}
+#endif
+
 static inline void glue(st16r, MEMSUFFIX) (target_ulong EA, uint16_t data)
 {
     uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8);
@@ -34,158 +79,355 @@
     glue(stl, MEMSUFFIX)(EA, tmp);
 }
 
+#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB)
+static inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    uint64_t tmp = ((data & 0xFF00000000000000ULL) >> 56) |
+        ((data & 0x00FF000000000000ULL) >> 40) |
+        ((data & 0x0000FF0000000000ULL) >> 24) |
+        ((data & 0x000000FF00000000ULL) >> 8) |
+        ((data & 0x00000000FF000000ULL) << 8) |
+        ((data & 0x0000000000FF0000ULL) << 24) |
+        ((data & 0x000000000000FF00ULL) << 40) |
+        ((data & 0x00000000000000FFULL) << 56);
+    glue(stq, MEMSUFFIX)(EA, tmp);
+}
+#endif
+
 /***                             Integer load                              ***/
 #define PPC_LD_OP(name, op)                                                   \
-PPC_OP(glue(glue(l, name), MEMSUFFIX))                                        \
+void OPPROTO glue(glue(op_l, name), MEMSUFFIX) (void)                         \
 {                                                                             \
-    T1 = glue(op, MEMSUFFIX)(T0);                                             \
+    T1 = glue(op, MEMSUFFIX)((uint32_t)T0);                                   \
     RETURN();                                                                 \
 }
 
-#define PPC_ST_OP(name, op)                                                   \
-PPC_OP(glue(glue(st, name), MEMSUFFIX))                                       \
+#if defined(TARGET_PPC64)
+#define PPC_LD_OP_64(name, op)                                                \
+void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void)              \
 {                                                                             \
-    glue(op, MEMSUFFIX)(T0, T1);                                              \
+    T1 = glue(op, MEMSUFFIX)((uint64_t)T0);                                   \
     RETURN();                                                                 \
 }
+#endif
+
+#define PPC_ST_OP(name, op)                                                   \
+void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void)                        \
+{                                                                             \
+    glue(op, MEMSUFFIX)((uint32_t)T0, T1);                                    \
+    RETURN();                                                                 \
+}
+
+#if defined(TARGET_PPC64)
+#define PPC_ST_OP_64(name, op)                                                \
+void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void)             \
+{                                                                             \
+    glue(op, MEMSUFFIX)((uint64_t)T0, T1);                                    \
+    RETURN();                                                                 \
+}
+#endif
 
 PPC_LD_OP(bz, ldub);
 PPC_LD_OP(ha, ldsw);
 PPC_LD_OP(hz, lduw);
 PPC_LD_OP(wz, ldl);
+#if defined(TARGET_PPC64)
+PPC_LD_OP(d, ldq);
+PPC_LD_OP(wa, ldsl);
+PPC_LD_OP_64(d, ldq);
+PPC_LD_OP_64(wa, ldsl);
+PPC_LD_OP_64(bz, ldub);
+PPC_LD_OP_64(ha, ldsw);
+PPC_LD_OP_64(hz, lduw);
+PPC_LD_OP_64(wz, ldl);
+#endif
 
 PPC_LD_OP(ha_le, ld16rs);
 PPC_LD_OP(hz_le, ld16r);
 PPC_LD_OP(wz_le, ld32r);
+#if defined(TARGET_PPC64)
+PPC_LD_OP(d_le, ld64r);
+PPC_LD_OP(wa_le, ld32rs);
+PPC_LD_OP_64(d_le, ld64r);
+PPC_LD_OP_64(wa_le, ld32rs);
+PPC_LD_OP_64(ha_le, ld16rs);
+PPC_LD_OP_64(hz_le, ld16r);
+PPC_LD_OP_64(wz_le, ld32r);
+#endif
 
 /***                              Integer store                            ***/
 PPC_ST_OP(b, stb);
 PPC_ST_OP(h, stw);
 PPC_ST_OP(w, stl);
+#if defined(TARGET_PPC64)
+PPC_ST_OP(d, stq);
+PPC_ST_OP_64(d, stq);
+PPC_ST_OP_64(b, stb);
+PPC_ST_OP_64(h, stw);
+PPC_ST_OP_64(w, stl);
+#endif
 
 PPC_ST_OP(h_le, st16r);
 PPC_ST_OP(w_le, st32r);
+#if defined(TARGET_PPC64)
+PPC_ST_OP(d_le, st64r);
+PPC_ST_OP_64(d_le, st64r);
+PPC_ST_OP_64(h_le, st16r);
+PPC_ST_OP_64(w_le, st32r);
+#endif
 
 /***                Integer load and store with byte reverse               ***/
 PPC_LD_OP(hbr, ld16r);
 PPC_LD_OP(wbr, ld32r);
 PPC_ST_OP(hbr, st16r);
 PPC_ST_OP(wbr, st32r);
+#if defined(TARGET_PPC64)
+PPC_LD_OP_64(hbr, ld16r);
+PPC_LD_OP_64(wbr, ld32r);
+PPC_ST_OP_64(hbr, st16r);
+PPC_ST_OP_64(wbr, st32r);
+#endif
 
 PPC_LD_OP(hbr_le, lduw);
 PPC_LD_OP(wbr_le, ldl);
 PPC_ST_OP(hbr_le, stw);
 PPC_ST_OP(wbr_le, stl);
+#if defined(TARGET_PPC64)
+PPC_LD_OP_64(hbr_le, lduw);
+PPC_LD_OP_64(wbr_le, ldl);
+PPC_ST_OP_64(hbr_le, stw);
+PPC_ST_OP_64(wbr_le, stl);
+#endif
 
 /***                    Integer load and store multiple                    ***/
-PPC_OP(glue(lmw, MEMSUFFIX))
+void OPPROTO glue(op_lmw, MEMSUFFIX) (void)
 {
-    int dst = PARAM(1);
-
-    for (; dst < 32; dst++, T0 += 4) {
-        ugpr(dst) = glue(ldl, MEMSUFFIX)(T0);
-    }
+    glue(do_lmw, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
-PPC_OP(glue(stmw, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lmw_64, MEMSUFFIX) (void)
 {
-    int src = PARAM(1);
+    glue(do_lmw_64, MEMSUFFIX)(PARAM1);
+    RETURN();
+}
+#endif
 
-    for (; src < 32; src++, T0 += 4) {
-        glue(stl, MEMSUFFIX)(T0, ugpr(src));
-    }
+void OPPROTO glue(op_lmw_le, MEMSUFFIX) (void)
+{
+    glue(do_lmw_le, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
-PPC_OP(glue(lmw_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lmw_le_64, MEMSUFFIX) (void)
 {
-    int dst = PARAM(1);
+    glue(do_lmw_le_64, MEMSUFFIX)(PARAM1);
+    RETURN();
+}
+#endif
 
-    for (; dst < 32; dst++, T0 += 4) {
-        ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0);
-    }
+void OPPROTO glue(op_stmw, MEMSUFFIX) (void)
+{
+    glue(do_stmw, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
-PPC_OP(glue(stmw_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stmw_64, MEMSUFFIX) (void)
 {
-    int src = PARAM(1);
-
-    for (; src < 32; src++, T0 += 4) {
-        glue(st32r, MEMSUFFIX)(T0, ugpr(src));
-    }
+    glue(do_stmw_64, MEMSUFFIX)(PARAM1);
     RETURN();
 }
+#endif
+
+void OPPROTO glue(op_stmw_le, MEMSUFFIX) (void)
+{
+    glue(do_stmw_le, MEMSUFFIX)(PARAM1);
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stmw_le_64, MEMSUFFIX) (void)
+{
+    glue(do_stmw_le_64, MEMSUFFIX)(PARAM1);
+    RETURN();
+}
+#endif
 
 /***                    Integer load and store strings                     ***/
-PPC_OP(glue(lswi, MEMSUFFIX))
+void OPPROTO glue(op_lswi, MEMSUFFIX) (void)
 {
-    glue(do_lsw, MEMSUFFIX)(PARAM(1));
+    glue(do_lsw, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
-void glue(do_lsw_le, MEMSUFFIX) (int dst);
-PPC_OP(glue(lswi_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lswi_64, MEMSUFFIX) (void)
 {
-    glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
+    glue(do_lsw_64, MEMSUFFIX)(PARAM1);
     RETURN();
 }
+#endif
+
+void OPPROTO glue(op_lswi_le, MEMSUFFIX) (void)
+{
+    glue(do_lsw_le, MEMSUFFIX)(PARAM1);
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lswi_le_64, MEMSUFFIX) (void)
+{
+    glue(do_lsw_le_64, MEMSUFFIX)(PARAM1);
+    RETURN();
+}
+#endif
 
 /* PPC32 specification says we must generate an exception if
  * rA is in the range of registers to be loaded.
  * In an other hand, IBM says this is valid, but rA won't be loaded.
  * For now, I'll follow the spec...
  */
-PPC_OP(glue(lswx, MEMSUFFIX))
+void OPPROTO glue(op_lswx, MEMSUFFIX) (void)
 {
-    if (T1 > 0) {
-        if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
-            (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
-            do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+    /* Note: T1 comes from xer_bc then no cast is needed */
+    if (likely(T1 != 0)) {
+        if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+                     (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
+            do_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL |
+                                   POWERPC_EXCP_INVAL_LSWX);
         } else {
-            glue(do_lsw, MEMSUFFIX)(PARAM(1));
+            glue(do_lsw, MEMSUFFIX)(PARAM1);
         }
     }
     RETURN();
 }
 
-PPC_OP(glue(lswx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lswx_64, MEMSUFFIX) (void)
 {
-    if (T1 > 0) {
-        if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
-            (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
-            do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+    /* Note: T1 comes from xer_bc then no cast is needed */
+    if (likely(T1 != 0)) {
+        if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+                     (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
+            do_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL |
+                                   POWERPC_EXCP_INVAL_LSWX);
         } else {
-            glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
+            glue(do_lsw_64, MEMSUFFIX)(PARAM1);
+        }
+    }
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_lswx_le, MEMSUFFIX) (void)
+{
+    /* Note: T1 comes from xer_bc then no cast is needed */
+    if (likely(T1 != 0)) {
+        if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+                     (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
+            do_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL |
+                                   POWERPC_EXCP_INVAL_LSWX);
+        } else {
+            glue(do_lsw_le, MEMSUFFIX)(PARAM1);
         }
     }
     RETURN();
 }
 
-PPC_OP(glue(stsw, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lswx_le_64, MEMSUFFIX) (void)
 {
-    glue(do_stsw, MEMSUFFIX)(PARAM(1));
+    /* Note: T1 comes from xer_bc then no cast is needed */
+    if (likely(T1 != 0)) {
+        if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+                     (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
+            do_raise_exception_err(POWERPC_EXCP_PROGRAM,
+                                   POWERPC_EXCP_INVAL |
+                                   POWERPC_EXCP_INVAL_LSWX);
+        } else {
+            glue(do_lsw_le_64, MEMSUFFIX)(PARAM1);
+        }
+    }
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_stsw, MEMSUFFIX) (void)
+{
+    glue(do_stsw, MEMSUFFIX)(PARAM1);
     RETURN();
 }
 
-void glue(do_stsw_le, MEMSUFFIX) (int src);
-PPC_OP(glue(stsw_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stsw_64, MEMSUFFIX) (void)
 {
-    glue(do_stsw_le, MEMSUFFIX)(PARAM(1));
+    glue(do_stsw_64, MEMSUFFIX)(PARAM1);
     RETURN();
 }
+#endif
+
+void OPPROTO glue(op_stsw_le, MEMSUFFIX) (void)
+{
+    glue(do_stsw_le, MEMSUFFIX)(PARAM1);
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stsw_le_64, MEMSUFFIX) (void)
+{
+    glue(do_stsw_le_64, MEMSUFFIX)(PARAM1);
+    RETURN();
+}
+#endif
 
 /***                         Floating-point store                          ***/
 #define PPC_STF_OP(name, op)                                                  \
-PPC_OP(glue(glue(st, name), MEMSUFFIX))                                       \
+void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void)                        \
 {                                                                             \
-    glue(op, MEMSUFFIX)(T0, FT1);                                     \
+    glue(op, MEMSUFFIX)((uint32_t)T0, FT0);                                   \
     RETURN();                                                                 \
 }
 
+#if defined(TARGET_PPC64)
+#define PPC_STF_OP_64(name, op)                                               \
+void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void)             \
+{                                                                             \
+    glue(op, MEMSUFFIX)((uint64_t)T0, FT0);                                   \
+    RETURN();                                                                 \
+}
+#endif
+
+static inline void glue(stfs, MEMSUFFIX) (target_ulong EA, double d)
+{
+    glue(stfl, MEMSUFFIX)(EA, float64_to_float32(d, &env->fp_status));
+}
+
+static inline void glue(stfiwx, MEMSUFFIX) (target_ulong EA, double d)
+{
+    union {
+        double d;
+        uint64_t u;
+    } u;
+
+    /* Store the low order 32 bits without any conversion */
+    u.d = d;
+    glue(stl, MEMSUFFIX)(EA, u.u);
+}
+
 PPC_STF_OP(fd, stfq);
-PPC_STF_OP(fs, stfl);
+PPC_STF_OP(fs, stfs);
+PPC_STF_OP(fiwx, stfiwx);
+#if defined(TARGET_PPC64)
+PPC_STF_OP_64(fd, stfq);
+PPC_STF_OP_64(fs, stfs);
+PPC_STF_OP_64(fiwx, stfiwx);
+#endif
 
 static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d)
 {
@@ -206,14 +448,14 @@
     glue(stfq, MEMSUFFIX)(EA, u.d);
 }
 
-static inline void glue(stflr, MEMSUFFIX) (target_ulong EA, float f)
+static inline void glue(stfsr, MEMSUFFIX) (target_ulong EA, double d)
 {
     union {
         float f;
         uint32_t u;
     } u;
 
-    u.f = f;
+    u.f = float64_to_float32(d, &env->fp_status);
     u.u = ((u.u & 0xFF000000UL) >> 24) |
         ((u.u & 0x00FF0000ULL) >> 8) |
         ((u.u & 0x0000FF00UL) << 8) |
@@ -221,19 +463,60 @@
     glue(stfl, MEMSUFFIX)(EA, u.f);
 }
 
+static inline void glue(stfiwxr, MEMSUFFIX) (target_ulong EA, double d)
+{
+    union {
+        double d;
+        uint64_t u;
+    } u;
+
+    /* Store the low order 32 bits without any conversion */
+    u.d = d;
+    u.u = ((u.u & 0xFF000000UL) >> 24) |
+        ((u.u & 0x00FF0000ULL) >> 8) |
+        ((u.u & 0x0000FF00UL) << 8) |
+        ((u.u & 0x000000FFULL) << 24);
+    glue(stl, MEMSUFFIX)(EA, u.u);
+}
+
+
 PPC_STF_OP(fd_le, stfqr);
-PPC_STF_OP(fs_le, stflr);
+PPC_STF_OP(fs_le, stfsr);
+PPC_STF_OP(fiwx_le, stfiwxr);
+#if defined(TARGET_PPC64)
+PPC_STF_OP_64(fd_le, stfqr);
+PPC_STF_OP_64(fs_le, stfsr);
+PPC_STF_OP_64(fiwx_le, stfiwxr);
+#endif
 
 /***                         Floating-point load                           ***/
 #define PPC_LDF_OP(name, op)                                                  \
-PPC_OP(glue(glue(l, name), MEMSUFFIX))                                        \
+void OPPROTO glue(glue(op_l, name), MEMSUFFIX) (void)                         \
 {                                                                             \
-    FT1 = glue(op, MEMSUFFIX)(T0);                                    \
+    FT0 = glue(op, MEMSUFFIX)((uint32_t)T0);                                  \
     RETURN();                                                                 \
 }
 
+#if defined(TARGET_PPC64)
+#define PPC_LDF_OP_64(name, op)                                               \
+void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void)              \
+{                                                                             \
+    FT0 = glue(op, MEMSUFFIX)((uint64_t)T0);                                  \
+    RETURN();                                                                 \
+}
+#endif
+
+static inline double glue(ldfs, MEMSUFFIX) (target_ulong EA)
+{
+    return float32_to_float64(glue(ldfl, MEMSUFFIX)(EA), &env->fp_status);
+}
+
 PPC_LDF_OP(fd, ldfq);
-PPC_LDF_OP(fs, ldfl);
+PPC_LDF_OP(fs, ldfs);
+#if defined(TARGET_PPC64)
+PPC_LDF_OP_64(fd, ldfq);
+PPC_LDF_OP_64(fs, ldfs);
+#endif
 
 static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA)
 {
@@ -255,7 +538,7 @@
     return u.d;
 }
 
-static inline float glue(ldflr, MEMSUFFIX) (target_ulong EA)
+static inline double glue(ldfsr, MEMSUFFIX) (target_ulong EA)
 {
     union {
         float f;
@@ -268,104 +551,657 @@
         ((u.u & 0x0000FF00UL) << 8) |
         ((u.u & 0x000000FFULL) << 24);
 
-    return u.f;
+    return float32_to_float64(u.f, &env->fp_status);
 }
 
 PPC_LDF_OP(fd_le, ldfqr);
-PPC_LDF_OP(fs_le, ldflr);
+PPC_LDF_OP(fs_le, ldfsr);
+#if defined(TARGET_PPC64)
+PPC_LDF_OP_64(fd_le, ldfqr);
+PPC_LDF_OP_64(fs_le, ldfsr);
+#endif
 
 /* Load and set reservation */
-PPC_OP(glue(lwarx, MEMSUFFIX))
+void OPPROTO glue(op_lwarx, MEMSUFFIX) (void)
 {
-    if (T0 & 0x03) {
-        do_raise_exception(EXCP_ALIGN);
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
     } else {
-       T1 = glue(ldl, MEMSUFFIX)(T0);
-       regs->reserve = T0;
+        T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0);
+        env->reserve = (uint32_t)T0;
     }
     RETURN();
 }
 
-PPC_OP(glue(lwarx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void)
 {
-    if (T0 & 0x03) {
-        do_raise_exception(EXCP_ALIGN);
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
     } else {
-       T1 = glue(ld32r, MEMSUFFIX)(T0);
-       regs->reserve = T0;
+        T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0);
+        env->reserve = (uint64_t)T0;
     }
     RETURN();
 }
 
+void OPPROTO glue(op_ldarx, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        T1 = glue(ldq, MEMSUFFIX)((uint32_t)T0);
+        env->reserve = (uint32_t)T0;
+    }
+    RETURN();
+}
+
+void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        T1 = glue(ldq, MEMSUFFIX)((uint64_t)T0);
+        env->reserve = (uint64_t)T0;
+    }
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_lwarx_le, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0);
+        env->reserve = (uint32_t)T0;
+    }
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0);
+        env->reserve = (uint64_t)T0;
+    }
+    RETURN();
+}
+
+void OPPROTO glue(op_ldarx_le, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        T1 = glue(ld64r, MEMSUFFIX)((uint32_t)T0);
+        env->reserve = (uint32_t)T0;
+    }
+    RETURN();
+}
+
+void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        T1 = glue(ld64r, MEMSUFFIX)((uint64_t)T0);
+        env->reserve = (uint64_t)T0;
+    }
+    RETURN();
+}
+#endif
+
 /* Store with reservation */
-PPC_OP(glue(stwcx, MEMSUFFIX))
+void OPPROTO glue(op_stwcx, MEMSUFFIX) (void)
 {
-    if (T0 & 0x03) {
-        do_raise_exception(EXCP_ALIGN);
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
     } else {
-        if (regs->reserve != T0) {
-            env->crf[0] = xer_ov;
+        if (unlikely(env->reserve != (uint32_t)T0)) {
+            env->crf[0] = xer_so;
         } else {
-            glue(stl, MEMSUFFIX)(T0, T1);
-            env->crf[0] = xer_ov | 0x02;
+            glue(stl, MEMSUFFIX)((uint32_t)T0, T1);
+            env->crf[0] = xer_so | 0x02;
         }
     }
-    regs->reserve = 0;
+    env->reserve = -1;
     RETURN();
 }
 
-PPC_OP(glue(stwcx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void)
 {
-    if (T0 & 0x03) {
-        do_raise_exception(EXCP_ALIGN);
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
     } else {
-        if (regs->reserve != T0) {
-            env->crf[0] = xer_ov;
+        if (unlikely(env->reserve != (uint64_t)T0)) {
+            env->crf[0] = xer_so;
         } else {
-            glue(st32r, MEMSUFFIX)(T0, T1);
-            env->crf[0] = xer_ov | 0x02;
+            glue(stl, MEMSUFFIX)((uint64_t)T0, T1);
+            env->crf[0] = xer_so | 0x02;
         }
     }
-    regs->reserve = 0;
+    env->reserve = -1;
     RETURN();
 }
 
-PPC_OP(glue(dcbz, MEMSUFFIX))
+void OPPROTO glue(op_stdcx, MEMSUFFIX) (void)
 {
-    glue(stl, MEMSUFFIX)(T0 + 0x00, 0);
-    glue(stl, MEMSUFFIX)(T0 + 0x04, 0);
-    glue(stl, MEMSUFFIX)(T0 + 0x08, 0);
-    glue(stl, MEMSUFFIX)(T0 + 0x0C, 0);
-    glue(stl, MEMSUFFIX)(T0 + 0x10, 0);
-    glue(stl, MEMSUFFIX)(T0 + 0x14, 0);
-    glue(stl, MEMSUFFIX)(T0 + 0x18, 0);
-    glue(stl, MEMSUFFIX)(T0 + 0x1C, 0);
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        if (unlikely(env->reserve != (uint32_t)T0)) {
+            env->crf[0] = xer_so;
+        } else {
+            glue(stq, MEMSUFFIX)((uint32_t)T0, T1);
+            env->crf[0] = xer_so | 0x02;
+        }
+    }
+    env->reserve = -1;
     RETURN();
 }
 
+void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        if (unlikely(env->reserve != (uint64_t)T0)) {
+            env->crf[0] = xer_so;
+        } else {
+            glue(stq, MEMSUFFIX)((uint64_t)T0, T1);
+            env->crf[0] = xer_so | 0x02;
+        }
+    }
+    env->reserve = -1;
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_stwcx_le, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        if (unlikely(env->reserve != (uint32_t)T0)) {
+            env->crf[0] = xer_so;
+        } else {
+            glue(st32r, MEMSUFFIX)((uint32_t)T0, T1);
+            env->crf[0] = xer_so | 0x02;
+        }
+    }
+    env->reserve = -1;
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        if (unlikely(env->reserve != (uint64_t)T0)) {
+            env->crf[0] = xer_so;
+        } else {
+            glue(st32r, MEMSUFFIX)((uint64_t)T0, T1);
+            env->crf[0] = xer_so | 0x02;
+        }
+    }
+    env->reserve = -1;
+    RETURN();
+}
+
+void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        if (unlikely(env->reserve != (uint32_t)T0)) {
+            env->crf[0] = xer_so;
+        } else {
+            glue(st64r, MEMSUFFIX)((uint32_t)T0, T1);
+            env->crf[0] = xer_so | 0x02;
+        }
+    }
+    env->reserve = -1;
+    RETURN();
+}
+
+void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void)
+{
+    if (unlikely(T0 & 0x03)) {
+        do_raise_exception(POWERPC_EXCP_ALIGN);
+    } else {
+        if (unlikely(env->reserve != (uint64_t)T0)) {
+            env->crf[0] = xer_so;
+        } else {
+            glue(st64r, MEMSUFFIX)((uint64_t)T0, T1);
+            env->crf[0] = xer_so | 0x02;
+        }
+    }
+    env->reserve = -1;
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_dcbz, MEMSUFFIX) (void)
+{
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0);
+#if DCACHE_LINE_SIZE == 64
+    /* XXX: cache line size should be 64 for POWER & PowerPC 601 */
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0);
+    glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0);
+#endif
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_dcbz_64, MEMSUFFIX) (void)
+{
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0);
+#if DCACHE_LINE_SIZE == 64
+    /* XXX: cache line size should be 64 for POWER & PowerPC 601 */
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0);
+    glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0);
+#endif
+    RETURN();
+}
+#endif
+
+/* Instruction cache block invalidate */
+void OPPROTO glue(op_icbi, MEMSUFFIX) (void)
+{
+    glue(do_icbi, MEMSUFFIX)();
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_icbi_64, MEMSUFFIX) (void)
+{
+    glue(do_icbi_64, MEMSUFFIX)();
+    RETURN();
+}
+#endif
+
 /* External access */
-PPC_OP(glue(eciwx, MEMSUFFIX))
+void OPPROTO glue(op_eciwx, MEMSUFFIX) (void)
 {
-    T1 = glue(ldl, MEMSUFFIX)(T0);
+    T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0);
     RETURN();
 }
 
-PPC_OP(glue(ecowx, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_eciwx_64, MEMSUFFIX) (void)
 {
-    glue(stl, MEMSUFFIX)(T0, T1);
+    T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0);
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_ecowx, MEMSUFFIX) (void)
+{
+    glue(stl, MEMSUFFIX)((uint32_t)T0, T1);
     RETURN();
 }
 
-PPC_OP(glue(eciwx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_ecowx_64, MEMSUFFIX) (void)
 {
-    T1 = glue(ld32r, MEMSUFFIX)(T0);
+    glue(stl, MEMSUFFIX)((uint64_t)T0, T1);
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_eciwx_le, MEMSUFFIX) (void)
+{
+    T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0);
     RETURN();
 }
 
-PPC_OP(glue(ecowx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_eciwx_le_64, MEMSUFFIX) (void)
 {
-    glue(st32r, MEMSUFFIX)(T0, T1);
+    T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0);
     RETURN();
 }
+#endif
+
+void OPPROTO glue(op_ecowx_le, MEMSUFFIX) (void)
+{
+    glue(st32r, MEMSUFFIX)((uint32_t)T0, T1);
+    RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_ecowx_le_64, MEMSUFFIX) (void)
+{
+    glue(st32r, MEMSUFFIX)((uint64_t)T0, T1);
+    RETURN();
+}
+#endif
+
+/* XXX: those micro-ops need tests ! */
+/* PowerPC 601 specific instructions (POWER bridge) */
+void OPPROTO glue(op_POWER_lscbx, MEMSUFFIX) (void)
+{
+    /* When byte count is 0, do nothing */
+    if (likely(T1 != 0)) {
+        glue(do_POWER_lscbx, MEMSUFFIX)(PARAM1, PARAM2, PARAM3);
+    }
+    RETURN();
+}
+
+/* POWER2 quad load and store */
+/* XXX: TAGs are not managed */
+void OPPROTO glue(op_POWER2_lfq, MEMSUFFIX) (void)
+{
+    glue(do_POWER2_lfq, MEMSUFFIX)();
+    RETURN();
+}
+
+void glue(op_POWER2_lfq_le, MEMSUFFIX) (void)
+{
+    glue(do_POWER2_lfq_le, MEMSUFFIX)();
+    RETURN();
+}
+
+void OPPROTO glue(op_POWER2_stfq, MEMSUFFIX) (void)
+{
+    glue(do_POWER2_stfq, MEMSUFFIX)();
+    RETURN();
+}
+
+void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void)
+{
+    glue(do_POWER2_stfq_le, MEMSUFFIX)();
+    RETURN();
+}
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension */
+#define _PPC_SPE_LD_OP(name, op)                                              \
+void OPPROTO glue(glue(op_spe_l, name), MEMSUFFIX) (void)                     \
+{                                                                             \
+    T1_64 = glue(op, MEMSUFFIX)((uint32_t)T0);                                \
+    RETURN();                                                                 \
+}
+
+#if defined(TARGET_PPC64)
+#define _PPC_SPE_LD_OP_64(name, op)                                           \
+void OPPROTO glue(glue(glue(op_spe_l, name), _64), MEMSUFFIX) (void)          \
+{                                                                             \
+    T1_64 = glue(op, MEMSUFFIX)((uint64_t)T0);                                \
+    RETURN();                                                                 \
+}
+#define PPC_SPE_LD_OP(name, op)                                               \
+_PPC_SPE_LD_OP(name, op);                                                     \
+_PPC_SPE_LD_OP_64(name, op)
+#else
+#define PPC_SPE_LD_OP(name, op)                                               \
+_PPC_SPE_LD_OP(name, op)
+#endif
+
+
+#define _PPC_SPE_ST_OP(name, op)                                              \
+void OPPROTO glue(glue(op_spe_st, name), MEMSUFFIX) (void)                    \
+{                                                                             \
+    glue(op, MEMSUFFIX)((uint32_t)T0, T1_64);                                 \
+    RETURN();                                                                 \
+}
+
+#if defined(TARGET_PPC64)
+#define _PPC_SPE_ST_OP_64(name, op)                                           \
+void OPPROTO glue(glue(glue(op_spe_st, name), _64), MEMSUFFIX) (void)         \
+{                                                                             \
+    glue(op, MEMSUFFIX)((uint64_t)T0, T1_64);                                 \
+    RETURN();                                                                 \
+}
+#define PPC_SPE_ST_OP(name, op)                                               \
+_PPC_SPE_ST_OP(name, op);                                                     \
+_PPC_SPE_ST_OP_64(name, op)
+#else
+#define PPC_SPE_ST_OP(name, op)                                               \
+_PPC_SPE_ST_OP(name, op)
+#endif
+
+#if !defined(TARGET_PPC64)
+PPC_SPE_LD_OP(dd, ldq);
+PPC_SPE_ST_OP(dd, stq);
+PPC_SPE_LD_OP(dd_le, ld64r);
+PPC_SPE_ST_OP(dd_le, st64r);
+#endif
+static inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ldl, MEMSUFFIX)(EA) << 32;
+    ret |= (uint64_t)glue(ldl, MEMSUFFIX)(EA + 4);
+    return ret;
+}
+PPC_SPE_LD_OP(dw, spe_ldw);
+static inline void glue(spe_stdw, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stl, MEMSUFFIX)(EA, data >> 32);
+    glue(stl, MEMSUFFIX)(EA + 4, data);
+}
+PPC_SPE_ST_OP(dw, spe_stdw);
+static inline uint64_t glue(spe_ldw_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ld32r, MEMSUFFIX)(EA) << 32;
+    ret |= (uint64_t)glue(ld32r, MEMSUFFIX)(EA + 4);
+    return ret;
+}
+PPC_SPE_LD_OP(dw_le, spe_ldw_le);
+static inline void glue(spe_stdw_le, MEMSUFFIX) (target_ulong EA,
+                                                 uint64_t data)
+{
+    glue(st32r, MEMSUFFIX)(EA, data >> 32);
+    glue(st32r, MEMSUFFIX)(EA + 4, data);
+}
+PPC_SPE_ST_OP(dw_le, spe_stdw_le);
+static inline uint64_t glue(spe_ldh, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 32;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 4) << 16;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 6);
+    return ret;
+}
+PPC_SPE_LD_OP(dh, spe_ldh);
+static inline void glue(spe_stdh, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stw, MEMSUFFIX)(EA, data >> 48);
+    glue(stw, MEMSUFFIX)(EA + 2, data >> 32);
+    glue(stw, MEMSUFFIX)(EA + 4, data >> 16);
+    glue(stw, MEMSUFFIX)(EA + 6, data);
+}
+PPC_SPE_ST_OP(dh, spe_stdh);
+static inline uint64_t glue(spe_ldh_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 32;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 4) << 16;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 6);
+    return ret;
+}
+PPC_SPE_LD_OP(dh_le, spe_ldh_le);
+static inline void glue(spe_stdh_le, MEMSUFFIX) (target_ulong EA,
+                                                 uint64_t data)
+{
+    glue(st16r, MEMSUFFIX)(EA, data >> 48);
+    glue(st16r, MEMSUFFIX)(EA + 2, data >> 32);
+    glue(st16r, MEMSUFFIX)(EA + 4, data >> 16);
+    glue(st16r, MEMSUFFIX)(EA + 6, data);
+}
+PPC_SPE_ST_OP(dh_le, spe_stdh_le);
+static inline uint64_t glue(spe_lwhe, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 16;
+    return ret;
+}
+PPC_SPE_LD_OP(whe, spe_lwhe);
+static inline void glue(spe_stwhe, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stw, MEMSUFFIX)(EA, data >> 48);
+    glue(stw, MEMSUFFIX)(EA + 2, data >> 16);
+}
+PPC_SPE_ST_OP(whe, spe_stwhe);
+static inline uint64_t glue(spe_lwhe_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 16;
+    return ret;
+}
+PPC_SPE_LD_OP(whe_le, spe_lwhe_le);
+static inline void glue(spe_stwhe_le, MEMSUFFIX) (target_ulong EA,
+                                                  uint64_t data)
+{
+    glue(st16r, MEMSUFFIX)(EA, data >> 48);
+    glue(st16r, MEMSUFFIX)(EA + 2, data >> 16);
+}
+PPC_SPE_ST_OP(whe_le, spe_stwhe_le);
+static inline uint64_t glue(spe_lwhou, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 32;
+    ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2);
+    return ret;
+}
+PPC_SPE_LD_OP(whou, spe_lwhou);
+static inline uint64_t glue(spe_lwhos, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = ((uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA))) << 32;
+    ret |= (uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA + 2));
+    return ret;
+}
+PPC_SPE_LD_OP(whos, spe_lwhos);
+static inline void glue(spe_stwho, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stw, MEMSUFFIX)(EA, data >> 32);
+    glue(stw, MEMSUFFIX)(EA + 2, data);
+}
+PPC_SPE_ST_OP(who, spe_stwho);
+static inline uint64_t glue(spe_lwhou_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 32;
+    ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2);
+    return ret;
+}
+PPC_SPE_LD_OP(whou_le, spe_lwhou_le);
+static inline uint64_t glue(spe_lwhos_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    ret = ((uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA))) << 32;
+    ret |= (uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA + 2));
+    return ret;
+}
+PPC_SPE_LD_OP(whos_le, spe_lwhos_le);
+static inline void glue(spe_stwho_le, MEMSUFFIX) (target_ulong EA,
+                                                  uint64_t data)
+{
+    glue(st16r, MEMSUFFIX)(EA, data >> 32);
+    glue(st16r, MEMSUFFIX)(EA + 2, data);
+}
+PPC_SPE_ST_OP(who_le, spe_stwho_le);
+#if !defined(TARGET_PPC64)
+static inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+    glue(stl, MEMSUFFIX)(EA, data);
+}
+PPC_SPE_ST_OP(wwo, spe_stwwo);
+static inline void glue(spe_stwwo_le, MEMSUFFIX) (target_ulong EA,
+                                                  uint64_t data)
+{
+    glue(st32r, MEMSUFFIX)(EA, data);
+}
+PPC_SPE_ST_OP(wwo_le, spe_stwwo_le);
+#endif
+static inline uint64_t glue(spe_lh, MEMSUFFIX) (target_ulong EA)
+{
+    uint16_t tmp;
+    tmp = glue(lduw, MEMSUFFIX)(EA);
+    return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16);
+}
+PPC_SPE_LD_OP(h, spe_lh);
+static inline uint64_t glue(spe_lh_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint16_t tmp;
+    tmp = glue(ld16r, MEMSUFFIX)(EA);
+    return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16);
+}
+PPC_SPE_LD_OP(h_le, spe_lh_le);
+static inline uint64_t glue(spe_lwwsplat, MEMSUFFIX) (target_ulong EA)
+{
+    uint32_t tmp;
+    tmp = glue(ldl, MEMSUFFIX)(EA);
+    return ((uint64_t)tmp << 32) | (uint64_t)tmp;
+}
+PPC_SPE_LD_OP(wwsplat, spe_lwwsplat);
+static inline uint64_t glue(spe_lwwsplat_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint32_t tmp;
+    tmp = glue(ld32r, MEMSUFFIX)(EA);
+    return ((uint64_t)tmp << 32) | (uint64_t)tmp;
+}
+PPC_SPE_LD_OP(wwsplat_le, spe_lwwsplat_le);
+static inline uint64_t glue(spe_lwhsplat, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    uint16_t tmp;
+    tmp = glue(lduw, MEMSUFFIX)(EA);
+    ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32);
+    tmp = glue(lduw, MEMSUFFIX)(EA + 2);
+    ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp;
+    return ret;
+}
+PPC_SPE_LD_OP(whsplat, spe_lwhsplat);
+static inline uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA)
+{
+    uint64_t ret;
+    uint16_t tmp;
+    tmp = glue(ld16r, MEMSUFFIX)(EA);
+    ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32);
+    tmp = glue(ld16r, MEMSUFFIX)(EA + 2);
+    ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp;
+    return ret;
+}
+PPC_SPE_LD_OP(whsplat_le, spe_lwhsplat_le);
+#endif /* defined(TARGET_PPCEMB) */
 
 #undef MEMSUFFIX
diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h
index 1be640d..d450625 100644
--- a/target-ppc/op_template.h
+++ b/target-ppc/op_template.h
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation micro-operations for qemu.
- * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,109 +19,141 @@
  */
 
 /* General purpose registers moves */
-void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T0_gpr, REG) (void)
 {
-    T0 = regs->gpr[REG];
+    T0 = env->gpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T1_gpr, REG) (void)
 {
-    T1 = regs->gpr[REG];
+    T1 = env->gpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T2_gpr, REG) (void)
 {
-    T2 = regs->gpr[REG];
+    T2 = env->gpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void)
+void OPPROTO glue(op_store_T0_gpr_gpr, REG) (void)
 {
-    regs->gpr[REG] = T0;
+    env->gpr[REG] = T0;
     RETURN();
 }
 
-void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void)
+void OPPROTO glue(op_store_T1_gpr_gpr, REG) (void)
 {
-    regs->gpr[REG] = T1;
+    env->gpr[REG] = T1;
     RETURN();
 }
 
-void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void)
+#if 0 // unused
+void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void)
 {
-    regs->gpr[REG] = T2;
+    env->gpr[REG] = T2;
     RETURN();
 }
+#endif
+
+#if defined(TARGET_PPCEMB)
+void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void)
+{
+    T0_64 = env->gpr[REG];
+    RETURN();
+}
+
+void OPPROTO glue(op_load_gpr64_T1_gpr, REG) (void)
+{
+    T1_64 = env->gpr[REG];
+    RETURN();
+}
+
+#if 0 // unused
+void OPPROTO glue(op_load_gpr64_T2_gpr, REG) (void)
+{
+    T2_64 = env->gpr[REG];
+    RETURN();
+}
+#endif
+
+void OPPROTO glue(op_store_T0_gpr64_gpr, REG) (void)
+{
+    env->gpr[REG] = T0_64;
+    RETURN();
+}
+
+void OPPROTO glue(op_store_T1_gpr64_gpr, REG) (void)
+{
+    env->gpr[REG] = T1_64;
+    RETURN();
+}
+
+#if 0 // unused
+void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void)
+{
+    env->gpr[REG] = T2_64;
+    RETURN();
+}
+#endif
+#endif /* defined(TARGET_PPCEMB) */
 
 #if REG <= 7
 /* Condition register moves */
-void OPPROTO glue(op_load_crf_T0_crf, REG)(void)
+void OPPROTO glue(op_load_crf_T0_crf, REG) (void)
 {
-    T0 = regs->crf[REG];
+    T0 = env->crf[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_load_crf_T1_crf, REG)(void)
+void OPPROTO glue(op_load_crf_T1_crf, REG) (void)
 {
-    T1 = regs->crf[REG];
+    T1 = env->crf[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_T0_crf_crf, REG)(void)
+void OPPROTO glue(op_store_T0_crf_crf, REG) (void)
 {
-    regs->crf[REG] = T0;
+    env->crf[REG] = T0;
     RETURN();
 }
 
-void OPPROTO glue(op_store_T1_crf_crf, REG)(void)
+void OPPROTO glue(op_store_T1_crf_crf, REG) (void)
 {
-    regs->crf[REG] = T1;
+    env->crf[REG] = T1;
     RETURN();
 }
 
 /* Floating point condition and status register moves */
-void OPPROTO glue(op_load_fpscr_T0_fpscr, REG)(void)
+void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void)
 {
-    T0 = regs->fpscr[REG];
+    T0 = env->fpscr[REG];
     RETURN();
 }
 
 #if REG == 0
-void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
 {
-    regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9);
+    env->fpscr[REG] = (env->fpscr[REG] & 0x9) | (T0 & ~0x9);
     RETURN();
 }
 
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
+void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
 {
-    regs->fpscr[REG] = (regs->fpscr[REG] & ~0x9) | (PARAM(1) & 0x9);
-    RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
-{
-    regs->fpscr[REG] = (regs->fpscr[REG] & 0x9);
+    env->fpscr[REG] = (env->fpscr[REG] & 0x9);
     RETURN();
 }
 #else
-void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
 {
-    regs->fpscr[REG] = T0;
+    env->fpscr[REG] = T0;
     RETURN();
 }
 
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
+void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
 {
-    regs->fpscr[REG] = PARAM(1);
-    RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
-{
-    regs->fpscr[REG] = 0x0;
+    env->fpscr[REG] = 0x0;
     RETURN();
 }
 #endif
@@ -129,55 +161,42 @@
 #endif /* REG <= 7 */
 
 /* floating point registers moves */
-void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT0_fpr, REG) (void)
 {
     FT0 = env->fpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_FT0_fpr_fpr, REG)(void)
+void OPPROTO glue(op_store_FT0_fpr_fpr, REG) (void)
 {
     env->fpr[REG] = FT0;
     RETURN();
 }
 
-void OPPROTO glue(op_load_fpr_FT1_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT1_fpr, REG) (void)
 {
     FT1 = env->fpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_FT1_fpr_fpr, REG)(void)
+void OPPROTO glue(op_store_FT1_fpr_fpr, REG) (void)
 {
     env->fpr[REG] = FT1;
     RETURN();
 }
 
-void OPPROTO glue(op_load_fpr_FT2_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT2_fpr, REG) (void)
 {
     FT2 = env->fpr[REG];
     RETURN();
 }
 
-void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void)
+#if 0 // unused
+void OPPROTO glue(op_store_FT2_fpr_fpr, REG) (void)
 {
     env->fpr[REG] = FT2;
     RETURN();
 }
-
-#if REG <= 15
-/* Segment register moves */
-void OPPROTO glue(op_load_sr, REG)(void)
-{
-    T0 = env->sr[REG];
-    RETURN();
-}
-
-void OPPROTO glue(op_store_sr, REG)(void)
-{
-    do_store_sr(env, REG, T0);
-    RETURN();
-}
 #endif
 
 #undef REG
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 41737d4..3cb89f4 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -1,7 +1,7 @@
 /*
  *  PowerPC emulation for qemu: main translation routines.
- * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,10 +27,15 @@
 #include "exec-all.h"
 #include "disas.h"
 
+/* Include definitions for instructions classes and implementations flags */
 //#define DO_SINGLE_STEP
 //#define PPC_DEBUG_DISAS
+//#define DEBUG_MEMORY_ACCESSES
+//#define DO_PPC_STATISTICS
 
-#ifdef USE_DIRECT_JUMP
+/*****************************************************************************/
+/* Code translation helpers                                                  */
+#if defined(USE_DIRECT_JUMP)
 #define TBPARAM(x)
 #else
 #define TBPARAM(x) (long)(x)
@@ -48,7 +53,27 @@
 
 #include "gen-op.h"
 
-#define GEN8(func, NAME) \
+static inline void gen_set_T0 (target_ulong val)
+{
+#if defined(TARGET_PPC64)
+    if (val >> 32)
+        gen_op_set_T0_64(val >> 32, val);
+    else
+#endif
+        gen_op_set_T0(val);
+}
+
+static inline void gen_set_T1 (target_ulong val)
+{
+#if defined(TARGET_PPC64)
+    if (val >> 32)
+        gen_op_set_T1_64(val >> 32, val);
+    else
+#endif
+        gen_op_set_T1(val);
+}
+
+#define GEN8(func, NAME)                                                      \
 static GenOpFunc *NAME ## _table [8] = {                                      \
 NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,                                   \
 NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,                                   \
@@ -70,7 +95,7 @@
     NAME ## _table[n]();                                                      \
 }
 
-#define GEN32(func, NAME) \
+#define GEN32(func, NAME)                                                     \
 static GenOpFunc *NAME ## _table [32] = {                                     \
 NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,                                   \
 NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,                                   \
@@ -96,25 +121,12 @@
 GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
 GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
 GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
-static GenOpFunc1 *gen_op_store_T0_fpscri_fpscr_table[8] = {
-    &gen_op_store_T0_fpscri_fpscr0,
-    &gen_op_store_T0_fpscri_fpscr1,
-    &gen_op_store_T0_fpscri_fpscr2,
-    &gen_op_store_T0_fpscri_fpscr3,
-    &gen_op_store_T0_fpscri_fpscr4,
-    &gen_op_store_T0_fpscri_fpscr5,
-    &gen_op_store_T0_fpscri_fpscr6,
-    &gen_op_store_T0_fpscri_fpscr7,
-};
-static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
+static inline void gen_op_store_T0_fpscri (int n, uint8_t param)
 {
-    (*gen_op_store_T0_fpscri_fpscr_table[n])(param);
+    gen_op_set_T0(param);
+    gen_op_store_T0_fpscr(n);
 }
 
-/* Segment register moves */
-GEN16(gen_op_load_sr, gen_op_load_sr);
-GEN16(gen_op_store_sr, gen_op_store_sr);
-
 /* General purpose registers moves */
 GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
 GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
@@ -122,7 +134,9 @@
 
 GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
 GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
+#if 0 // unused
 GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
+#endif
 
 /* floating point registers moves */
 GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
@@ -130,9 +144,9 @@
 GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
 GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
 GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
+#if 0 // unused
 GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
-
-static uint8_t  spr_access[1024 / 2];
+#endif
 
 /* internal defines */
 typedef struct DisasContext {
@@ -146,7 +160,13 @@
 #if !defined(CONFIG_USER_ONLY)
     int supervisor;
 #endif
+#if defined(TARGET_PPC64)
+    int sf_mode;
+#endif
     int fpu_enabled;
+#if defined(TARGET_PPCEMB)
+    int spe_enabled;
+#endif
     ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
     int singlestep_enabled;
 } DisasContext;
@@ -155,40 +175,76 @@
     /* invalid bits */
     uint32_t inval;
     /* instruction type */
-    uint32_t type;
+    uint64_t type;
     /* handler */
     void (*handler)(DisasContext *ctx);
+#if defined(DO_PPC_STATISTICS) || defined(PPC_DUMP_CPU)
+    const unsigned char *oname;
+#endif
+#if defined(DO_PPC_STATISTICS)
+    uint64_t count;
+#endif
 };
 
-#define RET_EXCP(ctx, excp, error)                                            \
+static inline void gen_set_Rc0 (DisasContext *ctx)
+{
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        gen_op_cmpi_64(0);
+    else
+#endif
+        gen_op_cmpi(0);
+    gen_op_set_Rc0();
+}
+
+static inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
+{
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        gen_op_update_nip_64(nip >> 32, nip);
+    else
+#endif
+        gen_op_update_nip(nip);
+}
+
+#define GEN_EXCP(ctx, excp, error)                                            \
 do {                                                                          \
-    if ((ctx)->exception == EXCP_NONE) {                                      \
-        gen_op_update_nip((ctx)->nip);                                        \
+    if ((ctx)->exception == POWERPC_EXCP_NONE) {                              \
+        gen_update_nip(ctx, (ctx)->nip);                                      \
     }                                                                         \
     gen_op_raise_exception_err((excp), (error));                              \
     ctx->exception = (excp);                                                  \
 } while (0)
 
-#define RET_INVAL(ctx)                                                        \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
+#define GEN_EXCP_INVAL(ctx)                                                   \
+GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
+         POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL)
 
-#define RET_PRIVOPC(ctx)                                                      \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
+#define GEN_EXCP_PRIVOPC(ctx)                                                 \
+GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
+         POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_OPC)
 
-#define RET_PRIVREG(ctx)                                                      \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
+#define GEN_EXCP_PRIVREG(ctx)                                                 \
+GEN_EXCP((ctx), POWERPC_EXCP_PROGRAM,                                         \
+         POWERPC_EXCP_INVAL | POWERPC_EXCP_PRIV_REG)
+
+#define GEN_EXCP_NO_FP(ctx)                                                   \
+GEN_EXCP(ctx, POWERPC_EXCP_FPU, 0)
+
+#define GEN_EXCP_NO_AP(ctx)                                                   \
+GEN_EXCP(ctx, POWERPC_EXCP_APU, 0)
 
 /* Stop translation */
-static inline void RET_STOP (DisasContext *ctx)
+static inline void GEN_STOP (DisasContext *ctx)
 {
-    gen_op_update_nip((ctx)->nip);
-    ctx->exception = EXCP_MTMSR;
+    gen_update_nip(ctx, ctx->nip);
+    ctx->exception = POWERPC_EXCP_STOP;
 }
 
 /* No need to update nip here, as execution flow will change */
-static inline void RET_CHG_FLOW (DisasContext *ctx)
+static inline void GEN_SYNC (DisasContext *ctx)
 {
-    ctx->exception = EXCP_MTMSR;
+    ctx->exception = POWERPC_EXCP_SYNC;
 }
 
 #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                      \
@@ -207,6 +263,7 @@
     const unsigned char *oname;
 } opcode_t;
 
+/*****************************************************************************/
 /***                           Instruction decoding                        ***/
 #define EXTRACT_HELPER(name, shift, nb)                                       \
 static inline uint32_t name (uint32_t opcode)                                 \
@@ -278,7 +335,7 @@
 /* Displacement */
 EXTRACT_SHELPER(d, 0, 16);
 /* Immediate address */
-static inline uint32_t LI (uint32_t opcode)
+static inline target_ulong LI (uint32_t opcode)
 {
     return (opcode >> 0) & 0x03FFFFFC;
 }
@@ -296,30 +353,168 @@
 EXTRACT_HELPER(LK, 0, 1);
 
 /* Create a mask between <start> and <end> bits */
-static inline uint32_t MASK (uint32_t start, uint32_t end)
+static inline target_ulong MASK (uint32_t start, uint32_t end)
 {
-    uint32_t ret;
+    target_ulong ret;
 
-    ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
-    if (start > end)
-        return ~ret;
+#if defined(TARGET_PPC64)
+    if (likely(start == 0)) {
+        ret = (uint64_t)(-1ULL) << (63 - end);
+    } else if (likely(end == 63)) {
+        ret = (uint64_t)(-1ULL) >> start;
+    }
+#else
+    if (likely(start == 0)) {
+        ret = (uint32_t)(-1ULL) << (31  - end);
+    } else if (likely(end == 31)) {
+        ret = (uint32_t)(-1ULL) >> start;
+    }
+#endif
+    else {
+        ret = (((target_ulong)(-1ULL)) >> (start)) ^
+            (((target_ulong)(-1ULL) >> (end)) >> 1);
+        if (unlikely(start > end))
+            return ~ret;
+    }
 
     return ret;
 }
 
+/*****************************************************************************/
+/* PowerPC Instructions types definitions                                    */
+enum {
+    PPC_NONE          = 0x0000000000000000ULL,
+    /* integer operations instructions                  */
+    /* flow control instructions                        */
+    /* virtual memory instructions                      */
+    /* ld/st with reservation instructions              */
+    /* cache control instructions                       */
+    /* spr/msr access instructions                      */
+    PPC_INSNS_BASE    = 0x0000000000000001ULL,
+#define PPC_INTEGER PPC_INSNS_BASE
+#define PPC_FLOW    PPC_INSNS_BASE
+#define PPC_MEM     PPC_INSNS_BASE
+#define PPC_RES     PPC_INSNS_BASE
+#define PPC_CACHE   PPC_INSNS_BASE
+#define PPC_MISC    PPC_INSNS_BASE
+    /* Optional floating point instructions             */
+    PPC_FLOAT         = 0x0000000000000002ULL,
+    PPC_FLOAT_FSQRT   = 0x0000000000000004ULL,
+    PPC_FLOAT_FRES    = 0x0000000000000008ULL,
+    PPC_FLOAT_FRSQRTE = 0x0000000000000010ULL,
+    PPC_FLOAT_FSEL    = 0x0000000000000020ULL,
+    PPC_FLOAT_STFIWX  = 0x0000000000000040ULL,
+    /* external control instructions                    */
+    PPC_EXTERN        = 0x0000000000000080ULL,
+    /* segment register access instructions             */
+    PPC_SEGMENT       = 0x0000000000000100ULL,
+    /* Optional cache control instruction               */
+    PPC_CACHE_DCBA    = 0x0000000000000200ULL,
+    /* Optional memory control instructions             */
+    PPC_MEM_TLBIA     = 0x0000000000000400ULL,
+    PPC_MEM_TLBIE     = 0x0000000000000800ULL,
+    PPC_MEM_TLBSYNC   = 0x0000000000001000ULL,
+    /* eieio & sync                                     */
+    PPC_MEM_SYNC      = 0x0000000000002000ULL,
+    /* PowerPC 6xx TLB management instructions          */
+    PPC_6xx_TLB       = 0x0000000000004000ULL,
+    /* Altivec support                                  */
+    PPC_ALTIVEC       = 0x0000000000008000ULL,
+    /* Time base mftb instruction                       */
+    PPC_MFTB          = 0x0000000000010000ULL,
+    /* Embedded PowerPC dedicated instructions          */
+    PPC_EMB_COMMON    = 0x0000000000020000ULL,
+    /* PowerPC 40x exception model                      */
+    PPC_40x_EXCP      = 0x0000000000040000ULL,
+    /* PowerPC 40x TLB management instructions          */
+    PPC_40x_TLB       = 0x0000000000080000ULL,
+    /* PowerPC 405 Mac instructions                     */
+    PPC_405_MAC       = 0x0000000000100000ULL,
+    /* PowerPC 440 specific instructions                */
+    PPC_440_SPEC      = 0x0000000000200000ULL,
+    /* Power-to-PowerPC bridge (601)                    */
+    PPC_POWER_BR      = 0x0000000000400000ULL,
+    /* PowerPC 602 specific */
+    PPC_602_SPEC      = 0x0000000000800000ULL,
+    /* Deprecated instructions                          */
+    /* Original POWER instruction set                   */
+    PPC_POWER         = 0x0000000001000000ULL,
+    /* POWER2 instruction set extension                 */
+    PPC_POWER2        = 0x0000000002000000ULL,
+    /* Power RTC support */
+    PPC_POWER_RTC     = 0x0000000004000000ULL,
+    /* 64 bits PowerPC instructions                     */
+    /* 64 bits PowerPC instruction set                  */
+    PPC_64B           = 0x0000000008000000ULL,
+    /* 64 bits hypervisor extensions                    */
+    PPC_64H           = 0x0000000010000000ULL,
+    /* 64 bits PowerPC "bridge" features                */
+    PPC_64_BRIDGE     = 0x0000000020000000ULL,
+    /* BookE (embedded) PowerPC specification           */
+    PPC_BOOKE         = 0x0000000040000000ULL,
+    /* eieio                                            */
+    PPC_MEM_EIEIO     = 0x0000000080000000ULL,
+    /* e500 vector instructions                         */
+    PPC_E500_VECTOR   = 0x0000000100000000ULL,
+    /* PowerPC 4xx dedicated instructions               */
+    PPC_4xx_COMMON    = 0x0000000200000000ULL,
+    /* PowerPC 2.03 specification extensions            */
+    PPC_203           = 0x0000000400000000ULL,
+    /* PowerPC 2.03 SPE extension                       */
+    PPC_SPE           = 0x0000000800000000ULL,
+    /* PowerPC 2.03 SPE floating-point extension        */
+    PPC_SPEFPU        = 0x0000001000000000ULL,
+    /* SLB management                                   */
+    PPC_SLBI          = 0x0000002000000000ULL,
+    /* PowerPC 40x ibct instructions                    */
+    PPC_40x_ICBT      = 0x0000004000000000ULL,
+    /* PowerPC 74xx TLB management instructions         */
+    PPC_74xx_TLB      = 0x0000008000000000ULL,
+    /* More BookE (embedded) instructions...            */
+    PPC_BOOKE_EXT     = 0x0000010000000000ULL,
+    /* rfmci is not implemented in all BookE PowerPC    */
+    PPC_RFMCI         = 0x0000020000000000ULL,
+    /* user-mode DCR access, implemented in PowerPC 460 */
+    PPC_DCRUX         = 0x0000040000000000ULL,
+    /* New floating-point extensions (PowerPC 2.0x)     */
+    PPC_FLOAT_EXT     = 0x0000080000000000ULL,
+    /* New wait instruction (PowerPC 2.0x)              */
+    PPC_WAIT          = 0x0000100000000000ULL,
+    /* New 64 bits extensions (PowerPC 2.0x)            */
+    PPC_64BX          = 0x0000200000000000ULL,
+};
+
+/*****************************************************************************/
+/* PowerPC instructions table                                                */
 #if HOST_LONG_BITS == 64
 #define OPC_ALIGN 8
 #else
 #define OPC_ALIGN 4
 #endif
 #if defined(__APPLE__)
-#define OPCODES_SECTION \
+#define OPCODES_SECTION                                                       \
     __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
 #else
-#define OPCODES_SECTION \
+#define OPCODES_SECTION                                                       \
     __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
 #endif
 
+#if defined(DO_PPC_STATISTICS)
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
+OPCODES_SECTION opcode_t opc_##name = {                                       \
+    .opc1 = op1,                                                              \
+    .opc2 = op2,                                                              \
+    .opc3 = op3,                                                              \
+    .pad  = { 0, },                                                           \
+    .handler = {                                                              \
+        .inval   = invl,                                                      \
+        .type = _typ,                                                         \
+        .handler = &gen_##name,                                               \
+        .oname = stringify(name),                                             \
+    },                                                                        \
+    .oname = stringify(name),                                                 \
+}
+#else
 #define GEN_OPCODE(name, op1, op2, op3, invl, _typ)                           \
 OPCODES_SECTION opcode_t opc_##name = {                                       \
     .opc1 = op1,                                                              \
@@ -333,6 +528,7 @@
     },                                                                        \
     .oname = stringify(name),                                                 \
 }
+#endif
 
 #define GEN_OPCODE_MARK(name)                                                 \
 OPCODES_SECTION opcode_t opc_##name = {                                       \
@@ -354,7 +550,7 @@
 /* Invalid instruction */
 GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
 {
-    RET_INVAL(ctx);
+    GEN_EXCP_INVAL(ctx);
 }
 
 static opc_handler_t invalid_handler = {
@@ -364,131 +560,387 @@
 };
 
 /***                           Integer arithmetic                          ***/
-#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval)                       \
-GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
+#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval, type)                 \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                              \
 {                                                                             \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 
-#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval)                     \
-GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER)                       \
+#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval, type)               \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                              \
 {                                                                             \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 
-#define __GEN_INT_ARITH1(name, opc1, opc2, opc3)                              \
-GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER)                  \
+#define __GEN_INT_ARITH1(name, opc1, opc2, opc3, type)                        \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type)                         \
 {                                                                             \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
-#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3)                            \
-GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER)                  \
+#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3, type)                      \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type)                         \
 {                                                                             \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 
 /* Two operands arithmetic functions */
-#define GEN_INT_ARITH2(name, opc1, opc2, opc3)                                \
-__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000)                          \
-__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)
+#define GEN_INT_ARITH2(name, opc1, opc2, opc3, type)                          \
+__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000, type)                    \
+__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type)
 
 /* Two operands arithmetic functions with no overflow allowed */
-#define GEN_INT_ARITHN(name, opc1, opc2, opc3)                                \
-__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)
+#define GEN_INT_ARITHN(name, opc1, opc2, opc3, type)                          \
+__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400, type)
 
 /* One operand arithmetic functions */
-#define GEN_INT_ARITH1(name, opc1, opc2, opc3)                                \
-__GEN_INT_ARITH1(name, opc1, opc2, opc3)                                      \
-__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)
+#define GEN_INT_ARITH1(name, opc1, opc2, opc3, type)                          \
+__GEN_INT_ARITH1(name, opc1, opc2, opc3, type)                                \
+__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10, type)
+
+#if defined(TARGET_PPC64)
+#define __GEN_INT_ARITH2_64(name, opc1, opc2, opc3, inval, type)              \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                              \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    if (ctx->sf_mode)                                                         \
+        gen_op_##name##_64();                                                 \
+    else                                                                      \
+        gen_op_##name();                                                      \
+    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
+}
+
+#define __GEN_INT_ARITH2_O_64(name, opc1, opc2, opc3, inval, type)            \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, type)                              \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    if (ctx->sf_mode)                                                         \
+        gen_op_##name##_64();                                                 \
+    else                                                                      \
+        gen_op_##name();                                                      \
+    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
+}
+
+#define __GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type)                     \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type)                         \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    if (ctx->sf_mode)                                                         \
+        gen_op_##name##_64();                                                 \
+    else                                                                      \
+        gen_op_##name();                                                      \
+    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
+}
+#define __GEN_INT_ARITH1_O_64(name, opc1, opc2, opc3, type)                   \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type)                         \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    if (ctx->sf_mode)                                                         \
+        gen_op_##name##_64();                                                 \
+    else                                                                      \
+        gen_op_##name();                                                      \
+    gen_op_store_T0_gpr(rD(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
+}
+
+/* Two operands arithmetic functions */
+#define GEN_INT_ARITH2_64(name, opc1, opc2, opc3, type)                       \
+__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000000, type)                 \
+__GEN_INT_ARITH2_O_64(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type)
+
+/* Two operands arithmetic functions with no overflow allowed */
+#define GEN_INT_ARITHN_64(name, opc1, opc2, opc3, type)                       \
+__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000400, type)
+
+/* One operand arithmetic functions */
+#define GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type)                       \
+__GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type)                             \
+__GEN_INT_ARITH1_O_64(name##o, opc1, opc2, opc3 | 0x10, type)
+#else
+#define GEN_INT_ARITH2_64 GEN_INT_ARITH2
+#define GEN_INT_ARITHN_64 GEN_INT_ARITHN
+#define GEN_INT_ARITH1_64 GEN_INT_ARITH1
+#endif
 
 /* add    add.    addo    addo.    */
-GEN_INT_ARITH2 (add,    0x1F, 0x0A, 0x08);
+static inline void gen_op_addo (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add();
+    gen_op_check_addo();
+}
+#if defined(TARGET_PPC64)
+#define gen_op_add_64 gen_op_add
+static inline void gen_op_addo_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add();
+    gen_op_check_addo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (add,    0x1F, 0x0A, 0x08, PPC_INTEGER);
 /* addc   addc.   addco   addco.   */
-GEN_INT_ARITH2 (addc,   0x1F, 0x0A, 0x00);
+static inline void gen_op_addc (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add();
+    gen_op_check_addc();
+}
+static inline void gen_op_addco (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add();
+    gen_op_check_addc();
+    gen_op_check_addo();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_addc_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add();
+    gen_op_check_addc_64();
+}
+static inline void gen_op_addco_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add();
+    gen_op_check_addc_64();
+    gen_op_check_addo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (addc,   0x1F, 0x0A, 0x00, PPC_INTEGER);
 /* adde   adde.   addeo   addeo.   */
-GEN_INT_ARITH2 (adde,   0x1F, 0x0A, 0x04);
+static inline void gen_op_addeo (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_adde();
+    gen_op_check_addo();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_addeo_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_adde_64();
+    gen_op_check_addo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (adde,   0x1F, 0x0A, 0x04, PPC_INTEGER);
 /* addme  addme.  addmeo  addmeo.  */
-GEN_INT_ARITH1 (addme,  0x1F, 0x0A, 0x07);
+static inline void gen_op_addme (void)
+{
+    gen_op_move_T1_T0();
+    gen_op_add_me();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_addme_64 (void)
+{
+    gen_op_move_T1_T0();
+    gen_op_add_me_64();
+}
+#endif
+GEN_INT_ARITH1_64 (addme,  0x1F, 0x0A, 0x07, PPC_INTEGER);
 /* addze  addze.  addzeo  addzeo.  */
-GEN_INT_ARITH1 (addze,  0x1F, 0x0A, 0x06);
+static inline void gen_op_addze (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add_ze();
+    gen_op_check_addc();
+}
+static inline void gen_op_addzeo (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add_ze();
+    gen_op_check_addc();
+    gen_op_check_addo();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_addze_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add_ze();
+    gen_op_check_addc_64();
+}
+static inline void gen_op_addzeo_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_add_ze();
+    gen_op_check_addc_64();
+    gen_op_check_addo_64();
+}
+#endif
+GEN_INT_ARITH1_64 (addze,  0x1F, 0x0A, 0x06, PPC_INTEGER);
 /* divw   divw.   divwo   divwo.   */
-GEN_INT_ARITH2 (divw,   0x1F, 0x0B, 0x0F);
+GEN_INT_ARITH2 (divw,   0x1F, 0x0B, 0x0F, PPC_INTEGER);
 /* divwu  divwu.  divwuo  divwuo.  */
-GEN_INT_ARITH2 (divwu,  0x1F, 0x0B, 0x0E);
+GEN_INT_ARITH2 (divwu,  0x1F, 0x0B, 0x0E, PPC_INTEGER);
 /* mulhw  mulhw.                   */
-GEN_INT_ARITHN (mulhw,  0x1F, 0x0B, 0x02);
+GEN_INT_ARITHN (mulhw,  0x1F, 0x0B, 0x02, PPC_INTEGER);
 /* mulhwu mulhwu.                  */
-GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
+GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00, PPC_INTEGER);
 /* mullw  mullw.  mullwo  mullwo.  */
-GEN_INT_ARITH2 (mullw,  0x1F, 0x0B, 0x07);
+GEN_INT_ARITH2 (mullw,  0x1F, 0x0B, 0x07, PPC_INTEGER);
 /* neg    neg.    nego    nego.    */
-GEN_INT_ARITH1 (neg,    0x1F, 0x08, 0x03);
+GEN_INT_ARITH1_64 (neg,    0x1F, 0x08, 0x03, PPC_INTEGER);
 /* subf   subf.   subfo   subfo.   */
-GEN_INT_ARITH2 (subf,   0x1F, 0x08, 0x01);
+static inline void gen_op_subfo (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_subf();
+    gen_op_check_subfo();
+}
+#if defined(TARGET_PPC64)
+#define gen_op_subf_64 gen_op_subf
+static inline void gen_op_subfo_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_subf();
+    gen_op_check_subfo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (subf,   0x1F, 0x08, 0x01, PPC_INTEGER);
 /* subfc  subfc.  subfco  subfco.  */
-GEN_INT_ARITH2 (subfc,  0x1F, 0x08, 0x00);
+static inline void gen_op_subfc (void)
+{
+    gen_op_subf();
+    gen_op_check_subfc();
+}
+static inline void gen_op_subfco (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_subf();
+    gen_op_check_subfc();
+    gen_op_check_subfo();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_subfc_64 (void)
+{
+    gen_op_subf();
+    gen_op_check_subfc_64();
+}
+static inline void gen_op_subfco_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_subf();
+    gen_op_check_subfc_64();
+    gen_op_check_subfo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (subfc,  0x1F, 0x08, 0x00, PPC_INTEGER);
 /* subfe  subfe.  subfeo  subfeo.  */
-GEN_INT_ARITH2 (subfe,  0x1F, 0x08, 0x04);
+static inline void gen_op_subfeo (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_subfe();
+    gen_op_check_subfo();
+}
+#if defined(TARGET_PPC64)
+#define gen_op_subfe_64 gen_op_subfe
+static inline void gen_op_subfeo_64 (void)
+{
+    gen_op_move_T2_T0();
+    gen_op_subfe_64();
+    gen_op_check_subfo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (subfe,  0x1F, 0x08, 0x04, PPC_INTEGER);
 /* subfme subfme. subfmeo subfmeo. */
-GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
+GEN_INT_ARITH1_64 (subfme, 0x1F, 0x08, 0x07, PPC_INTEGER);
 /* subfze subfze. subfzeo subfzeo. */
-GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
+GEN_INT_ARITH1_64 (subfze, 0x1F, 0x08, 0x06, PPC_INTEGER);
 /* addi */
 GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    int32_t simm = SIMM(ctx->opcode);
+    target_long simm = SIMM(ctx->opcode);
 
     if (rA(ctx->opcode) == 0) {
-        gen_op_set_T0(simm);
+        /* li case */
+        gen_set_T0(simm);
     } else {
         gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_addi(simm);
+        if (likely(simm != 0))
+            gen_op_addi(simm);
     }
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 /* addic */
 GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
+    target_long simm = SIMM(ctx->opcode);
+
     gen_op_load_gpr_T0(rA(ctx->opcode));
-    gen_op_addic(SIMM(ctx->opcode));
+    if (likely(simm != 0)) {
+        gen_op_move_T2_T0();
+        gen_op_addi(simm);
+#if defined(TARGET_PPC64)
+        if (ctx->sf_mode)
+            gen_op_check_addc_64();
+        else
+#endif
+            gen_op_check_addc();
+    } else {
+        gen_op_clear_xer_ca();
+    }
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 /* addic. */
 GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
+    target_long simm = SIMM(ctx->opcode);
+
     gen_op_load_gpr_T0(rA(ctx->opcode));
-    gen_op_addic(SIMM(ctx->opcode));
-    gen_op_set_Rc0();
+    if (likely(simm != 0)) {
+        gen_op_move_T2_T0();
+        gen_op_addi(simm);
+#if defined(TARGET_PPC64)
+        if (ctx->sf_mode)
+            gen_op_check_addc_64();
+        else
+#endif
+            gen_op_check_addc();
+    } else {
+        gen_op_clear_xer_ca();
+    }
     gen_op_store_T0_gpr(rD(ctx->opcode));
+    gen_set_Rc0(ctx);
 }
 /* addis */
 GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    int32_t simm = SIMM(ctx->opcode);
+    target_long simm = SIMM(ctx->opcode);
 
     if (rA(ctx->opcode) == 0) {
-        gen_op_set_T0(simm << 16);
+        /* lis case */
+        gen_set_T0(simm << 16);
     } else {
         gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_addi(simm << 16);
+        if (likely(simm != 0))
+            gen_op_addi(simm << 16);
     }
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
@@ -503,113 +955,232 @@
 GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rA(ctx->opcode));
-    gen_op_subfic(SIMM(ctx->opcode));
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        gen_op_subfic_64(SIMM(ctx->opcode));
+    else
+#endif
+        gen_op_subfic(SIMM(ctx->opcode));
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
+#if defined(TARGET_PPC64)
+/* mulhd  mulhd.                   */
+GEN_INT_ARITHN (mulhd,  0x1F, 0x09, 0x02, PPC_64B);
+/* mulhdu mulhdu.                  */
+GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_64B);
+/* mulld  mulld.  mulldo  mulldo.  */
+GEN_INT_ARITH2 (mulld,  0x1F, 0x09, 0x07, PPC_64B);
+/* divd   divd.   divdo   divdo.   */
+GEN_INT_ARITH2 (divd,   0x1F, 0x09, 0x0F, PPC_64B);
+/* divdu  divdu.  divduo  divduo.  */
+GEN_INT_ARITH2 (divdu,  0x1F, 0x09, 0x0E, PPC_64B);
+#endif
+
 /***                           Integer comparison                          ***/
-#define GEN_CMP(name, opc)                                                    \
-GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER)                   \
+#if defined(TARGET_PPC64)
+#define GEN_CMP(name, opc, type)                                              \
+GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type)                          \
+{                                                                             \
+    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
+    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
+    if (ctx->sf_mode && (ctx->opcode & 0x00200000))                           \
+        gen_op_##name##_64();                                                 \
+    else                                                                      \
+        gen_op_##name();                                                      \
+    gen_op_store_T0_crf(crfD(ctx->opcode));                                   \
+}
+#else
+#define GEN_CMP(name, opc, type)                                              \
+GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type)                          \
 {                                                                             \
     gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
     gen_op_##name();                                                          \
     gen_op_store_T0_crf(crfD(ctx->opcode));                                   \
 }
+#endif
 
 /* cmp */
-GEN_CMP(cmp, 0x00);
+GEN_CMP(cmp, 0x00, PPC_INTEGER);
 /* cmpi */
 GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rA(ctx->opcode));
-    gen_op_cmpi(SIMM(ctx->opcode));
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode && (ctx->opcode & 0x00200000))
+        gen_op_cmpi_64(SIMM(ctx->opcode));
+    else
+#endif
+        gen_op_cmpi(SIMM(ctx->opcode));
     gen_op_store_T0_crf(crfD(ctx->opcode));
 }
 /* cmpl */
-GEN_CMP(cmpl, 0x01);
+GEN_CMP(cmpl, 0x01, PPC_INTEGER);
 /* cmpli */
 GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rA(ctx->opcode));
-    gen_op_cmpli(UIMM(ctx->opcode));
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode && (ctx->opcode & 0x00200000))
+        gen_op_cmpli_64(UIMM(ctx->opcode));
+    else
+#endif
+        gen_op_cmpli(UIMM(ctx->opcode));
     gen_op_store_T0_crf(crfD(ctx->opcode));
 }
 
+/* isel (PowerPC 2.03 specification) */
+GEN_HANDLER(isel, 0x1F, 0x0F, 0x00, 0x00000001, PPC_203)
+{
+    uint32_t bi = rC(ctx->opcode);
+    uint32_t mask;
+
+    if (rA(ctx->opcode) == 0) {
+        gen_set_T0(0);
+    } else {
+        gen_op_load_gpr_T1(rA(ctx->opcode));
+    }
+    gen_op_load_gpr_T2(rB(ctx->opcode));
+    mask = 1 << (3 - (bi & 0x03));
+    gen_op_load_crf_T0(bi >> 2);
+    gen_op_test_true(mask);
+    gen_op_isel();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
 /***                            Integer logical                            ***/
-#define __GEN_LOGICAL2(name, opc2, opc3)                                      \
-GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER)                  \
+#define __GEN_LOGICAL2(name, opc2, opc3, type)                                \
+GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, type)                         \
 {                                                                             \
     gen_op_load_gpr_T0(rS(ctx->opcode));                                      \
     gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
-#define GEN_LOGICAL2(name, opc)                                               \
-__GEN_LOGICAL2(name, 0x1C, opc)
+#define GEN_LOGICAL2(name, opc, type)                                         \
+__GEN_LOGICAL2(name, 0x1C, opc, type)
 
-#define GEN_LOGICAL1(name, opc)                                               \
-GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER)                   \
+#define GEN_LOGICAL1(name, opc, type)                                         \
+GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type)                          \
 {                                                                             \
     gen_op_load_gpr_T0(rS(ctx->opcode));                                      \
     gen_op_##name();                                                          \
-    if (Rc(ctx->opcode) != 0)                                                 \
-        gen_op_set_Rc0();                                                     \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
+        gen_set_Rc0(ctx);                                                     \
 }
 
 /* and & and. */
-GEN_LOGICAL2(and, 0x00);
+GEN_LOGICAL2(and, 0x00, PPC_INTEGER);
 /* andc & andc. */
-GEN_LOGICAL2(andc, 0x01);
+GEN_LOGICAL2(andc, 0x01, PPC_INTEGER);
 /* andi. */
 GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_andi_(UIMM(ctx->opcode));
-    gen_op_set_Rc0();
+    gen_op_andi_T0(UIMM(ctx->opcode));
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_set_Rc0(ctx);
 }
 /* andis. */
 GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_andi_(UIMM(ctx->opcode) << 16);
-    gen_op_set_Rc0();
+    gen_op_andi_T0(UIMM(ctx->opcode) << 16);
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_set_Rc0(ctx);
 }
 
 /* cntlzw */
-GEN_LOGICAL1(cntlzw, 0x00);
+GEN_LOGICAL1(cntlzw, 0x00, PPC_INTEGER);
 /* eqv & eqv. */
-GEN_LOGICAL2(eqv, 0x08);
+GEN_LOGICAL2(eqv, 0x08, PPC_INTEGER);
 /* extsb & extsb. */
-GEN_LOGICAL1(extsb, 0x1D);
+GEN_LOGICAL1(extsb, 0x1D, PPC_INTEGER);
 /* extsh & extsh. */
-GEN_LOGICAL1(extsh, 0x1C);
+GEN_LOGICAL1(extsh, 0x1C, PPC_INTEGER);
 /* nand & nand. */
-GEN_LOGICAL2(nand, 0x0E);
+GEN_LOGICAL2(nand, 0x0E, PPC_INTEGER);
 /* nor & nor. */
-GEN_LOGICAL2(nor, 0x03);
+GEN_LOGICAL2(nor, 0x03, PPC_INTEGER);
 
 /* or & or. */
 GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
 {
-    gen_op_load_gpr_T0(rS(ctx->opcode));
-    /* Optimisation for mr case */
-    if (rS(ctx->opcode) != rB(ctx->opcode)) {
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_or();
+    int rs, ra, rb;
+
+    rs = rS(ctx->opcode);
+    ra = rA(ctx->opcode);
+    rb = rB(ctx->opcode);
+    /* Optimisation for mr. ri case */
+    if (rs != ra || rs != rb) {
+        gen_op_load_gpr_T0(rs);
+        if (rs != rb) {
+            gen_op_load_gpr_T1(rb);
+            gen_op_or();
+        }
+        gen_op_store_T0_gpr(ra);
+        if (unlikely(Rc(ctx->opcode) != 0))
+            gen_set_Rc0(ctx);
+    } else if (unlikely(Rc(ctx->opcode) != 0)) {
+        gen_op_load_gpr_T0(rs);
+        gen_set_Rc0(ctx);
+#if defined(TARGET_PPC64)
+    } else {
+        switch (rs) {
+        case 1:
+            /* Set process priority to low */
+            gen_op_store_pri(2);
+            break;
+        case 6:
+            /* Set process priority to medium-low */
+            gen_op_store_pri(3);
+            break;
+        case 2:
+            /* Set process priority to normal */
+            gen_op_store_pri(4);
+            break;
+#if !defined(CONFIG_USER_ONLY)
+        case 31:
+            if (ctx->supervisor > 0) {
+                /* Set process priority to very low */
+                gen_op_store_pri(1);
+            }
+            break;
+        case 5:
+            if (ctx->supervisor > 0) {
+                /* Set process priority to medium-hight */
+                gen_op_store_pri(5);
+            }
+            break;
+        case 3:
+            if (ctx->supervisor > 0) {
+                /* Set process priority to high */
+                gen_op_store_pri(6);
+            }
+            break;
+#if defined(TARGET_PPC64H)
+        case 7:
+            if (ctx->supervisor > 1) {
+                /* Set process priority to very high */
+                gen_op_store_pri(7);
+            }
+            break;
+#endif
+#endif
+        default:
+            /* nop */
+            break;
+        }
+#endif
     }
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
-    gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 
 /* orc & orc. */
-GEN_LOGICAL2(orc, 0x0C);
+GEN_LOGICAL2(orc, 0x0C, PPC_INTEGER);
 /* xor & xor. */
 GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
 {
@@ -619,123 +1190,167 @@
         gen_op_load_gpr_T1(rB(ctx->opcode));
         gen_op_xor();
     } else {
-        gen_op_set_T0(0);
+        gen_op_reset_T0();
     }
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 /* ori */
 GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t uimm = UIMM(ctx->opcode);
+    target_ulong uimm = UIMM(ctx->opcode);
 
     if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
         /* NOP */
+        /* XXX: should handle special NOPs for POWER series */
         return;
-        }
-        gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (uimm != 0)
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (likely(uimm != 0))
         gen_op_ori(uimm);
-        gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 /* oris */
 GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t uimm = UIMM(ctx->opcode);
-
-    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
-        /* NOP */
-        return;
-        }
-        gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (uimm != 0)
-        gen_op_ori(uimm << 16);
-        gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-/* xori */
-GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
-    uint32_t uimm = UIMM(ctx->opcode);
+    target_ulong uimm = UIMM(ctx->opcode);
 
     if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
         /* NOP */
         return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (uimm != 0)
-    gen_op_xori(uimm);
+    if (likely(uimm != 0))
+        gen_op_ori(uimm << 16);
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+}
+/* xori */
+GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
+{
+    target_ulong uimm = UIMM(ctx->opcode);
+
+    if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
+        /* NOP */
+        return;
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (likely(uimm != 0))
+        gen_op_xori(uimm);
     gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 
 /* xoris */
 GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t uimm = UIMM(ctx->opcode);
+    target_ulong uimm = UIMM(ctx->opcode);
 
     if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
         /* NOP */
         return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (uimm != 0)
-    gen_op_xori(uimm << 16);
+    if (likely(uimm != 0))
+        gen_op_xori(uimm << 16);
     gen_op_store_T0_gpr(rA(ctx->opcode));
 }
 
+/* popcntb : PowerPC 2.03 specification */
+GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_203)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        gen_op_popcntb_64();
+    else
+#endif
+        gen_op_popcntb();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+}
+
+#if defined(TARGET_PPC64)
+/* extsw & extsw. */
+GEN_LOGICAL1(extsw, 0x1E, PPC_64B);
+/* cntlzd */
+GEN_LOGICAL1(cntlzd, 0x01, PPC_64B);
+#endif
+
 /***                             Integer rotate                            ***/
 /* rlwimi & rlwimi. */
 GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    uint32_t mb, me;
+    target_ulong mask;
+    uint32_t mb, me, sh;
 
     mb = MB(ctx->opcode);
     me = ME(ctx->opcode);
+    sh = SH(ctx->opcode);
+    if (likely(sh == 0)) {
+        if (likely(mb == 0 && me == 31)) {
+            gen_op_load_gpr_T0(rS(ctx->opcode));
+            goto do_store;
+        } else if (likely(mb == 31 && me == 0)) {
+            gen_op_load_gpr_T0(rA(ctx->opcode));
+            goto do_store;
+        }
+        gen_op_load_gpr_T0(rS(ctx->opcode));
+        gen_op_load_gpr_T1(rA(ctx->opcode));
+        goto do_mask;
+    }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_load_gpr_T1(rA(ctx->opcode));
-    gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
+    gen_op_rotli32_T0(SH(ctx->opcode));
+ do_mask:
+#if defined(TARGET_PPC64)
+    mb += 32;
+    me += 32;
+#endif
+    mask = MASK(mb, me);
+    gen_op_andi_T0(mask);
+    gen_op_andi_T1(~mask);
+    gen_op_or();
+ do_store:
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 /* rlwinm & rlwinm. */
 GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
     uint32_t mb, me, sh;
-    
+
     sh = SH(ctx->opcode);
     mb = MB(ctx->opcode);
     me = ME(ctx->opcode);
     gen_op_load_gpr_T0(rS(ctx->opcode));
-#if 1 // TRY
-    if (sh == 0) {
-        gen_op_andi_(MASK(mb, me));
-        goto store;
+    if (likely(sh == 0)) {
+        goto do_mask;
     }
-#endif
-    if (mb == 0) {
-        if (me == 31) {
-            gen_op_rotlwi(sh);
-            goto store;
-#if 0
-        } else if (me == (31 - sh)) {
-            gen_op_slwi(sh);
-            goto store;
-#endif
+    if (likely(mb == 0)) {
+        if (likely(me == 31)) {
+            gen_op_rotli32_T0(sh);
+            goto do_store;
+        } else if (likely(me == (31 - sh))) {
+            gen_op_sli_T0(sh);
+            goto do_store;
         }
-    } else if (me == 31) {
-#if 0
-        if (sh == (32 - mb)) {
-            gen_op_srwi(mb);
-            goto store;
+    } else if (likely(me == 31)) {
+        if (likely(sh == (32 - mb))) {
+            gen_op_srli_T0(mb);
+            goto do_store;
         }
-#endif
     }
-    gen_op_rlwinm(sh, MASK(mb, me));
-store:
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
+    gen_op_rotli32_T0(sh);
+ do_mask:
+#if defined(TARGET_PPC64)
+    mb += 32;
+    me += 32;
+#endif
+    gen_op_andi_T0(MASK(mb, me));
+ do_store:
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 /* rlwnm & rlwnm. */
 GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
@@ -746,41 +1361,259 @@
     me = ME(ctx->opcode);
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_load_gpr_T1(rB(ctx->opcode));
-    if (mb == 0 && me == 31) {
-        gen_op_rotl();
-    } else
-    {
-        gen_op_rlwnm(MASK(mb, me));
+    gen_op_rotl32_T0_T1();
+    if (unlikely(mb != 0 || me != 31)) {
+#if defined(TARGET_PPC64)
+        mb += 32;
+        me += 32;
+#endif
+        gen_op_andi_T0(MASK(mb, me));
     }
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 
+#if defined(TARGET_PPC64)
+#define GEN_PPC64_R2(name, opc1, opc2)                                        \
+GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B)                   \
+{                                                                             \
+    gen_##name(ctx, 0);                                                       \
+}                                                                             \
+GEN_HANDLER(name##1, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B)            \
+{                                                                             \
+    gen_##name(ctx, 1);                                                       \
+}
+#define GEN_PPC64_R4(name, opc1, opc2)                                        \
+GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B)                   \
+{                                                                             \
+    gen_##name(ctx, 0, 0);                                                    \
+}                                                                             \
+GEN_HANDLER(name##1, opc1, opc2 | 0x01, 0xFF, 0x00000000, PPC_64B)            \
+{                                                                             \
+    gen_##name(ctx, 0, 1);                                                    \
+}                                                                             \
+GEN_HANDLER(name##2, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B)            \
+{                                                                             \
+    gen_##name(ctx, 1, 0);                                                    \
+}                                                                             \
+GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B)            \
+{                                                                             \
+    gen_##name(ctx, 1, 1);                                                    \
+}
+
+static inline void gen_andi_T0_64 (DisasContext *ctx, uint64_t mask)
+{
+    if (mask >> 32)
+        gen_op_andi_T0_64(mask >> 32, mask & 0xFFFFFFFF);
+    else
+        gen_op_andi_T0(mask);
+}
+
+static inline void gen_andi_T1_64 (DisasContext *ctx, uint64_t mask)
+{
+    if (mask >> 32)
+        gen_op_andi_T1_64(mask >> 32, mask & 0xFFFFFFFF);
+    else
+        gen_op_andi_T1(mask);
+}
+
+static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me,
+                               uint32_t sh)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (likely(sh == 0)) {
+        goto do_mask;
+    }
+    if (likely(mb == 0)) {
+        if (likely(me == 63)) {
+            gen_op_rotli64_T0(sh);
+            goto do_store;
+        } else if (likely(me == (63 - sh))) {
+            gen_op_sli_T0(sh);
+            goto do_store;
+        }
+    } else if (likely(me == 63)) {
+        if (likely(sh == (64 - mb))) {
+            gen_op_srli_T0_64(mb);
+            goto do_store;
+        }
+    }
+    gen_op_rotli64_T0(sh);
+ do_mask:
+    gen_andi_T0_64(ctx, MASK(mb, me));
+ do_store:
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+/* rldicl - rldicl. */
+static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn)
+{
+    uint32_t sh, mb;
+
+    sh = SH(ctx->opcode) | (shn << 5);
+    mb = MB(ctx->opcode) | (mbn << 5);
+    gen_rldinm(ctx, mb, 63, sh);
+}
+GEN_PPC64_R4(rldicl, 0x1E, 0x00);
+/* rldicr - rldicr. */
+static inline void gen_rldicr (DisasContext *ctx, int men, int shn)
+{
+    uint32_t sh, me;
+
+    sh = SH(ctx->opcode) | (shn << 5);
+    me = MB(ctx->opcode) | (men << 5);
+    gen_rldinm(ctx, 0, me, sh);
+}
+GEN_PPC64_R4(rldicr, 0x1E, 0x02);
+/* rldic - rldic. */
+static inline void gen_rldic (DisasContext *ctx, int mbn, int shn)
+{
+    uint32_t sh, mb;
+
+    sh = SH(ctx->opcode) | (shn << 5);
+    mb = MB(ctx->opcode) | (mbn << 5);
+    gen_rldinm(ctx, mb, 63 - sh, sh);
+}
+GEN_PPC64_R4(rldic, 0x1E, 0x04);
+
+static inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_rotl64_T0_T1();
+    if (unlikely(mb != 0 || me != 63)) {
+        gen_andi_T0_64(ctx, MASK(mb, me));
+    }
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* rldcl - rldcl. */
+static inline void gen_rldcl (DisasContext *ctx, int mbn)
+{
+    uint32_t mb;
+
+    mb = MB(ctx->opcode) | (mbn << 5);
+    gen_rldnm(ctx, mb, 63);
+}
+GEN_PPC64_R2(rldcl, 0x1E, 0x08);
+/* rldcr - rldcr. */
+static inline void gen_rldcr (DisasContext *ctx, int men)
+{
+    uint32_t me;
+
+    me = MB(ctx->opcode) | (men << 5);
+    gen_rldnm(ctx, 0, me);
+}
+GEN_PPC64_R2(rldcr, 0x1E, 0x09);
+/* rldimi - rldimi. */
+static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
+{
+    uint64_t mask;
+    uint32_t sh, mb;
+
+    sh = SH(ctx->opcode) | (shn << 5);
+    mb = MB(ctx->opcode) | (mbn << 5);
+    if (likely(sh == 0)) {
+        if (likely(mb == 0)) {
+            gen_op_load_gpr_T0(rS(ctx->opcode));
+            goto do_store;
+        } else if (likely(mb == 63)) {
+            gen_op_load_gpr_T0(rA(ctx->opcode));
+            goto do_store;
+        }
+        gen_op_load_gpr_T0(rS(ctx->opcode));
+        gen_op_load_gpr_T1(rA(ctx->opcode));
+        goto do_mask;
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rA(ctx->opcode));
+    gen_op_rotli64_T0(sh);
+ do_mask:
+    mask = MASK(mb, 63 - sh);
+    gen_andi_T0_64(ctx, mask);
+    gen_andi_T1_64(ctx, ~mask);
+    gen_op_or();
+ do_store:
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+GEN_PPC64_R4(rldimi, 0x1E, 0x06);
+#endif
+
 /***                             Integer shift                             ***/
 /* slw & slw. */
-__GEN_LOGICAL2(slw, 0x18, 0x00);
+__GEN_LOGICAL2(slw, 0x18, 0x00, PPC_INTEGER);
 /* sraw & sraw. */
-__GEN_LOGICAL2(sraw, 0x18, 0x18);
+__GEN_LOGICAL2(sraw, 0x18, 0x18, PPC_INTEGER);
 /* srawi & srawi. */
 GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
 {
+    int mb, me;
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    if (SH(ctx->opcode) != 0)
-    gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
-    if (Rc(ctx->opcode) != 0)
-        gen_op_set_Rc0();
+    if (SH(ctx->opcode) != 0) {
+        gen_op_move_T1_T0();
+        mb = 32 - SH(ctx->opcode);
+        me = 31;
+#if defined(TARGET_PPC64)
+        mb += 32;
+        me += 32;
+#endif
+        gen_op_srawi(SH(ctx->opcode), MASK(mb, me));
+    }
     gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
 }
 /* srw & srw. */
-__GEN_LOGICAL2(srw, 0x18, 0x10);
+__GEN_LOGICAL2(srw, 0x18, 0x10, PPC_INTEGER);
+
+#if defined(TARGET_PPC64)
+/* sld & sld. */
+__GEN_LOGICAL2(sld, 0x1B, 0x00, PPC_64B);
+/* srad & srad. */
+__GEN_LOGICAL2(srad, 0x1A, 0x18, PPC_64B);
+/* sradi & sradi. */
+static inline void gen_sradi (DisasContext *ctx, int n)
+{
+    uint64_t mask;
+    int sh, mb, me;
+
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    sh = SH(ctx->opcode) + (n << 5);
+    if (sh != 0) {
+        gen_op_move_T1_T0();
+        mb = 64 - SH(ctx->opcode);
+        me = 63;
+        mask = MASK(mb, me);
+        gen_op_sradi(sh, mask >> 32, mask);
+    }
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+GEN_HANDLER(sradi0, 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B)
+{
+    gen_sradi(ctx, 0);
+}
+GEN_HANDLER(sradi1, 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B)
+{
+    gen_sradi(ctx, 1);
+}
+/* srd & srd. */
+__GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B);
+#endif
 
 /***                       Floating-Point arithmetic                       ***/
-#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat)                           \
-GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT)                   \
+#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat, type)                     \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, type)                        \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
     gen_op_reset_scrfx();                                                     \
@@ -792,19 +1625,19 @@
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 
-#define GEN_FLOAT_ACB(name, op2)                                              \
-_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0);                                     \
-_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
+#define GEN_FLOAT_ACB(name, op2, type)                                        \
+_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0, type);                               \
+_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1, type);
 
 #define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat)                     \
 GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
     gen_op_reset_scrfx();                                                     \
@@ -815,7 +1648,7 @@
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 #define GEN_FLOAT_AB(name, op2, inval)                                        \
@@ -825,8 +1658,8 @@
 #define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat)                     \
 GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT)                        \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
     gen_op_reset_scrfx();                                                     \
@@ -837,40 +1670,40 @@
         gen_op_frsp();                                                        \
     }                                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 #define GEN_FLOAT_AC(name, op2, inval)                                        \
 _GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0);                               \
 _GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
 
-#define GEN_FLOAT_B(name, op2, op3)                                           \
-GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT)                   \
+#define GEN_FLOAT_B(name, op2, op3, type)                                     \
+GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, type)                        \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
     gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
     gen_op_f##name();                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 
-#define GEN_FLOAT_BS(name, op1, op2)                                          \
-GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT)                   \
+#define GEN_FLOAT_BS(name, op1, op2, type)                                    \
+GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, type)                        \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
     gen_op_reset_scrfx();                                                     \
     gen_op_load_fpr_FT0(rB(ctx->opcode));                                     \
     gen_op_f##name();                                                         \
     gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
-    if (Rc(ctx->opcode))                                                      \
+    if (unlikely(Rc(ctx->opcode) != 0))                                       \
         gen_op_set_Rc1();                                                     \
 }
 
@@ -881,36 +1714,39 @@
 /* fmul - fmuls */
 GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
 
+/* fre */
+GEN_FLOAT_BS(re, 0x3F, 0x18, PPC_FLOAT_EXT);
+
 /* fres */
-GEN_FLOAT_BS(res, 0x3B, 0x18);
+GEN_FLOAT_BS(res, 0x3B, 0x18, PPC_FLOAT_FRES);
 
 /* frsqrte */
-GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
+GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A, PPC_FLOAT_FRSQRTE);
 
 /* fsel */
-_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
+_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0, PPC_FLOAT_FSEL);
 /* fsub - fsubs */
 GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
 /* Optional: */
 /* fsqrt */
-GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
+GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rB(ctx->opcode));
     gen_op_fsqrt();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
-GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
+GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_FSQRT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_reset_scrfx();
@@ -918,34 +1754,51 @@
     gen_op_fsqrt();
     gen_op_frsp();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
 /***                     Floating-Point multiply-and-add                   ***/
 /* fmadd - fmadds */
-GEN_FLOAT_ACB(madd, 0x1D);
+GEN_FLOAT_ACB(madd, 0x1D, PPC_FLOAT);
 /* fmsub - fmsubs */
-GEN_FLOAT_ACB(msub, 0x1C);
+GEN_FLOAT_ACB(msub, 0x1C, PPC_FLOAT);
 /* fnmadd - fnmadds */
-GEN_FLOAT_ACB(nmadd, 0x1F);
+GEN_FLOAT_ACB(nmadd, 0x1F, PPC_FLOAT);
 /* fnmsub - fnmsubs */
-GEN_FLOAT_ACB(nmsub, 0x1E);
+GEN_FLOAT_ACB(nmsub, 0x1E, PPC_FLOAT);
 
 /***                     Floating-Point round & convert                    ***/
 /* fctiw */
-GEN_FLOAT_B(ctiw, 0x0E, 0x00);
+GEN_FLOAT_B(ctiw, 0x0E, 0x00, PPC_FLOAT);
 /* fctiwz */
-GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
+GEN_FLOAT_B(ctiwz, 0x0F, 0x00, PPC_FLOAT);
 /* frsp */
-GEN_FLOAT_B(rsp, 0x0C, 0x00);
+GEN_FLOAT_B(rsp, 0x0C, 0x00, PPC_FLOAT);
+#if defined(TARGET_PPC64)
+/* fcfid */
+GEN_FLOAT_B(cfid, 0x0E, 0x1A, PPC_64B);
+/* fctid */
+GEN_FLOAT_B(ctid, 0x0E, 0x19, PPC_64B);
+/* fctidz */
+GEN_FLOAT_B(ctidz, 0x0F, 0x19, PPC_64B);
+#endif
+
+/* frin */
+GEN_FLOAT_B(rin, 0x08, 0x0C, PPC_FLOAT_EXT);
+/* friz */
+GEN_FLOAT_B(riz, 0x08, 0x0D, PPC_FLOAT_EXT);
+/* frip */
+GEN_FLOAT_B(rip, 0x08, 0x0E, PPC_FLOAT_EXT);
+/* frim */
+GEN_FLOAT_B(rim, 0x08, 0x0F, PPC_FLOAT_EXT);
 
 /***                         Floating-Point compare                        ***/
 /* fcmpo */
-GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
+GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_reset_scrfx();
@@ -956,10 +1809,10 @@
 }
 
 /* fcmpu */
-GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
+GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_reset_scrfx();
@@ -971,33 +1824,33 @@
 
 /***                         Floating-point move                           ***/
 /* fabs */
-GEN_FLOAT_B(abs, 0x08, 0x08);
+GEN_FLOAT_B(abs, 0x08, 0x08, PPC_FLOAT);
 
 /* fmr  - fmr. */
 GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_reset_scrfx();
     gen_op_load_fpr_FT0(rB(ctx->opcode));
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
 /* fnabs */
-GEN_FLOAT_B(nabs, 0x08, 0x04);
+GEN_FLOAT_B(nabs, 0x08, 0x04, PPC_FLOAT);
 /* fneg */
-GEN_FLOAT_B(neg, 0x08, 0x01);
+GEN_FLOAT_B(neg, 0x08, 0x01, PPC_FLOAT);
 
 /***                  Floating-Point status & ctrl register                ***/
 /* mcrfs */
 GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_load_fpscr_T0(crfS(ctx->opcode));
@@ -1008,13 +1861,13 @@
 /* mffs */
 GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_load_fpscr();
     gen_op_store_FT0_fpr(rD(ctx->opcode));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
@@ -1022,16 +1875,16 @@
 GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
 {
     uint8_t crb;
-    
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     crb = crbD(ctx->opcode) >> 2;
     gen_op_load_fpscr_T0(crb);
-    gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03)));
+    gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
     gen_op_store_T0_fpscr(crb);
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
@@ -1039,47 +1892,111 @@
 GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
 {
     uint8_t crb;
-    
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     crb = crbD(ctx->opcode) >> 2;
     gen_op_load_fpscr_T0(crb);
     gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
     gen_op_store_T0_fpscr(crb);
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
 /* mtfsf */
 GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_load_fpr_FT0(rB(ctx->opcode));
     gen_op_store_fpscr(FM(ctx->opcode));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
 /* mtfsfi */
 GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
 {
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
+    if (unlikely(!ctx->fpu_enabled)) {
+        GEN_EXCP_NO_FP(ctx);
         return;
     }
     gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
-    if (Rc(ctx->opcode))
+    if (unlikely(Rc(ctx->opcode) != 0))
         gen_op_set_Rc1();
 }
 
+/***                           Addressing modes                            ***/
+/* Register indirect with immediate index : EA = (rA|0) + SIMM */
+static inline void gen_addr_imm_index (DisasContext *ctx, target_long maskl)
+{
+    target_long simm = SIMM(ctx->opcode);
+
+    simm &= ~maskl;
+    if (rA(ctx->opcode) == 0) {
+        gen_set_T0(simm);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        if (likely(simm != 0))
+            gen_op_addi(simm);
+    }
+#ifdef DEBUG_MEMORY_ACCESSES
+    gen_op_print_mem_EA();
+#endif
+}
+
+static inline void gen_addr_reg_index (DisasContext *ctx)
+{
+    if (rA(ctx->opcode) == 0) {
+        gen_op_load_gpr_T0(rB(ctx->opcode));
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rB(ctx->opcode));
+        gen_op_add();
+    }
+#ifdef DEBUG_MEMORY_ACCESSES
+    gen_op_print_mem_EA();
+#endif
+}
+
+static inline void gen_addr_register (DisasContext *ctx)
+{
+    if (rA(ctx->opcode) == 0) {
+        gen_op_reset_T0();
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+    }
+#ifdef DEBUG_MEMORY_ACCESSES
+    gen_op_print_mem_EA();
+#endif
+}
+
 /***                             Integer load                              ***/
 #define op_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
 #if defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+#define OP_LD_TABLE(width)                                                    \
+static GenOpFunc *gen_op_l##width[] = {                                       \
+    &gen_op_l##width##_raw,                                                   \
+    &gen_op_l##width##_le_raw,                                                \
+    &gen_op_l##width##_64_raw,                                                \
+    &gen_op_l##width##_le_64_raw,                                             \
+};
+#define OP_ST_TABLE(width)                                                    \
+static GenOpFunc *gen_op_st##width[] = {                                      \
+    &gen_op_st##width##_raw,                                                  \
+    &gen_op_st##width##_le_raw,                                               \
+    &gen_op_st##width##_64_raw,                                               \
+    &gen_op_st##width##_le_64_raw,                                            \
+};
+/* Byte access routine are endian safe */
+#define gen_op_stb_le_64_raw gen_op_stb_64_raw
+#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw
+#else
 #define OP_LD_TABLE(width)                                                    \
 static GenOpFunc *gen_op_l##width[] = {                                       \
     &gen_op_l##width##_raw,                                                   \
@@ -1090,10 +2007,40 @@
     &gen_op_st##width##_raw,                                                  \
     &gen_op_st##width##_le_raw,                                               \
 };
+#endif
 /* Byte access routine are endian safe */
 #define gen_op_stb_le_raw gen_op_stb_raw
 #define gen_op_lbz_le_raw gen_op_lbz_raw
 #else
+#if defined(TARGET_PPC64)
+#define OP_LD_TABLE(width)                                                    \
+static GenOpFunc *gen_op_l##width[] = {                                       \
+    &gen_op_l##width##_user,                                                  \
+    &gen_op_l##width##_le_user,                                               \
+    &gen_op_l##width##_kernel,                                                \
+    &gen_op_l##width##_le_kernel,                                             \
+    &gen_op_l##width##_64_user,                                               \
+    &gen_op_l##width##_le_64_user,                                            \
+    &gen_op_l##width##_64_kernel,                                             \
+    &gen_op_l##width##_le_64_kernel,                                          \
+};
+#define OP_ST_TABLE(width)                                                    \
+static GenOpFunc *gen_op_st##width[] = {                                      \
+    &gen_op_st##width##_user,                                                 \
+    &gen_op_st##width##_le_user,                                              \
+    &gen_op_st##width##_kernel,                                               \
+    &gen_op_st##width##_le_kernel,                                            \
+    &gen_op_st##width##_64_user,                                              \
+    &gen_op_st##width##_le_64_user,                                           \
+    &gen_op_st##width##_64_kernel,                                            \
+    &gen_op_st##width##_le_64_kernel,                                         \
+};
+/* Byte access routine are endian safe */
+#define gen_op_stb_le_64_user gen_op_stb_64_user
+#define gen_op_lbz_le_64_user gen_op_lbz_64_user
+#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel
+#define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel
+#else
 #define OP_LD_TABLE(width)                                                    \
 static GenOpFunc *gen_op_l##width[] = {                                       \
     &gen_op_l##width##_user,                                                  \
@@ -1108,6 +2055,7 @@
     &gen_op_st##width##_kernel,                                               \
     &gen_op_st##width##_le_kernel,                                            \
 };
+#endif
 /* Byte access routine are endian safe */
 #define gen_op_stb_le_user gen_op_stb_user
 #define gen_op_lbz_le_user gen_op_lbz_user
@@ -1115,175 +2063,294 @@
 #define gen_op_lbz_le_kernel gen_op_lbz_kernel
 #endif
 
-#define GEN_LD(width, opc)                                                    \
-GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)               \
+#define GEN_LD(width, opc, type)                                              \
+GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type)                      \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_set_T0(simm);                                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        if (simm != 0)                                                        \
-            gen_op_addi(simm);                                                \
-    }                                                                         \
+    gen_addr_imm_index(ctx, 0);                                               \
     op_ldst(l##width);                                                        \
     gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
 }
 
-#define GEN_LDU(width, opc)                                                   \
-GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)            \
+#define GEN_LDU(width, opc, type)                                             \
+GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type)                   \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (rA(ctx->opcode) == 0 ||                                               \
-        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
-        RET_INVAL(ctx);                                                       \
+    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
+                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
+        GEN_EXCP_INVAL(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    if (simm != 0)                                                            \
-        gen_op_addi(simm);                                                    \
+    if (type == PPC_64B)                                                      \
+        gen_addr_imm_index(ctx, 0x03);                                        \
+    else                                                                      \
+        gen_addr_imm_index(ctx, 0);                                           \
     op_ldst(l##width);                                                        \
     gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
-#define GEN_LDUX(width, opc)                                                  \
-GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)           \
+#define GEN_LDUX(width, opc2, opc3, type)                                     \
+GEN_HANDLER(l##width##ux, 0x1F, opc2, opc3, 0x00000001, type)                 \
 {                                                                             \
-    if (rA(ctx->opcode) == 0 ||                                               \
-        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
-        RET_INVAL(ctx);                                                       \
+    if (unlikely(rA(ctx->opcode) == 0 ||                                      \
+                 rA(ctx->opcode) == rD(ctx->opcode))) {                       \
+        GEN_EXCP_INVAL(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
-    gen_op_add();                                                             \
+    gen_addr_reg_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
     gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
-#define GEN_LDX(width, opc2, opc3)                                            \
-GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)           \
+#define GEN_LDX(width, opc2, opc3, type)                                      \
+GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, type)                  \
 {                                                                             \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
-        gen_op_add();                                                         \
-    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
     gen_op_store_T1_gpr(rD(ctx->opcode));                                     \
 }
 
-#define GEN_LDS(width, op)                                                    \
+#define GEN_LDS(width, op, type)                                              \
 OP_LD_TABLE(width);                                                           \
-GEN_LD(width, op | 0x20);                                                     \
-GEN_LDU(width, op | 0x21);                                                    \
-GEN_LDUX(width, op | 0x01);                                                   \
-GEN_LDX(width, 0x17, op | 0x00)
+GEN_LD(width, op | 0x20, type);                                               \
+GEN_LDU(width, op | 0x21, type);                                              \
+GEN_LDUX(width, 0x17, op | 0x01, type);                                       \
+GEN_LDX(width, 0x17, op | 0x00, type)
 
 /* lbz lbzu lbzux lbzx */
-GEN_LDS(bz, 0x02);
+GEN_LDS(bz, 0x02, PPC_INTEGER);
 /* lha lhau lhaux lhax */
-GEN_LDS(ha, 0x0A);
+GEN_LDS(ha, 0x0A, PPC_INTEGER);
 /* lhz lhzu lhzux lhzx */
-GEN_LDS(hz, 0x08);
+GEN_LDS(hz, 0x08, PPC_INTEGER);
 /* lwz lwzu lwzux lwzx */
-GEN_LDS(wz, 0x00);
+GEN_LDS(wz, 0x00, PPC_INTEGER);
+#if defined(TARGET_PPC64)
+OP_LD_TABLE(wa);
+OP_LD_TABLE(d);
+/* lwaux */
+GEN_LDUX(wa, 0x15, 0x0B, PPC_64B);
+/* lwax */
+GEN_LDX(wa, 0x15, 0x0A, PPC_64B);
+/* ldux */
+GEN_LDUX(d, 0x15, 0x01, PPC_64B);
+/* ldx */
+GEN_LDX(d, 0x15, 0x00, PPC_64B);
+GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B)
+{
+    if (Rc(ctx->opcode)) {
+        if (unlikely(rA(ctx->opcode) == 0 ||
+                     rA(ctx->opcode) == rD(ctx->opcode))) {
+            GEN_EXCP_INVAL(ctx);
+            return;
+        }
+    }
+    gen_addr_imm_index(ctx, 0x03);
+    if (ctx->opcode & 0x02) {
+        /* lwa (lwau is undefined) */
+        op_ldst(lwa);
+    } else {
+        /* ld - ldu */
+        op_ldst(ld);
+    }
+    gen_op_store_T1_gpr(rD(ctx->opcode));
+    if (Rc(ctx->opcode))
+        gen_op_store_T0_gpr(rA(ctx->opcode));
+}
+/* lq */
+GEN_HANDLER(lq, 0x38, 0xFF, 0xFF, 0x00000000, PPC_64BX)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    int ra, rd;
+
+    /* Restore CPU state */
+    if (unlikely(ctx->supervisor == 0)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    ra = rA(ctx->opcode);
+    rd = rD(ctx->opcode);
+    if (unlikely((rd & 1) || rd == ra)) {
+        GEN_EXCP_INVAL(ctx);
+        return;
+    }
+    if (unlikely(ctx->mem_idx & 1)) {
+        /* Little-endian mode is not handled */
+        GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+        return;
+    }
+    gen_addr_imm_index(ctx, 0x0F);
+    op_ldst(ld);
+    gen_op_store_T1_gpr(rd);
+    gen_op_addi(8);
+    op_ldst(ld);
+    gen_op_store_T1_gpr(rd + 1);
+#endif
+}
+#endif
 
 /***                              Integer store                            ***/
-#define GEN_ST(width, opc)                                                    \
-GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)              \
+#define GEN_ST(width, opc, type)                                              \
+GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type)                     \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_set_T0(simm);                                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        if (simm != 0)                                                        \
-            gen_op_addi(simm);                                                \
-    }                                                                         \
+    gen_addr_imm_index(ctx, 0);                                               \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
     op_ldst(st##width);                                                       \
 }
 
-#define GEN_STU(width, opc)                                                   \
-GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)           \
+#define GEN_STU(width, opc, type)                                             \
+GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type)                  \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL(ctx);                                                       \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        GEN_EXCP_INVAL(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    if (simm != 0)                                                            \
-        gen_op_addi(simm);                                                    \
+    if (type == PPC_64B)                                                      \
+        gen_addr_imm_index(ctx, 0x03);                                        \
+    else                                                                      \
+        gen_addr_imm_index(ctx, 0);                                           \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
     op_ldst(st##width);                                                       \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
-#define GEN_STUX(width, opc)                                                  \
-GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER)          \
+#define GEN_STUX(width, opc2, opc3, type)                                     \
+GEN_HANDLER(st##width##ux, 0x1F, opc2, opc3, 0x00000001, type)                \
 {                                                                             \
-    if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL(ctx);                                                       \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        GEN_EXCP_INVAL(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
-    gen_op_add();                                                             \
+    gen_addr_reg_index(ctx);                                                  \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
     op_ldst(st##width);                                                       \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
-#define GEN_STX(width, opc2, opc3)                                            \
-GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER)          \
+#define GEN_STX(width, opc2, opc3, type)                                      \
+GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, type)                 \
 {                                                                             \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
-        gen_op_add();                                                         \
-    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
     gen_op_load_gpr_T1(rS(ctx->opcode));                                      \
     op_ldst(st##width);                                                       \
 }
 
-#define GEN_STS(width, op)                                                    \
+#define GEN_STS(width, op, type)                                              \
 OP_ST_TABLE(width);                                                           \
-GEN_ST(width, op | 0x20);                                                     \
-GEN_STU(width, op | 0x21);                                                    \
-GEN_STUX(width, op | 0x01);                                                   \
-GEN_STX(width, 0x17, op | 0x00)
+GEN_ST(width, op | 0x20, type);                                               \
+GEN_STU(width, op | 0x21, type);                                              \
+GEN_STUX(width, 0x17, op | 0x01, type);                                       \
+GEN_STX(width, 0x17, op | 0x00, type)
 
 /* stb stbu stbux stbx */
-GEN_STS(b, 0x06);
+GEN_STS(b, 0x06, PPC_INTEGER);
 /* sth sthu sthux sthx */
-GEN_STS(h, 0x0C);
+GEN_STS(h, 0x0C, PPC_INTEGER);
 /* stw stwu stwux stwx */
-GEN_STS(w, 0x04);
+GEN_STS(w, 0x04, PPC_INTEGER);
+#if defined(TARGET_PPC64)
+OP_ST_TABLE(d);
+GEN_STUX(d, 0x15, 0x05, PPC_64B);
+GEN_STX(d, 0x15, 0x04, PPC_64B);
+GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000000, PPC_64B)
+{
+    int rs;
 
+    rs = rS(ctx->opcode);
+    if ((ctx->opcode & 0x3) == 0x2) {
+#if defined(CONFIG_USER_ONLY)
+        GEN_EXCP_PRIVOPC(ctx);
+#else
+        /* stq */
+        if (unlikely(ctx->supervisor == 0)) {
+            GEN_EXCP_PRIVOPC(ctx);
+            return;
+        }
+        if (unlikely(rs & 1)) {
+            GEN_EXCP_INVAL(ctx);
+            return;
+        }
+        if (unlikely(ctx->mem_idx & 1)) {
+            /* Little-endian mode is not handled */
+            GEN_EXCP(ctx, POWERPC_EXCP_ALIGN, POWERPC_EXCP_ALIGN_LE);
+            return;
+        }
+        gen_addr_imm_index(ctx, 0x03);
+        gen_op_load_gpr_T1(rs);
+        op_ldst(std);
+        gen_op_addi(8);
+        gen_op_load_gpr_T1(rs + 1);
+        op_ldst(std);
+#endif
+    } else {
+        /* std / stdu */
+        if (Rc(ctx->opcode)) {
+            if (unlikely(rA(ctx->opcode) == 0)) {
+                GEN_EXCP_INVAL(ctx);
+                return;
+            }
+        }
+        gen_addr_imm_index(ctx, 0x03);
+        gen_op_load_gpr_T1(rs);
+        op_ldst(std);
+        if (Rc(ctx->opcode))
+            gen_op_store_T0_gpr(rA(ctx->opcode));
+    }
+}
+#endif
 /***                Integer load and store with byte reverse               ***/
 /* lhbrx */
 OP_LD_TABLE(hbr);
-GEN_LDX(hbr, 0x16, 0x18);
+GEN_LDX(hbr, 0x16, 0x18, PPC_INTEGER);
 /* lwbrx */
 OP_LD_TABLE(wbr);
-GEN_LDX(wbr, 0x16, 0x10);
+GEN_LDX(wbr, 0x16, 0x10, PPC_INTEGER);
 /* sthbrx */
 OP_ST_TABLE(hbr);
-GEN_STX(hbr, 0x16, 0x1C);
+GEN_STX(hbr, 0x16, 0x1C, PPC_INTEGER);
 /* stwbrx */
 OP_ST_TABLE(wbr);
-GEN_STX(wbr, 0x16, 0x14);
+GEN_STX(wbr, 0x16, 0x14, PPC_INTEGER);
 
 /***                    Integer load and store multiple                    ***/
 #define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
+#if defined(TARGET_PPC64)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc1 *gen_op_lmw[] = {
+    &gen_op_lmw_raw,
+    &gen_op_lmw_le_raw,
+    &gen_op_lmw_64_raw,
+    &gen_op_lmw_le_64_raw,
+};
+static GenOpFunc1 *gen_op_stmw[] = {
+    &gen_op_stmw_64_raw,
+    &gen_op_stmw_le_64_raw,
+};
+#else
+static GenOpFunc1 *gen_op_lmw[] = {
+    &gen_op_lmw_user,
+    &gen_op_lmw_le_user,
+    &gen_op_lmw_kernel,
+    &gen_op_lmw_le_kernel,
+    &gen_op_lmw_64_user,
+    &gen_op_lmw_le_64_user,
+    &gen_op_lmw_64_kernel,
+    &gen_op_lmw_le_64_kernel,
+};
+static GenOpFunc1 *gen_op_stmw[] = {
+    &gen_op_stmw_user,
+    &gen_op_stmw_le_user,
+    &gen_op_stmw_kernel,
+    &gen_op_stmw_le_kernel,
+    &gen_op_stmw_64_user,
+    &gen_op_stmw_le_64_user,
+    &gen_op_stmw_64_kernel,
+    &gen_op_stmw_le_64_kernel,
+};
+#endif
+#else
 #if defined(CONFIG_USER_ONLY)
 static GenOpFunc1 *gen_op_lmw[] = {
     &gen_op_lmw_raw,
@@ -1307,40 +2374,82 @@
     &gen_op_stmw_le_kernel,
 };
 #endif
+#endif
 
 /* lmw */
 GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    int simm = SIMM(ctx->opcode);
-
-    if (rA(ctx->opcode) == 0) {
-        gen_op_set_T0(simm);
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        if (simm != 0)
-            gen_op_addi(simm);
-    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_imm_index(ctx, 0);
     op_ldstm(lmw, rD(ctx->opcode));
 }
 
 /* stmw */
 GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
 {
-    int simm = SIMM(ctx->opcode);
-
-    if (rA(ctx->opcode) == 0) {
-        gen_op_set_T0(simm);
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        if (simm != 0)
-            gen_op_addi(simm);
-    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_imm_index(ctx, 0);
     op_ldstm(stmw, rS(ctx->opcode));
 }
 
 /***                    Integer load and store strings                     ***/
 #define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
 #define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
+#if defined(TARGET_PPC64)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc1 *gen_op_lswi[] = {
+    &gen_op_lswi_raw,
+    &gen_op_lswi_le_raw,
+    &gen_op_lswi_64_raw,
+    &gen_op_lswi_le_64_raw,
+};
+static GenOpFunc3 *gen_op_lswx[] = {
+    &gen_op_lswx_raw,
+    &gen_op_lswx_le_raw,
+    &gen_op_lswx_64_raw,
+    &gen_op_lswx_le_64_raw,
+};
+static GenOpFunc1 *gen_op_stsw[] = {
+    &gen_op_stsw_raw,
+    &gen_op_stsw_le_raw,
+    &gen_op_stsw_64_raw,
+    &gen_op_stsw_le_64_raw,
+};
+#else
+static GenOpFunc1 *gen_op_lswi[] = {
+    &gen_op_lswi_user,
+    &gen_op_lswi_le_user,
+    &gen_op_lswi_kernel,
+    &gen_op_lswi_le_kernel,
+    &gen_op_lswi_64_user,
+    &gen_op_lswi_le_64_user,
+    &gen_op_lswi_64_kernel,
+    &gen_op_lswi_le_64_kernel,
+};
+static GenOpFunc3 *gen_op_lswx[] = {
+    &gen_op_lswx_user,
+    &gen_op_lswx_le_user,
+    &gen_op_lswx_kernel,
+    &gen_op_lswx_le_kernel,
+    &gen_op_lswx_64_user,
+    &gen_op_lswx_le_64_user,
+    &gen_op_lswx_64_kernel,
+    &gen_op_lswx_le_64_kernel,
+};
+static GenOpFunc1 *gen_op_stsw[] = {
+    &gen_op_stsw_user,
+    &gen_op_stsw_le_user,
+    &gen_op_stsw_kernel,
+    &gen_op_stsw_le_kernel,
+    &gen_op_stsw_64_user,
+    &gen_op_stsw_le_64_user,
+    &gen_op_stsw_64_kernel,
+    &gen_op_stsw_le_64_kernel,
+};
+#endif
+#else
 #if defined(CONFIG_USER_ONLY)
 static GenOpFunc1 *gen_op_lswi[] = {
     &gen_op_lswi_raw,
@@ -1374,6 +2483,7 @@
     &gen_op_stsw_le_kernel,
 };
 #endif
+#endif
 
 /* lswi */
 /* PowerPC32 specification says we must generate an exception if
@@ -1391,19 +2501,17 @@
     if (nb == 0)
         nb = 32;
     nr = nb / 4;
-    if (((start + nr) > 32  && start <= ra && (start + nr - 32) > ra) ||
-        ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
-        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+    if (unlikely(((start + nr) > 32  &&
+                  start <= ra && (start + nr - 32) > ra) ||
+                 ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
+        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
+                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_LSWX);
         return;
     }
-    if (ra == 0) {
-        gen_op_set_T0(0);
-    } else {
-        gen_op_load_gpr_T0(ra);
-    }
-    gen_op_set_T1(nb);
     /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_op_update_nip((ctx)->nip - 4); 
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_register(ctx);
+    gen_op_set_T1(nb);
     op_ldsts(lswi, start);
 }
 
@@ -1413,17 +2521,13 @@
     int ra = rA(ctx->opcode);
     int rb = rB(ctx->opcode);
 
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
     if (ra == 0) {
-        gen_op_load_gpr_T0(rb);
         ra = rb;
-    } else {
-        gen_op_load_gpr_T0(ra);
-        gen_op_load_gpr_T1(rb);
-        gen_op_add();
     }
     gen_op_load_xer_bc();
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_op_update_nip((ctx)->nip - 4); 
     op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
 }
 
@@ -1432,51 +2536,76 @@
 {
     int nb = NB(ctx->opcode);
 
-    if (rA(ctx->opcode) == 0) {
-        gen_op_set_T0(0);
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_register(ctx);
     if (nb == 0)
         nb = 32;
     gen_op_set_T1(nb);
-    /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_op_update_nip((ctx)->nip - 4); 
     op_ldsts(stsw, rS(ctx->opcode));
 }
 
 /* stswx */
 GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
 {
-    int ra = rA(ctx->opcode);
-
-    if (ra == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-        ra = rB(ctx->opcode);
-    } else {
-        gen_op_load_gpr_T0(ra);
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
-    gen_op_load_xer_bc();
     /* NIP cannot be restored if the memory exception comes from an helper */
-    gen_op_update_nip((ctx)->nip - 4); 
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    gen_op_load_xer_bc();
     op_ldsts(stsw, rS(ctx->opcode));
 }
 
 /***                        Memory synchronisation                         ***/
 /* eieio */
-GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FFF801, PPC_MEM_EIEIO)
 {
 }
 
 /* isync */
-GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FFF801, PPC_MEM)
 {
+    GEN_STOP(ctx);
 }
 
 #define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
 #define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_lwarx[] = {
+    &gen_op_lwarx_raw,
+    &gen_op_lwarx_le_raw,
+    &gen_op_lwarx_64_raw,
+    &gen_op_lwarx_le_64_raw,
+};
+static GenOpFunc *gen_op_stwcx[] = {
+    &gen_op_stwcx_raw,
+    &gen_op_stwcx_le_raw,
+    &gen_op_stwcx_64_raw,
+    &gen_op_stwcx_le_64_raw,
+};
+#else
+static GenOpFunc *gen_op_lwarx[] = {
+    &gen_op_lwarx_user,
+    &gen_op_lwarx_le_user,
+    &gen_op_lwarx_kernel,
+    &gen_op_lwarx_le_kernel,
+    &gen_op_lwarx_64_user,
+    &gen_op_lwarx_le_64_user,
+    &gen_op_lwarx_64_kernel,
+    &gen_op_lwarx_le_64_kernel,
+};
+static GenOpFunc *gen_op_stwcx[] = {
+    &gen_op_stwcx_user,
+    &gen_op_stwcx_le_user,
+    &gen_op_stwcx_kernel,
+    &gen_op_stwcx_le_kernel,
+    &gen_op_stwcx_64_user,
+    &gen_op_stwcx_le_64_user,
+    &gen_op_stwcx_64_kernel,
+    &gen_op_stwcx_le_64_kernel,
+};
+#endif
+#else
 #if defined(CONFIG_USER_ONLY)
 static GenOpFunc *gen_op_lwarx[] = {
     &gen_op_lwarx_raw,
@@ -1500,17 +2629,14 @@
     &gen_op_stwcx_le_kernel,
 };
 #endif
+#endif
 
 /* lwarx */
-GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
+GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
 {
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
     op_lwarx();
     gen_op_store_T1_gpr(rD(ctx->opcode));
 }
@@ -1518,216 +2644,235 @@
 /* stwcx. */
 GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
 {
-        if (rA(ctx->opcode) == 0) {
-            gen_op_load_gpr_T0(rB(ctx->opcode));
-        } else {
-            gen_op_load_gpr_T0(rA(ctx->opcode));
-            gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-        }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
     gen_op_load_gpr_T1(rS(ctx->opcode));
     op_stwcx();
 }
 
-/* sync */
-GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
+#if defined(TARGET_PPC64)
+#define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])()
+#define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_ldarx[] = {
+    &gen_op_ldarx_raw,
+    &gen_op_ldarx_le_raw,
+    &gen_op_ldarx_64_raw,
+    &gen_op_ldarx_le_64_raw,
+};
+static GenOpFunc *gen_op_stdcx[] = {
+    &gen_op_stdcx_raw,
+    &gen_op_stdcx_le_raw,
+    &gen_op_stdcx_64_raw,
+    &gen_op_stdcx_le_64_raw,
+};
+#else
+static GenOpFunc *gen_op_ldarx[] = {
+    &gen_op_ldarx_user,
+    &gen_op_ldarx_le_user,
+    &gen_op_ldarx_kernel,
+    &gen_op_ldarx_le_kernel,
+    &gen_op_ldarx_64_user,
+    &gen_op_ldarx_le_64_user,
+    &gen_op_ldarx_64_kernel,
+    &gen_op_ldarx_le_64_kernel,
+};
+static GenOpFunc *gen_op_stdcx[] = {
+    &gen_op_stdcx_user,
+    &gen_op_stdcx_le_user,
+    &gen_op_stdcx_kernel,
+    &gen_op_stdcx_le_kernel,
+    &gen_op_stdcx_64_user,
+    &gen_op_stdcx_le_64_user,
+    &gen_op_stdcx_64_kernel,
+    &gen_op_stdcx_le_64_kernel,
+};
+#endif
+
+/* ldarx */
+GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_64B)
 {
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    op_ldarx();
+    gen_op_store_T1_gpr(rD(ctx->opcode));
+}
+
+/* stdcx. */
+GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_64B)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    gen_op_load_gpr_T1(rS(ctx->opcode));
+    op_stdcx();
+}
+#endif /* defined(TARGET_PPC64) */
+
+/* sync */
+GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x039FF801, PPC_MEM_SYNC)
+{
+}
+
+/* wait */
+GEN_HANDLER(wait, 0x1F, 0x1E, 0x01, 0x03FFF801, PPC_WAIT)
+{
+    /* Stop translation, as the CPU is supposed to sleep from now */
+    gen_op_wait();
+    GEN_EXCP(ctx, EXCP_HLT, 1);
 }
 
 /***                         Floating-point load                           ***/
-#define GEN_LDF(width, opc)                                                   \
-GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)                 \
+#define GEN_LDF(width, opc, type)                                             \
+GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type)                      \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_set_T0(simm);                                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        if (simm != 0)                                                        \
-            gen_op_addi(simm);                                                \
-    }                                                                         \
+    gen_addr_imm_index(ctx, 0);                                               \
     op_ldst(l##width);                                                        \
-    gen_op_store_FT1_fpr(rD(ctx->opcode));                                    \
+    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
 }
 
-#define GEN_LDUF(width, opc)                                                  \
-GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)              \
+#define GEN_LDUF(width, opc, type)                                            \
+GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type)                   \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0 ||                                               \
-        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
-        RET_INVAL(ctx);                                                       \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        GEN_EXCP_INVAL(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    if (simm != 0)                                                            \
-        gen_op_addi(simm);                                                    \
+    gen_addr_imm_index(ctx, 0);                                               \
     op_ldst(l##width);                                                        \
-    gen_op_store_FT1_fpr(rD(ctx->opcode));                                    \
+    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
-#define GEN_LDUXF(width, opc)                                                 \
-GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)             \
+#define GEN_LDUXF(width, opc, type)                                           \
+GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, type)                  \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0 ||                                               \
-        rA(ctx->opcode) == rD(ctx->opcode)) {                                 \
-        RET_INVAL(ctx);                                                       \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        GEN_EXCP_INVAL(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
-    gen_op_add();                                                             \
+    gen_addr_reg_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
-    gen_op_store_FT1_fpr(rD(ctx->opcode));                                    \
+    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
-#define GEN_LDXF(width, opc2, opc3)                                           \
-GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT)             \
+#define GEN_LDXF(width, opc2, opc3, type)                                     \
+GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, type)                  \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
-        gen_op_add();                                                         \
-    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
     op_ldst(l##width);                                                        \
-    gen_op_store_FT1_fpr(rD(ctx->opcode));                                    \
+    gen_op_store_FT0_fpr(rD(ctx->opcode));                                    \
 }
 
-#define GEN_LDFS(width, op)                                                   \
+#define GEN_LDFS(width, op, type)                                             \
 OP_LD_TABLE(width);                                                           \
-GEN_LDF(width, op | 0x20);                                                    \
-GEN_LDUF(width, op | 0x21);                                                   \
-GEN_LDUXF(width, op | 0x01);                                                  \
-GEN_LDXF(width, 0x17, op | 0x00)
+GEN_LDF(width, op | 0x20, type);                                              \
+GEN_LDUF(width, op | 0x21, type);                                             \
+GEN_LDUXF(width, op | 0x01, type);                                            \
+GEN_LDXF(width, 0x17, op | 0x00, type)
 
 /* lfd lfdu lfdux lfdx */
-GEN_LDFS(fd, 0x12);
+GEN_LDFS(fd, 0x12, PPC_FLOAT);
 /* lfs lfsu lfsux lfsx */
-GEN_LDFS(fs, 0x10);
+GEN_LDFS(fs, 0x10, PPC_FLOAT);
 
 /***                         Floating-point store                          ***/
-#define GEN_STF(width, opc)                                                   \
-GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)                \
+#define GEN_STF(width, opc, type)                                             \
+GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type)                     \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_set_T0(simm);                                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        if (simm != 0)                                                        \
-            gen_op_addi(simm);                                                \
-    }                                                                         \
-    gen_op_load_fpr_FT1(rS(ctx->opcode));                                     \
+    gen_addr_imm_index(ctx, 0);                                               \
+    gen_op_load_fpr_FT0(rS(ctx->opcode));                                     \
     op_ldst(st##width);                                                       \
 }
 
-#define GEN_STUF(width, opc)                                                  \
-GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT)             \
+#define GEN_STUF(width, opc, type)                                            \
+GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type)                  \
 {                                                                             \
-    uint32_t simm = SIMM(ctx->opcode);                                        \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL(ctx);                                                       \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        GEN_EXCP_INVAL(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    if (simm != 0)                                                            \
-        gen_op_addi(simm);                                                    \
-    gen_op_load_fpr_FT1(rS(ctx->opcode));                                     \
+    gen_addr_imm_index(ctx, 0);                                               \
+    gen_op_load_fpr_FT0(rS(ctx->opcode));                                     \
     op_ldst(st##width);                                                       \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
-#define GEN_STUXF(width, opc)                                                 \
-GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT)            \
+#define GEN_STUXF(width, opc, type)                                           \
+GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, type)                 \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
-        RET_INVAL(ctx);                                                       \
+    if (unlikely(rA(ctx->opcode) == 0)) {                                     \
+        GEN_EXCP_INVAL(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    gen_op_load_gpr_T0(rA(ctx->opcode));                                      \
-    gen_op_load_gpr_T1(rB(ctx->opcode));                                      \
-    gen_op_add();                                                             \
-    gen_op_load_fpr_FT1(rS(ctx->opcode));                                     \
+    gen_addr_reg_index(ctx);                                                  \
+    gen_op_load_fpr_FT0(rS(ctx->opcode));                                     \
     op_ldst(st##width);                                                       \
     gen_op_store_T0_gpr(rA(ctx->opcode));                                     \
 }
 
-#define GEN_STXF(width, opc2, opc3)                                           \
-GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT)            \
+#define GEN_STXF(width, opc2, opc3, type)                                     \
+GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, type)                 \
 {                                                                             \
-    if (!ctx->fpu_enabled) {                                                  \
-        RET_EXCP(ctx, EXCP_NO_FP, 0);                                         \
+    if (unlikely(!ctx->fpu_enabled)) {                                        \
+        GEN_EXCP_NO_FP(ctx);                                                  \
         return;                                                               \
     }                                                                         \
-    if (rA(ctx->opcode) == 0) {                                               \
-        gen_op_load_gpr_T0(rB(ctx->opcode));                                  \
-    } else {                                                                  \
-        gen_op_load_gpr_T0(rA(ctx->opcode));                                  \
-        gen_op_load_gpr_T1(rB(ctx->opcode));                                  \
-        gen_op_add();                                                         \
-    }                                                                         \
-    gen_op_load_fpr_FT1(rS(ctx->opcode));                                     \
+    gen_addr_reg_index(ctx);                                                  \
+    gen_op_load_fpr_FT0(rS(ctx->opcode));                                     \
     op_ldst(st##width);                                                       \
 }
 
-#define GEN_STFS(width, op)                                                   \
+#define GEN_STFS(width, op, type)                                             \
 OP_ST_TABLE(width);                                                           \
-GEN_STF(width, op | 0x20);                                                    \
-GEN_STUF(width, op | 0x21);                                                   \
-GEN_STUXF(width, op | 0x01);                                                  \
-GEN_STXF(width, 0x17, op | 0x00)
+GEN_STF(width, op | 0x20, type);                                              \
+GEN_STUF(width, op | 0x21, type);                                             \
+GEN_STUXF(width, op | 0x01, type);                                            \
+GEN_STXF(width, 0x17, op | 0x00, type)
 
 /* stfd stfdu stfdux stfdx */
-GEN_STFS(fd, 0x16);
+GEN_STFS(fd, 0x16, PPC_FLOAT);
 /* stfs stfsu stfsux stfsx */
-GEN_STFS(fs, 0x14);
+GEN_STFS(fs, 0x14, PPC_FLOAT);
 
 /* Optional: */
 /* stfiwx */
-GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
-{
-    if (!ctx->fpu_enabled) {
-        RET_EXCP(ctx, EXCP_NO_FP, 0);
-        return;
-    }
-    RET_INVAL(ctx);
-}
+OP_ST_TABLE(fiwx);
+GEN_STXF(fiwx, 0x17, 0x1E, PPC_FLOAT_STFIWX);
 
 /***                                Branch                                 ***/
-
-static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
+static inline void gen_goto_tb (DisasContext *ctx, int n, target_ulong dest)
 {
     TranslationBlock *tb;
     tb = ctx->tb;
@@ -1736,63 +2881,94 @@
             gen_op_goto_tb0(TBPARAM(tb));
         else
             gen_op_goto_tb1(TBPARAM(tb));
-        gen_op_set_T1(dest);
-        gen_op_b_T1();
+        gen_set_T1(dest);
+#if defined(TARGET_PPC64)
+        if (ctx->sf_mode)
+            gen_op_b_T1_64();
+        else
+#endif
+            gen_op_b_T1();
         gen_op_set_T0((long)tb + n);
         if (ctx->singlestep_enabled)
             gen_op_debug();
         gen_op_exit_tb();
     } else {
-        gen_op_set_T1(dest);
-        gen_op_b_T1();
+        gen_set_T1(dest);
+#if defined(TARGET_PPC64)
+        if (ctx->sf_mode)
+            gen_op_b_T1_64();
+        else
+#endif
+            gen_op_b_T1();
+        gen_op_reset_T0();
         if (ctx->singlestep_enabled)
             gen_op_debug();
-        gen_op_set_T0(0);
         gen_op_exit_tb();
     }
 }
 
+static inline void gen_setlr (DisasContext *ctx, target_ulong nip)
+{
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode != 0 && (nip >> 32))
+        gen_op_setlr_64(ctx->nip >> 32, ctx->nip);
+    else
+#endif
+        gen_op_setlr(ctx->nip);
+}
+
 /* b ba bl bla */
 GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
-    uint32_t li, target;
+    target_ulong li, target;
 
     /* sign extend LI */
-    li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
-
-    if (AA(ctx->opcode) == 0)
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
+    else
+#endif
+        li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
+    if (likely(AA(ctx->opcode) == 0))
         target = ctx->nip + li - 4;
     else
         target = li;
-    if (LK(ctx->opcode)) {
-        gen_op_setlr(ctx->nip);
-    }
+#if defined(TARGET_PPC64)
+    if (!ctx->sf_mode)
+        target = (uint32_t)target;
+#endif
+    if (LK(ctx->opcode))
+        gen_setlr(ctx, ctx->nip);
     gen_goto_tb(ctx, 0, target);
-    ctx->exception = EXCP_BRANCH;
+    ctx->exception = POWERPC_EXCP_BRANCH;
 }
 
 #define BCOND_IM  0
 #define BCOND_LR  1
 #define BCOND_CTR 2
 
-static inline void gen_bcond(DisasContext *ctx, int type) 
-{                                                                             
-    uint32_t target = 0;
-    uint32_t bo = BO(ctx->opcode);                                            
-    uint32_t bi = BI(ctx->opcode);                                            
-    uint32_t mask;                                                            
-    uint32_t li;
+static inline void gen_bcond (DisasContext *ctx, int type)
+{
+    target_ulong target = 0;
+    target_ulong li;
+    uint32_t bo = BO(ctx->opcode);
+    uint32_t bi = BI(ctx->opcode);
+    uint32_t mask;
 
     if ((bo & 0x4) == 0)
-        gen_op_dec_ctr();                                                     
+        gen_op_dec_ctr();
     switch(type) {
     case BCOND_IM:
-        li = (int32_t)((int16_t)(BD(ctx->opcode)));
-        if (AA(ctx->opcode) == 0) {
+        li = (target_long)((int16_t)(BD(ctx->opcode)));
+        if (likely(AA(ctx->opcode) == 0)) {
             target = ctx->nip + li - 4;
         } else {
             target = li;
         }
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode)
+            target = (uint32_t)target;
+#endif
         break;
     case BCOND_CTR:
         gen_op_movl_T1_ctr();
@@ -1802,61 +2978,98 @@
         gen_op_movl_T1_lr();
         break;
     }
-    if (LK(ctx->opcode)) {                                        
-        gen_op_setlr(ctx->nip);
-    }
+    if (LK(ctx->opcode))
+        gen_setlr(ctx, ctx->nip);
     if (bo & 0x10) {
-        /* No CR condition */                                                 
-        switch (bo & 0x6) {                                                   
-        case 0:                                                               
-            gen_op_test_ctr();
+        /* No CR condition */
+        switch (bo & 0x6) {
+        case 0:
+#if defined(TARGET_PPC64)
+            if (ctx->sf_mode)
+                gen_op_test_ctr_64();
+            else
+#endif
+                gen_op_test_ctr();
             break;
-        case 2:                                                               
-            gen_op_test_ctrz();
-            break;                                                            
+        case 2:
+#if defined(TARGET_PPC64)
+            if (ctx->sf_mode)
+                gen_op_test_ctrz_64();
+            else
+#endif
+                gen_op_test_ctrz();
+            break;
         default:
-        case 4:                                                               
-        case 6:                                                               
+        case 4:
+        case 6:
             if (type == BCOND_IM) {
                 gen_goto_tb(ctx, 0, target);
+                goto out;
             } else {
-                gen_op_b_T1();
+#if defined(TARGET_PPC64)
+                if (ctx->sf_mode)
+                    gen_op_b_T1_64();
+                else
+#endif
+                    gen_op_b_T1();
+                gen_op_reset_T0();
+                goto no_test;
             }
-            goto no_test;
+            break;
         }
-    } else {                                                                  
-        mask = 1 << (3 - (bi & 0x03));                                        
-        gen_op_load_crf_T0(bi >> 2);                                          
-        if (bo & 0x8) {                                                       
-            switch (bo & 0x6) {                                               
-            case 0:                                                           
-                gen_op_test_ctr_true(mask);
-                break;                                                        
-            case 2:                                                           
-                gen_op_test_ctrz_true(mask);
-                break;                                                        
-            default:                                                          
-            case 4:                                                           
-            case 6:                                                           
-                gen_op_test_true(mask);
-                break;                                                        
-            }                                                                 
-        } else {                                                              
-            switch (bo & 0x6) {                                               
-            case 0:                                                           
-                gen_op_test_ctr_false(mask);
-                break;                                                        
-            case 2:                                                           
-                gen_op_test_ctrz_false(mask);
-                break;                                                        
+    } else {
+        mask = 1 << (3 - (bi & 0x03));
+        gen_op_load_crf_T0(bi >> 2);
+        if (bo & 0x8) {
+            switch (bo & 0x6) {
+            case 0:
+#if defined(TARGET_PPC64)
+                if (ctx->sf_mode)
+                    gen_op_test_ctr_true_64(mask);
+                else
+#endif
+                    gen_op_test_ctr_true(mask);
+                break;
+            case 2:
+#if defined(TARGET_PPC64)
+                if (ctx->sf_mode)
+                    gen_op_test_ctrz_true_64(mask);
+                else
+#endif
+                    gen_op_test_ctrz_true(mask);
+                break;
             default:
-            case 4:                                                           
-            case 6:                                                           
+            case 4:
+            case 6:
+                gen_op_test_true(mask);
+                break;
+            }
+        } else {
+            switch (bo & 0x6) {
+            case 0:
+#if defined(TARGET_PPC64)
+                if (ctx->sf_mode)
+                    gen_op_test_ctr_false_64(mask);
+                else
+#endif
+                    gen_op_test_ctr_false(mask);
+                break;
+            case 2:
+#if defined(TARGET_PPC64)
+                if (ctx->sf_mode)
+                    gen_op_test_ctrz_false_64(mask);
+                else
+#endif
+                    gen_op_test_ctrz_false(mask);
+                break;
+            default:
+            case 4:
+            case 6:
                 gen_op_test_false(mask);
-                break;                                                        
-            }                                                                 
-        }                                                                     
-    }                                                                         
+                break;
+            }
+        }
+    }
     if (type == BCOND_IM) {
         int l1 = gen_new_label();
         gen_op_jz_T0(l1);
@@ -1864,24 +3077,34 @@
         gen_set_label(l1);
         gen_goto_tb(ctx, 1, ctx->nip);
     } else {
-        gen_op_btest_T1(ctx->nip);
+#if defined(TARGET_PPC64)
+        if (ctx->sf_mode)
+            gen_op_btest_T1_64(ctx->nip >> 32, ctx->nip);
+        else
+#endif
+            gen_op_btest_T1(ctx->nip);
+        gen_op_reset_T0();
+    no_test:
+        if (ctx->singlestep_enabled)
+            gen_op_debug();
+        gen_op_exit_tb();
     }
- no_test:
-    ctx->exception = EXCP_BRANCH;                                             
+ out:
+    ctx->exception = POWERPC_EXCP_BRANCH;
 }
 
 GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
-{                                                                             
+{
     gen_bcond(ctx, BCOND_IM);
 }
 
 GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
-{                                                                             
+{
     gen_bcond(ctx, BCOND_CTR);
 }
 
 GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
-{                                                                             
+{
     gen_bcond(ctx, BCOND_LR);
 }
 
@@ -1901,21 +3124,21 @@
 }
 
 /* crand */
-GEN_CRLOGIC(and, 0x08)
+GEN_CRLOGIC(and, 0x08);
 /* crandc */
-GEN_CRLOGIC(andc, 0x04)
+GEN_CRLOGIC(andc, 0x04);
 /* creqv */
-GEN_CRLOGIC(eqv, 0x09)
+GEN_CRLOGIC(eqv, 0x09);
 /* crnand */
-GEN_CRLOGIC(nand, 0x07)
+GEN_CRLOGIC(nand, 0x07);
 /* crnor */
-GEN_CRLOGIC(nor, 0x01)
+GEN_CRLOGIC(nor, 0x01);
 /* cror */
-GEN_CRLOGIC(or, 0x0E)
+GEN_CRLOGIC(or, 0x0E);
 /* crorc */
-GEN_CRLOGIC(orc, 0x0D)
+GEN_CRLOGIC(orc, 0x0D);
 /* crxor */
-GEN_CRLOGIC(xor, 0x06)
+GEN_CRLOGIC(xor, 0x06);
 /* mcrf */
 GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
 {
@@ -1925,39 +3148,76 @@
 
 /***                           System linkage                              ***/
 /* rfi (supervisor only) */
-GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
+GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC(ctx);
+    GEN_EXCP_PRIVOPC(ctx);
 #else
     /* Restore CPU state */
-    if (!ctx->supervisor) {
-        RET_PRIVOPC(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
         return;
     }
     gen_op_rfi();
-    RET_CHG_FLOW(ctx);
+    GEN_SYNC(ctx);
 #endif
 }
 
-/* sc */
-GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
+#if defined(TARGET_PPC64)
+GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_64B)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
+    GEN_EXCP_PRIVOPC(ctx);
 #else
-    RET_EXCP(ctx, EXCP_SYSCALL, 0);
+    /* Restore CPU state */
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_rfid();
+    GEN_SYNC(ctx);
+#endif
+}
+#endif
+
+#if defined(TARGET_PPC64H)
+GEN_HANDLER(hrfid, 0x13, 0x12, 0x08, 0x03FF8001, PPC_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    /* Restore CPU state */
+    if (unlikely(ctx->supervisor <= 1)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_hrfid();
+    GEN_SYNC(ctx);
+#endif
+}
+#endif
+
+/* sc */
+GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFF01D, PPC_FLOW)
+{
+    uint32_t lev;
+
+    lev = (ctx->opcode >> 5) & 0x7F;
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP(ctx, POWERPC_EXCP_SYSCALL_USER, lev);
+#else
+    GEN_EXCP(ctx, POWERPC_EXCP_SYSCALL, lev);
 #endif
 }
 
 /***                                Trap                                   ***/
 /* tw */
-GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
+GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
 {
     gen_op_load_gpr_T0(rA(ctx->opcode));
     gen_op_load_gpr_T1(rB(ctx->opcode));
     /* Update the nip since this might generate a trap exception */
-    gen_op_update_nip(ctx->nip);
+    gen_update_nip(ctx, ctx->nip);
     gen_op_tw(TO(ctx->opcode));
 }
 
@@ -1965,51 +3225,58 @@
 GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
 {
     gen_op_load_gpr_T0(rA(ctx->opcode));
-#if 0
-    printf("%s: param=0x%04x T0=0x%04x\n", __func__,
-           SIMM(ctx->opcode), TO(ctx->opcode));
-#endif
-    gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode));
+    gen_set_T1(SIMM(ctx->opcode));
+    /* Update the nip since this might generate a trap exception */
+    gen_update_nip(ctx, ctx->nip);
+    gen_op_tw(TO(ctx->opcode));
 }
 
+#if defined(TARGET_PPC64)
+/* td */
+GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    /* Update the nip since this might generate a trap exception */
+    gen_update_nip(ctx, ctx->nip);
+    gen_op_td(TO(ctx->opcode));
+}
+
+/* tdi */
+GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_set_T1(SIMM(ctx->opcode));
+    /* Update the nip since this might generate a trap exception */
+    gen_update_nip(ctx, ctx->nip);
+    gen_op_td(TO(ctx->opcode));
+}
+#endif
+
 /***                          Processor control                            ***/
-static inline int check_spr_access (int spr, int rw, int supervisor)
-{
-    uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
-
-#if 0
-    if (spr != LR && spr != CTR) {
-    if (loglevel > 0) {
-        fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
-                SPR_ENCODE(spr), supervisor, rw, rights,
-                (rights >> ((2 * supervisor) + rw)) & 1);
-    } else {
-        printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
-               SPR_ENCODE(spr), supervisor, rw, rights,
-               (rights >> ((2 * supervisor) + rw)) & 1);
-    }
-    }
-#endif
-    if (rights == 0)
-        return -1;
-    rights = rights >> (2 * supervisor);
-    rights = rights >> rw;
-
-    return rights & 1;
-}
-
 /* mcrxr */
 GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
 {
     gen_op_load_xer_cr();
     gen_op_store_T0_crf(crfD(ctx->opcode));
-    gen_op_clear_xer_cr();
+    gen_op_clear_xer_ov();
+    gen_op_clear_xer_ca();
 }
 
 /* mfcr */
-GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
+GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
 {
-    gen_op_load_cr();
+    uint32_t crm, crn;
+
+    if (likely(ctx->opcode & 0x00100000)) {
+        crm = CRM(ctx->opcode);
+        if (likely((crm ^ (crm - 1)) == 0)) {
+            crn = ffs(crm);
+            gen_op_load_cro(7 - crn);
+        }
+    } else {
+        gen_op_load_cr();
+    }
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
 
@@ -2017,10 +3284,10 @@
 GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG(ctx);
+    GEN_EXCP_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVREG(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
         return;
     }
     gen_op_load_msr();
@@ -2046,69 +3313,128 @@
     uint32_t sprn = SPR(ctx->opcode);
 
 #if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64H)
+    if (ctx->supervisor == 2)
+        read_cb = ctx->spr_cb[sprn].hea_read;
+    else
+#endif
     if (ctx->supervisor)
         read_cb = ctx->spr_cb[sprn].oea_read;
     else
 #endif
         read_cb = ctx->spr_cb[sprn].uea_read;
-    if (read_cb != NULL) {
-        if (read_cb != SPR_NOACCESS) {
+    if (likely(read_cb != NULL)) {
+        if (likely(read_cb != SPR_NOACCESS)) {
             (*read_cb)(ctx, sprn);
             gen_op_store_T0_gpr(rD(ctx->opcode));
         } else {
             /* Privilege exception */
-            if (loglevel) {
-                fprintf(logfile, "Trying to read priviledged spr %d %03x\n",
+            if (loglevel != 0) {
+                fprintf(logfile, "Trying to read privileged spr %d %03x\n",
                         sprn, sprn);
             }
-            printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
-        RET_PRIVREG(ctx);
+            printf("Trying to read privileged spr %d %03x\n", sprn, sprn);
+            GEN_EXCP_PRIVREG(ctx);
         }
     } else {
         /* Not defined */
-        if (loglevel) {
+        if (loglevel != 0) {
             fprintf(logfile, "Trying to read invalid spr %d %03x\n",
                     sprn, sprn);
         }
         printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
-        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
+        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
+                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
     }
 }
 
 GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
 {
     gen_op_mfspr(ctx);
-    }
+}
 
 /* mftb */
-GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
+GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MFTB)
 {
     gen_op_mfspr(ctx);
 }
 
 /* mtcrf */
-/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */
 GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
 {
+    uint32_t crm, crn;
+
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_store_cr(CRM(ctx->opcode));
+    crm = CRM(ctx->opcode);
+    if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
+        crn = ffs(crm);
+        gen_op_srli_T0(crn * 4);
+        gen_op_andi_T0(0xF);
+        gen_op_store_cro(7 - crn);
+    } else {
+        gen_op_store_cr(crm);
+    }
 }
 
 /* mtmsr */
+#if defined(TARGET_PPC64)
+GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001EF801, PPC_64B)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    if (ctx->opcode & 0x00010000) {
+        /* Special form that does not need any synchronisation */
+        gen_op_update_riee();
+    } else {
+        /* XXX: we need to update nip before the store
+         *      if we enter power saving mode, we will exit the loop
+         *      directly from ppc_store_msr
+         */
+        gen_update_nip(ctx, ctx->nip);
+        gen_op_store_msr();
+        /* Must stop the translation as machine state (may have) changed */
+        /* Note that mtmsr is not always defined as context-synchronizing */
+        ctx->exception = POWERPC_EXCP_STOP;
+    }
+#endif
+}
+#endif
+
 GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG(ctx);
+    GEN_EXCP_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVREG(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
         return;
     }
-    gen_op_update_nip((ctx)->nip);
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_store_msr();
-    /* Must stop the translation as machine state (may have) changed */
-    RET_CHG_FLOW(ctx);
+    if (ctx->opcode & 0x00010000) {
+        /* Special form that does not need any synchronisation */
+        gen_op_update_riee();
+    } else {
+        /* XXX: we need to update nip before the store
+         *      if we enter power saving mode, we will exit the loop
+         *      directly from ppc_store_msr
+         */
+        gen_update_nip(ctx, ctx->nip);
+#if defined(TARGET_PPC64)
+        if (!ctx->sf_mode)
+            gen_op_store_msr_32();
+        else
+#endif
+            gen_op_store_msr();
+        /* Must stop the translation as machine state (may have) changed */
+        /* Note that mtmsrd is not always defined as context-synchronizing */
+        ctx->exception = POWERPC_EXCP_STOP;
+    }
 #endif
 }
 
@@ -2119,32 +3445,38 @@
     uint32_t sprn = SPR(ctx->opcode);
 
 #if !defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64H)
+    if (ctx->supervisor == 2)
+        write_cb = ctx->spr_cb[sprn].hea_write;
+    else
+#endif
     if (ctx->supervisor)
         write_cb = ctx->spr_cb[sprn].oea_write;
     else
 #endif
         write_cb = ctx->spr_cb[sprn].uea_write;
-    if (write_cb != NULL) {
-        if (write_cb != SPR_NOACCESS) {
+    if (likely(write_cb != NULL)) {
+        if (likely(write_cb != SPR_NOACCESS)) {
             gen_op_load_gpr_T0(rS(ctx->opcode));
             (*write_cb)(ctx, sprn);
         } else {
             /* Privilege exception */
-            if (loglevel) {
-                fprintf(logfile, "Trying to write priviledged spr %d %03x\n",
+            if (loglevel != 0) {
+                fprintf(logfile, "Trying to write privileged spr %d %03x\n",
                         sprn, sprn);
             }
-            printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
-        RET_PRIVREG(ctx);
-    }
+            printf("Trying to write privileged spr %d %03x\n", sprn, sprn);
+            GEN_EXCP_PRIVREG(ctx);
+        }
     } else {
         /* Not defined */
-        if (loglevel) {
+        if (loglevel != 0) {
             fprintf(logfile, "Trying to write invalid spr %d %03x\n",
                     sprn, sprn);
         }
         printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
-        RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
+        GEN_EXCP(ctx, POWERPC_EXCP_PROGRAM,
+                 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_SPR);
     }
 }
 
@@ -2154,15 +3486,9 @@
  * We just have to flush tb while invalidating instruction cache lines...
  */
 /* dcbf */
-GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
+GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03C00001, PPC_CACHE)
 {
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
+    gen_addr_reg_index(ctx);
     op_ldst(lbz);
 }
 
@@ -2170,20 +3496,15 @@
 GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC(ctx);
+    GEN_EXCP_PRIVOPC(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVOPC(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
         return;
     }
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
-    op_ldst(lbz);
+    gen_addr_reg_index(ctx);
+    /* XXX: specification says this should be treated as a store by the MMU */
+    //op_ldst(lbz);
     op_ldst(stb);
 #endif
 }
@@ -2191,31 +3512,58 @@
 /* dcdst */
 GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
 {
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
+    /* XXX: specification say this is treated as a load by the MMU */
+    gen_addr_reg_index(ctx);
     op_ldst(lbz);
 }
 
 /* dcbt */
-GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
+GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x02000001, PPC_CACHE)
 {
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
 }
 
 /* dcbtst */
-GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
+GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x02000001, PPC_CACHE)
 {
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
 }
 
 /* dcbz */
-#if defined(CONFIG_USER_ONLY)
-#define op_dcbz() gen_op_dcbz_raw()
-#else
 #define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_dcbz[] = {
+    &gen_op_dcbz_raw,
+    &gen_op_dcbz_raw,
+    &gen_op_dcbz_64_raw,
+    &gen_op_dcbz_64_raw,
+};
+#else
+static GenOpFunc *gen_op_dcbz[] = {
+    &gen_op_dcbz_user,
+    &gen_op_dcbz_user,
+    &gen_op_dcbz_kernel,
+    &gen_op_dcbz_kernel,
+    &gen_op_dcbz_64_user,
+    &gen_op_dcbz_64_user,
+    &gen_op_dcbz_64_kernel,
+    &gen_op_dcbz_64_kernel,
+};
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_dcbz[] = {
+    &gen_op_dcbz_raw,
+    &gen_op_dcbz_raw,
+};
+#else
 static GenOpFunc *gen_op_dcbz[] = {
     &gen_op_dcbz_user,
     &gen_op_dcbz_user,
@@ -2223,37 +3571,69 @@
     &gen_op_dcbz_kernel,
 };
 #endif
+#endif
 
 GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
 {
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
+    gen_addr_reg_index(ctx);
     op_dcbz();
     gen_op_check_reservation();
 }
 
 /* icbi */
+#define op_icbi() (*gen_op_icbi[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_icbi[] = {
+    &gen_op_icbi_raw,
+    &gen_op_icbi_raw,
+    &gen_op_icbi_64_raw,
+    &gen_op_icbi_64_raw,
+};
+#else
+static GenOpFunc *gen_op_icbi[] = {
+    &gen_op_icbi_user,
+    &gen_op_icbi_user,
+    &gen_op_icbi_kernel,
+    &gen_op_icbi_kernel,
+    &gen_op_icbi_64_user,
+    &gen_op_icbi_64_user,
+    &gen_op_icbi_64_kernel,
+    &gen_op_icbi_64_kernel,
+};
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_icbi[] = {
+    &gen_op_icbi_raw,
+    &gen_op_icbi_raw,
+};
+#else
+static GenOpFunc *gen_op_icbi[] = {
+    &gen_op_icbi_user,
+    &gen_op_icbi_user,
+    &gen_op_icbi_kernel,
+    &gen_op_icbi_kernel,
+};
+#endif
+#endif
+
 GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
 {
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
-    gen_op_icbi();
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    op_icbi();
 }
 
 /* Optional: */
 /* dcba */
-GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT)
+GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_DCBA)
 {
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a store by the MMU
+     *      but does not generate any exception
+     */
 }
 
 /***                    Segment register manipulation                      ***/
@@ -2262,13 +3642,14 @@
 GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG(ctx);
+    GEN_EXCP_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVREG(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
         return;
     }
-    gen_op_load_sr(SR(ctx->opcode));
+    gen_op_set_T1(SR(ctx->opcode));
+    gen_op_load_sr();
     gen_op_store_T0_gpr(rD(ctx->opcode));
 #endif
 }
@@ -2277,14 +3658,15 @@
 GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG(ctx);
+    GEN_EXCP_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVREG(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
         return;
     }
     gen_op_load_gpr_T1(rB(ctx->opcode));
-    gen_op_load_srin();
+    gen_op_srli_T1(28);
+    gen_op_load_sr();
     gen_op_store_T0_gpr(rD(ctx->opcode));
 #endif
 }
@@ -2293,15 +3675,15 @@
 GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG(ctx);
+    GEN_EXCP_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVREG(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
         return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
-    gen_op_store_sr(SR(ctx->opcode));
-    RET_STOP(ctx);
+    gen_op_set_T1(SR(ctx->opcode));
+    gen_op_store_sr();
 #endif
 }
 
@@ -2309,16 +3691,16 @@
 GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVREG(ctx);
+    GEN_EXCP_PRIVREG(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVREG(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
         return;
     }
     gen_op_load_gpr_T0(rS(ctx->opcode));
     gen_op_load_gpr_T1(rB(ctx->opcode));
-    gen_op_store_srin();
-    RET_STOP(ctx);
+    gen_op_srli_T1(28);
+    gen_op_store_sr();
 #endif
 }
 
@@ -2328,56 +3710,129 @@
 GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC(ctx);
+    GEN_EXCP_PRIVOPC(ctx);
 #else
-    if (!ctx->supervisor) {
-        if (loglevel)
+    if (unlikely(!ctx->supervisor)) {
+        if (loglevel != 0)
             fprintf(logfile, "%s: ! supervisor\n", __func__);
-        RET_PRIVOPC(ctx);
+        GEN_EXCP_PRIVOPC(ctx);
         return;
     }
     gen_op_tlbia();
-    RET_STOP(ctx);
 #endif
 }
 
 /* tlbie */
-GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
+GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC(ctx);
+    GEN_EXCP_PRIVOPC(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVOPC(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
         return;
     }
     gen_op_load_gpr_T0(rB(ctx->opcode));
-    gen_op_tlbie();
-    RET_STOP(ctx);
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        gen_op_tlbie_64();
+    else
+#endif
+        gen_op_tlbie();
 #endif
 }
 
 /* tlbsync */
-GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
+GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
 {
 #if defined(CONFIG_USER_ONLY)
-    RET_PRIVOPC(ctx);
+    GEN_EXCP_PRIVOPC(ctx);
 #else
-    if (!ctx->supervisor) {
-        RET_PRIVOPC(ctx);
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
         return;
     }
     /* This has no effect: it should ensure that all previous
      * tlbie have completed
      */
-    RET_STOP(ctx);
+    GEN_STOP(ctx);
 #endif
 }
 
+#if defined(TARGET_PPC64)
+/* slbia */
+GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        if (loglevel != 0)
+            fprintf(logfile, "%s: ! supervisor\n", __func__);
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_slbia();
+#endif
+}
+
+/* slbie */
+GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rB(ctx->opcode));
+    gen_op_slbie();
+#endif
+}
+#endif
+
 /***                              External control                         ***/
 /* Optional: */
 #define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
 #define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_eciwx[] = {
+    &gen_op_eciwx_raw,
+    &gen_op_eciwx_le_raw,
+    &gen_op_eciwx_64_raw,
+    &gen_op_eciwx_le_64_raw,
+};
+static GenOpFunc *gen_op_ecowx[] = {
+    &gen_op_ecowx_raw,
+    &gen_op_ecowx_le_raw,
+    &gen_op_ecowx_64_raw,
+    &gen_op_ecowx_le_64_raw,
+};
+#else
+static GenOpFunc *gen_op_eciwx[] = {
+    &gen_op_eciwx_user,
+    &gen_op_eciwx_le_user,
+    &gen_op_eciwx_kernel,
+    &gen_op_eciwx_le_kernel,
+    &gen_op_eciwx_64_user,
+    &gen_op_eciwx_le_64_user,
+    &gen_op_eciwx_64_kernel,
+    &gen_op_eciwx_le_64_kernel,
+};
+static GenOpFunc *gen_op_ecowx[] = {
+    &gen_op_ecowx_user,
+    &gen_op_ecowx_le_user,
+    &gen_op_ecowx_kernel,
+    &gen_op_ecowx_le_kernel,
+    &gen_op_ecowx_64_user,
+    &gen_op_ecowx_le_64_user,
+    &gen_op_ecowx_64_kernel,
+    &gen_op_ecowx_le_64_kernel,
+};
+#endif
+#else
 #if defined(CONFIG_USER_ONLY)
 static GenOpFunc *gen_op_eciwx[] = {
     &gen_op_eciwx_raw,
@@ -2401,18 +3856,13 @@
     &gen_op_ecowx_le_kernel,
 };
 #endif
+#endif
 
 /* eciwx */
 GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
 {
     /* Should check EAR[E] & alignment ! */
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
+    gen_addr_reg_index(ctx);
     op_eciwx();
     gen_op_store_T0_gpr(rD(ctx->opcode));
 }
@@ -2421,17 +3871,2164 @@
 GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
 {
     /* Should check EAR[E] & alignment ! */
-    if (rA(ctx->opcode) == 0) {
-        gen_op_load_gpr_T0(rB(ctx->opcode));
-    } else {
-        gen_op_load_gpr_T0(rA(ctx->opcode));
-        gen_op_load_gpr_T1(rB(ctx->opcode));
-        gen_op_add();
-    }
-    gen_op_load_gpr_T2(rS(ctx->opcode));
+    gen_addr_reg_index(ctx);
+    gen_op_load_gpr_T1(rS(ctx->opcode));
     op_ecowx();
 }
 
+/* PowerPC 601 specific instructions */
+/* abs - abs. */
+GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_abs();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* abso - abso. */
+GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_abso();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* clcs */
+GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_clcs();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* div - div. */
+GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_div();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* divo - divo. */
+GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_divo();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* divs - divs. */
+GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_divs();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* divso - divso. */
+GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_divso();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* doz - doz. */
+GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_doz();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* dozo - dozo. */
+GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_dozo();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* dozi */
+GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_set_T1(SIMM(ctx->opcode));
+    gen_op_POWER_doz();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* As lscbx load from memory byte after byte, it's always endian safe */
+#define op_POWER_lscbx(start, ra, rb) \
+(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc3 *gen_op_POWER_lscbx[] = {
+    &gen_op_POWER_lscbx_raw,
+    &gen_op_POWER_lscbx_raw,
+};
+#else
+static GenOpFunc3 *gen_op_POWER_lscbx[] = {
+    &gen_op_POWER_lscbx_user,
+    &gen_op_POWER_lscbx_user,
+    &gen_op_POWER_lscbx_kernel,
+    &gen_op_POWER_lscbx_kernel,
+};
+#endif
+
+/* lscbx - lscbx. */
+GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
+{
+    int ra = rA(ctx->opcode);
+    int rb = rB(ctx->opcode);
+
+    gen_addr_reg_index(ctx);
+    if (ra == 0) {
+        ra = rb;
+    }
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_op_load_xer_bc();
+    gen_op_load_xer_cmp();
+    op_POWER_lscbx(rD(ctx->opcode), ra, rb);
+    gen_op_store_xer_bc();
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* maskg - maskg. */
+GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_maskg();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* maskir - maskir. */
+GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rS(ctx->opcode));
+    gen_op_load_gpr_T2(rB(ctx->opcode));
+    gen_op_POWER_maskir();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* mul - mul. */
+GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_mul();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* mulo - mulo. */
+GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_mulo();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* nabs - nabs. */
+GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_nabs();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* nabso - nabso. */
+GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_POWER_nabso();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* rlmi - rlmi. */
+GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
+{
+    uint32_t mb, me;
+
+    mb = MB(ctx->opcode);
+    me = ME(ctx->opcode);
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rA(ctx->opcode));
+    gen_op_load_gpr_T2(rB(ctx->opcode));
+    gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me));
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* rrib - rrib. */
+GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rA(ctx->opcode));
+    gen_op_load_gpr_T2(rB(ctx->opcode));
+    gen_op_POWER_rrib();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sle - sle. */
+GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sle();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sleq - sleq. */
+GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sleq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sliq - sliq. */
+GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_sle();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* slliq - slliq. */
+GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_sleq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sllq - sllq. */
+GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sllq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* slq - slq. */
+GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_slq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sraiq - sraiq. */
+GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_sraq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sraq - sraq. */
+GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sraq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sre - sre. */
+GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sre();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* srea - srea. */
+GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_srea();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sreq */
+GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_sreq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* sriq */
+GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_srq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* srliq */
+GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_set_T1(SH(ctx->opcode));
+    gen_op_POWER_srlq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* srlq */
+GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_srlq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* srq */
+GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_POWER_srq();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    if (unlikely(Rc(ctx->opcode) != 0))
+        gen_set_Rc0(ctx);
+}
+
+/* PowerPC 602 specific instructions */
+/* dsa  */
+GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
+{
+    /* XXX: TODO */
+    GEN_EXCP_INVAL(ctx);
+}
+
+/* esa */
+GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
+{
+    /* XXX: TODO */
+    GEN_EXCP_INVAL(ctx);
+}
+
+/* mfrom */
+GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_602_mfrom();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* 602 - 603 - G2 TLB management */
+/* tlbld */
+GEN_HANDLER(tlbld_6xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rB(ctx->opcode));
+    gen_op_6xx_tlbld();
+#endif
+}
+
+/* tlbli */
+GEN_HANDLER(tlbli_6xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rB(ctx->opcode));
+    gen_op_6xx_tlbli();
+#endif
+}
+
+/* 74xx TLB management */
+/* tlbld */
+GEN_HANDLER(tlbld_74xx, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_74xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rB(ctx->opcode));
+    gen_op_74xx_tlbld();
+#endif
+}
+
+/* tlbli */
+GEN_HANDLER(tlbli_74xx, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_74xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rB(ctx->opcode));
+    gen_op_74xx_tlbli();
+#endif
+}
+
+/* POWER instructions not in PowerPC 601 */
+/* clf */
+GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)
+{
+    /* Cache line flush: implemented as no-op */
+}
+
+/* cli */
+GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER)
+{
+    /* Cache line invalidate: privileged and treated as no-op */
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+#endif
+}
+
+/* dclst */
+GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER)
+{
+    /* Data cache line store: treated as no-op */
+}
+
+GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    int ra = rA(ctx->opcode);
+    int rd = rD(ctx->opcode);
+
+    gen_addr_reg_index(ctx);
+    gen_op_POWER_mfsri();
+    gen_op_store_T0_gpr(rd);
+    if (ra != 0 && ra != rd)
+        gen_op_store_T1_gpr(ra);
+#endif
+}
+
+GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    gen_op_POWER_rac();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_POWER_rfsvc();
+    GEN_SYNC(ctx);
+#endif
+}
+
+/* svc is not implemented for now */
+
+/* POWER2 specific instructions */
+/* Quad manipulation (load/store two floats at a time) */
+#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])()
+#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_POWER2_lfq[] = {
+    &gen_op_POWER2_lfq_le_raw,
+    &gen_op_POWER2_lfq_raw,
+};
+static GenOpFunc *gen_op_POWER2_stfq[] = {
+    &gen_op_POWER2_stfq_le_raw,
+    &gen_op_POWER2_stfq_raw,
+};
+#else
+static GenOpFunc *gen_op_POWER2_lfq[] = {
+    &gen_op_POWER2_lfq_le_user,
+    &gen_op_POWER2_lfq_user,
+    &gen_op_POWER2_lfq_le_kernel,
+    &gen_op_POWER2_lfq_kernel,
+};
+static GenOpFunc *gen_op_POWER2_stfq[] = {
+    &gen_op_POWER2_stfq_le_user,
+    &gen_op_POWER2_stfq_user,
+    &gen_op_POWER2_stfq_le_kernel,
+    &gen_op_POWER2_stfq_kernel,
+};
+#endif
+
+/* lfq */
+GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_imm_index(ctx, 0);
+    op_POWER2_lfq();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+}
+
+/* lfqu */
+GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+    int ra = rA(ctx->opcode);
+
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_imm_index(ctx, 0);
+    op_POWER2_lfq();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+    if (ra != 0)
+        gen_op_store_T0_gpr(ra);
+}
+
+/* lfqux */
+GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
+{
+    int ra = rA(ctx->opcode);
+
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    op_POWER2_lfq();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+    if (ra != 0)
+        gen_op_store_T0_gpr(ra);
+}
+
+/* lfqx */
+GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    op_POWER2_lfq();
+    gen_op_store_FT0_fpr(rD(ctx->opcode));
+    gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+}
+
+/* stfq */
+GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_imm_index(ctx, 0);
+    gen_op_load_fpr_FT0(rS(ctx->opcode));
+    gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+    op_POWER2_stfq();
+}
+
+/* stfqu */
+GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+    int ra = rA(ctx->opcode);
+
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_imm_index(ctx, 0);
+    gen_op_load_fpr_FT0(rS(ctx->opcode));
+    gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+    op_POWER2_stfq();
+    if (ra != 0)
+        gen_op_store_T0_gpr(ra);
+}
+
+/* stfqux */
+GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
+{
+    int ra = rA(ctx->opcode);
+
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    gen_op_load_fpr_FT0(rS(ctx->opcode));
+    gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+    op_POWER2_stfq();
+    if (ra != 0)
+        gen_op_store_T0_gpr(ra);
+}
+
+/* stfqx */
+GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
+{
+    /* NIP cannot be restored if the memory exception comes from an helper */
+    gen_update_nip(ctx, ctx->nip - 4);
+    gen_addr_reg_index(ctx);
+    gen_op_load_fpr_FT0(rS(ctx->opcode));
+    gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+    op_POWER2_stfq();
+}
+
+/* BookE specific instructions */
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE_EXT)
+{
+    /* XXX: TODO */
+    GEN_EXCP_INVAL(ctx);
+}
+
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE_EXT)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    /* Use the same micro-ops as for tlbie */
+#if defined(TARGET_PPC64)
+    if (ctx->sf_mode)
+        gen_op_tlbie_64();
+    else
+#endif
+        gen_op_tlbie();
+#endif
+}
+
+/* All 405 MAC instructions are translated here */
+static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3,
+                                         int ra, int rb, int rt, int Rc)
+{
+    gen_op_load_gpr_T0(ra);
+    gen_op_load_gpr_T1(rb);
+    switch (opc3 & 0x0D) {
+    case 0x05:
+        /* macchw    - macchw.    - macchwo   - macchwo.   */
+        /* macchws   - macchws.   - macchwso  - macchwso.  */
+        /* nmacchw   - nmacchw.   - nmacchwo  - nmacchwo.  */
+        /* nmacchws  - nmacchws.  - nmacchwso - nmacchwso. */
+        /* mulchw - mulchw. */
+        gen_op_405_mulchw();
+        break;
+    case 0x04:
+        /* macchwu   - macchwu.   - macchwuo  - macchwuo.  */
+        /* macchwsu  - macchwsu.  - macchwsuo - macchwsuo. */
+        /* mulchwu - mulchwu. */
+        gen_op_405_mulchwu();
+        break;
+    case 0x01:
+        /* machhw    - machhw.    - machhwo   - machhwo.   */
+        /* machhws   - machhws.   - machhwso  - machhwso.  */
+        /* nmachhw   - nmachhw.   - nmachhwo  - nmachhwo.  */
+        /* nmachhws  - nmachhws.  - nmachhwso - nmachhwso. */
+        /* mulhhw - mulhhw. */
+        gen_op_405_mulhhw();
+        break;
+    case 0x00:
+        /* machhwu   - machhwu.   - machhwuo  - machhwuo.  */
+        /* machhwsu  - machhwsu.  - machhwsuo - machhwsuo. */
+        /* mulhhwu - mulhhwu. */
+        gen_op_405_mulhhwu();
+        break;
+    case 0x0D:
+        /* maclhw    - maclhw.    - maclhwo   - maclhwo.   */
+        /* maclhws   - maclhws.   - maclhwso  - maclhwso.  */
+        /* nmaclhw   - nmaclhw.   - nmaclhwo  - nmaclhwo.  */
+        /* nmaclhws  - nmaclhws.  - nmaclhwso - nmaclhwso. */
+        /* mullhw - mullhw. */
+        gen_op_405_mullhw();
+        break;
+    case 0x0C:
+        /* maclhwu   - maclhwu.   - maclhwuo  - maclhwuo.  */
+        /* maclhwsu  - maclhwsu.  - maclhwsuo - maclhwsuo. */
+        /* mullhwu - mullhwu. */
+        gen_op_405_mullhwu();
+        break;
+    }
+    if (opc2 & 0x02) {
+        /* nmultiply-and-accumulate (0x0E) */
+        gen_op_neg();
+    }
+    if (opc2 & 0x04) {
+        /* (n)multiply-and-accumulate (0x0C - 0x0E) */
+        gen_op_load_gpr_T2(rt);
+        gen_op_move_T1_T0();
+        gen_op_405_add_T0_T2();
+    }
+    if (opc3 & 0x10) {
+        /* Check overflow */
+        if (opc3 & 0x01)
+            gen_op_405_check_ov();
+        else
+            gen_op_405_check_ovu();
+    }
+    if (opc3 & 0x02) {
+        /* Saturate */
+        if (opc3 & 0x01)
+            gen_op_405_check_sat();
+        else
+            gen_op_405_check_satu();
+    }
+    gen_op_store_T0_gpr(rt);
+    if (unlikely(Rc) != 0) {
+        /* Update Rc0 */
+        gen_set_Rc0(ctx);
+    }
+}
+
+#define GEN_MAC_HANDLER(name, opc2, opc3)                                     \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC)                  \
+{                                                                             \
+    gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode),   \
+                         rD(ctx->opcode), Rc(ctx->opcode));                   \
+}
+
+/* macchw    - macchw.    */
+GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
+/* macchwo   - macchwo.   */
+GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
+/* macchws   - macchws.   */
+GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
+/* macchwso  - macchwso.  */
+GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
+/* macchwsu  - macchwsu.  */
+GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
+/* macchwsuo - macchwsuo. */
+GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
+/* macchwu   - macchwu.   */
+GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
+/* macchwuo  - macchwuo.  */
+GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
+/* machhw    - machhw.    */
+GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
+/* machhwo   - machhwo.   */
+GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
+/* machhws   - machhws.   */
+GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
+/* machhwso  - machhwso.  */
+GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
+/* machhwsu  - machhwsu.  */
+GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
+/* machhwsuo - machhwsuo. */
+GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
+/* machhwu   - machhwu.   */
+GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
+/* machhwuo  - machhwuo.  */
+GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
+/* maclhw    - maclhw.    */
+GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
+/* maclhwo   - maclhwo.   */
+GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
+/* maclhws   - maclhws.   */
+GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
+/* maclhwso  - maclhwso.  */
+GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
+/* maclhwu   - maclhwu.   */
+GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
+/* maclhwuo  - maclhwuo.  */
+GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
+/* maclhwsu  - maclhwsu.  */
+GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
+/* maclhwsuo - maclhwsuo. */
+GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
+/* nmacchw   - nmacchw.   */
+GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
+/* nmacchwo  - nmacchwo.  */
+GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
+/* nmacchws  - nmacchws.  */
+GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
+/* nmacchwso - nmacchwso. */
+GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
+/* nmachhw   - nmachhw.   */
+GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
+/* nmachhwo  - nmachhwo.  */
+GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
+/* nmachhws  - nmachhws.  */
+GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
+/* nmachhwso - nmachhwso. */
+GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
+/* nmaclhw   - nmaclhw.   */
+GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
+/* nmaclhwo  - nmaclhwo.  */
+GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
+/* nmaclhws  - nmaclhws.  */
+GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
+/* nmaclhwso - nmaclhwso. */
+GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
+
+/* mulchw  - mulchw.  */
+GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
+/* mulchwu - mulchwu. */
+GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
+/* mulhhw  - mulhhw.  */
+GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
+/* mulhhwu - mulhhwu. */
+GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
+/* mullhw  - mullhw.  */
+GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
+/* mullhwu - mullhwu. */
+GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
+
+/* mfdcr */
+GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    uint32_t dcrn = SPR(ctx->opcode);
+
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_set_T0(dcrn);
+    gen_op_load_dcr();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mtdcr */
+GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    uint32_t dcrn = SPR(ctx->opcode);
+
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_set_T0(dcrn);
+    gen_op_load_gpr_T1(rS(ctx->opcode));
+    gen_op_store_dcr();
+#endif
+}
+
+/* mfdcrx */
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000000, PPC_BOOKE_EXT)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_dcr();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    /* Note: Rc update flag set leads to undefined state of Rc0 */
+#endif
+}
+
+/* mtdcrx */
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000000, PPC_BOOKE_EXT)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVREG(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVREG(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rS(ctx->opcode));
+    gen_op_store_dcr();
+    /* Note: Rc update flag set leads to undefined state of Rc0 */
+#endif
+}
+
+/* mfdcrux (PPC 460) : user-mode access to DCR */
+GEN_HANDLER(mfdcrux, 0x1F, 0x03, 0x09, 0x00000000, PPC_DCRUX)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_dcr();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+    /* Note: Rc update flag set leads to undefined state of Rc0 */
+}
+
+/* mtdcrux (PPC 460) : user-mode access to DCR */
+GEN_HANDLER(mtdcrux, 0x1F, 0x03, 0x0D, 0x00000000, PPC_DCRUX)
+{
+    gen_op_load_gpr_T0(rA(ctx->opcode));
+    gen_op_load_gpr_T1(rS(ctx->opcode));
+    gen_op_store_dcr();
+    /* Note: Rc update flag set leads to undefined state of Rc0 */
+}
+
+/* dccci */
+GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* dcread */
+GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    op_ldst(lwz);
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* icbt */
+GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_ICBT)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
+}
+
+/* iccci */
+GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* icread */
+GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    /* interpreted as no-op */
+#endif
+}
+
+/* rfci (supervisor only) */
+GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    /* Restore CPU state */
+    gen_op_40x_rfci();
+    GEN_SYNC(ctx);
+#endif
+}
+
+GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    /* Restore CPU state */
+    gen_op_rfci();
+    GEN_SYNC(ctx);
+#endif
+}
+
+/* BookE specific */
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE_EXT)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    /* Restore CPU state */
+    gen_op_rfdi();
+    GEN_SYNC(ctx);
+#endif
+}
+
+/* XXX: not implemented on 440 ? */
+GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_RFMCI)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    /* Restore CPU state */
+    gen_op_rfmci();
+    GEN_SYNC(ctx);
+#endif
+}
+
+/* TLB management - PowerPC 405 implementation */
+/* tlbre */
+GEN_HANDLER(tlbre_40x, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_4xx_tlbre_hi();
+        gen_op_store_T0_gpr(rD(ctx->opcode));
+        break;
+    case 1:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_4xx_tlbre_lo();
+        gen_op_store_T0_gpr(rD(ctx->opcode));
+        break;
+    default:
+        GEN_EXCP_INVAL(ctx);
+        break;
+    }
+#endif
+}
+
+/* tlbsx - tlbsx. */
+GEN_HANDLER(tlbsx_40x, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    gen_op_4xx_tlbsx();
+    if (Rc(ctx->opcode))
+        gen_op_4xx_tlbsx_check();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* tlbwe */
+GEN_HANDLER(tlbwe_40x, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rS(ctx->opcode));
+        gen_op_4xx_tlbwe_hi();
+        break;
+    case 1:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rS(ctx->opcode));
+        gen_op_4xx_tlbwe_lo();
+        break;
+    default:
+        GEN_EXCP_INVAL(ctx);
+        break;
+    }
+#endif
+}
+
+/* TLB management - PowerPC 440 implementation */
+/* tlbre */
+GEN_HANDLER(tlbre_440, 0x1F, 0x12, 0x1D, 0x00000001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+    case 1:
+    case 2:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_440_tlbre(rB(ctx->opcode));
+        gen_op_store_T0_gpr(rD(ctx->opcode));
+        break;
+    default:
+        GEN_EXCP_INVAL(ctx);
+        break;
+    }
+#endif
+}
+
+/* tlbsx - tlbsx. */
+GEN_HANDLER(tlbsx_440, 0x1F, 0x12, 0x1C, 0x00000000, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_addr_reg_index(ctx);
+    gen_op_440_tlbsx();
+    if (Rc(ctx->opcode))
+        gen_op_4xx_tlbsx_check();
+    gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* tlbwe */
+GEN_HANDLER(tlbwe_440, 0x1F, 0x12, 0x1E, 0x00000001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    switch (rB(ctx->opcode)) {
+    case 0:
+    case 1:
+    case 2:
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        gen_op_load_gpr_T1(rS(ctx->opcode));
+        gen_op_440_tlbwe(rB(ctx->opcode));
+        break;
+    default:
+        GEN_EXCP_INVAL(ctx);
+        break;
+    }
+#endif
+}
+
+/* wrtee */
+GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_load_gpr_T0(rD(ctx->opcode));
+    gen_op_wrte();
+    /* Stop translation to have a chance to raise an exception
+     * if we just set msr_ee to 1
+     */
+    GEN_STOP(ctx);
+#endif
+}
+
+/* wrteei */
+GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+    GEN_EXCP_PRIVOPC(ctx);
+#else
+    if (unlikely(!ctx->supervisor)) {
+        GEN_EXCP_PRIVOPC(ctx);
+        return;
+    }
+    gen_op_set_T0(ctx->opcode & 0x00010000);
+    gen_op_wrte();
+    /* Stop translation to have a chance to raise an exception
+     * if we just set msr_ee to 1
+     */
+    GEN_STOP(ctx);
+#endif
+}
+
+/* PowerPC 440 specific instructions */
+/* dlmzb */
+GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
+{
+    gen_op_load_gpr_T0(rS(ctx->opcode));
+    gen_op_load_gpr_T1(rB(ctx->opcode));
+    gen_op_440_dlmzb();
+    gen_op_store_T0_gpr(rA(ctx->opcode));
+    gen_op_store_xer_bc();
+    if (Rc(ctx->opcode)) {
+        gen_op_440_dlmzb_update_Rc();
+        gen_op_store_T0_crf(0);
+    }
+}
+
+/* mbar replaces eieio on 440 */
+GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE)
+{
+    /* interpreted as no-op */
+}
+
+/* msync replaces sync on 440 */
+GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FFF801, PPC_BOOKE)
+{
+    /* interpreted as no-op */
+}
+
+/* icbt */
+GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
+{
+    /* interpreted as no-op */
+    /* XXX: specification say this is treated as a load by the MMU
+     *      but does not generate any exception
+     */
+}
+
+#if defined(TARGET_PPCEMB)
+/***                           SPE extension                               ***/
+
+/* Register moves */
+GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr);
+GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr);
+#if 0 // unused
+GEN32(gen_op_load_gpr64_T2, gen_op_load_gpr64_T2_gpr);
+#endif
+
+GEN32(gen_op_store_T0_gpr64, gen_op_store_T0_gpr64_gpr);
+GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr);
+#if 0 // unused
+GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr);
+#endif
+
+#define GEN_SPE(name0, name1, opc2, opc3, inval, type)                        \
+GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type)                   \
+{                                                                             \
+    if (Rc(ctx->opcode))                                                      \
+        gen_##name1(ctx);                                                     \
+    else                                                                      \
+        gen_##name0(ctx);                                                     \
+}
+
+/* Handler for undefined SPE opcodes */
+static inline void gen_speundef (DisasContext *ctx)
+{
+    GEN_EXCP_INVAL(ctx);
+}
+
+/* SPE load and stores */
+static inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh)
+{
+    target_long simm = rB(ctx->opcode);
+
+    if (rA(ctx->opcode) == 0) {
+        gen_set_T0(simm << sh);
+    } else {
+        gen_op_load_gpr_T0(rA(ctx->opcode));
+        if (likely(simm != 0))
+            gen_op_addi(simm << sh);
+    }
+}
+
+#define op_spe_ldst(name)        (*gen_op_##name[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+#define OP_SPE_LD_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_l##name[] = {                                    \
+    &gen_op_spe_l##name##_raw,                                                \
+    &gen_op_spe_l##name##_le_raw,                                             \
+    &gen_op_spe_l##name##_64_raw,                                             \
+    &gen_op_spe_l##name##_le_64_raw,                                          \
+};
+#define OP_SPE_ST_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_st##name[] = {                                   \
+    &gen_op_spe_st##name##_raw,                                               \
+    &gen_op_spe_st##name##_le_raw,                                            \
+    &gen_op_spe_st##name##_64_raw,                                            \
+    &gen_op_spe_st##name##_le_64_raw,                                         \
+};
+#else /* defined(TARGET_PPC64) */
+#define OP_SPE_LD_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_l##name[] = {                                    \
+    &gen_op_spe_l##name##_raw,                                                \
+    &gen_op_spe_l##name##_le_raw,                                             \
+};
+#define OP_SPE_ST_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_st##name[] = {                                   \
+    &gen_op_spe_st##name##_raw,                                               \
+    &gen_op_spe_st##name##_le_raw,                                            \
+};
+#endif /* defined(TARGET_PPC64) */
+#else /* defined(CONFIG_USER_ONLY) */
+#if defined(TARGET_PPC64)
+#define OP_SPE_LD_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_l##name[] = {                                    \
+    &gen_op_spe_l##name##_user,                                               \
+    &gen_op_spe_l##name##_le_user,                                            \
+    &gen_op_spe_l##name##_kernel,                                             \
+    &gen_op_spe_l##name##_le_kernel,                                          \
+    &gen_op_spe_l##name##_64_user,                                            \
+    &gen_op_spe_l##name##_le_64_user,                                         \
+    &gen_op_spe_l##name##_64_kernel,                                          \
+    &gen_op_spe_l##name##_le_64_kernel,                                       \
+};
+#define OP_SPE_ST_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_st##name[] = {                                   \
+    &gen_op_spe_st##name##_user,                                              \
+    &gen_op_spe_st##name##_le_user,                                           \
+    &gen_op_spe_st##name##_kernel,                                            \
+    &gen_op_spe_st##name##_le_kernel,                                         \
+    &gen_op_spe_st##name##_64_user,                                           \
+    &gen_op_spe_st##name##_le_64_user,                                        \
+    &gen_op_spe_st##name##_64_kernel,                                         \
+    &gen_op_spe_st##name##_le_64_kernel,                                      \
+};
+#else /* defined(TARGET_PPC64) */
+#define OP_SPE_LD_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_l##name[] = {                                    \
+    &gen_op_spe_l##name##_user,                                               \
+    &gen_op_spe_l##name##_le_user,                                            \
+    &gen_op_spe_l##name##_kernel,                                             \
+    &gen_op_spe_l##name##_le_kernel,                                          \
+};
+#define OP_SPE_ST_TABLE(name)                                                 \
+static GenOpFunc *gen_op_spe_st##name[] = {                                   \
+    &gen_op_spe_st##name##_user,                                              \
+    &gen_op_spe_st##name##_le_user,                                           \
+    &gen_op_spe_st##name##_kernel,                                            \
+    &gen_op_spe_st##name##_le_kernel,                                         \
+};
+#endif /* defined(TARGET_PPC64) */
+#endif /* defined(CONFIG_USER_ONLY) */
+
+#define GEN_SPE_LD(name, sh)                                                  \
+static inline void gen_evl##name (DisasContext *ctx)                          \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_addr_spe_imm_index(ctx, sh);                                          \
+    op_spe_ldst(spe_l##name);                                                 \
+    gen_op_store_T1_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPE_LDX(name)                                                     \
+static inline void gen_evl##name##x (DisasContext *ctx)                       \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
+    op_spe_ldst(spe_l##name);                                                 \
+    gen_op_store_T1_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPEOP_LD(name, sh)                                                \
+OP_SPE_LD_TABLE(name);                                                        \
+GEN_SPE_LD(name, sh);                                                         \
+GEN_SPE_LDX(name)
+
+#define GEN_SPE_ST(name, sh)                                                  \
+static inline void gen_evst##name (DisasContext *ctx)                         \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_addr_spe_imm_index(ctx, sh);                                          \
+    gen_op_load_gpr64_T1(rS(ctx->opcode));                                    \
+    op_spe_ldst(spe_st##name);                                                \
+}
+
+#define GEN_SPE_STX(name)                                                     \
+static inline void gen_evst##name##x (DisasContext *ctx)                      \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_addr_reg_index(ctx);                                                  \
+    gen_op_load_gpr64_T1(rS(ctx->opcode));                                    \
+    op_spe_ldst(spe_st##name);                                                \
+}
+
+#define GEN_SPEOP_ST(name, sh)                                                \
+OP_SPE_ST_TABLE(name);                                                        \
+GEN_SPE_ST(name, sh);                                                         \
+GEN_SPE_STX(name)
+
+#define GEN_SPEOP_LDST(name, sh)                                              \
+GEN_SPEOP_LD(name, sh);                                                       \
+GEN_SPEOP_ST(name, sh)
+
+/* SPE arithmetic and logic */
+#define GEN_SPEOP_ARITH2(name)                                                \
+static inline void gen_##name (DisasContext *ctx)                             \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rA(ctx->opcode));                                    \
+    gen_op_load_gpr64_T1(rB(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPEOP_ARITH1(name)                                                \
+static inline void gen_##name (DisasContext *ctx)                             \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rA(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPEOP_COMP(name)                                                  \
+static inline void gen_##name (DisasContext *ctx)                             \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rA(ctx->opcode));                                    \
+    gen_op_load_gpr64_T1(rB(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_crf(crfD(ctx->opcode));                                   \
+}
+
+/* Logical */
+GEN_SPEOP_ARITH2(evand);
+GEN_SPEOP_ARITH2(evandc);
+GEN_SPEOP_ARITH2(evxor);
+GEN_SPEOP_ARITH2(evor);
+GEN_SPEOP_ARITH2(evnor);
+GEN_SPEOP_ARITH2(eveqv);
+GEN_SPEOP_ARITH2(evorc);
+GEN_SPEOP_ARITH2(evnand);
+GEN_SPEOP_ARITH2(evsrwu);
+GEN_SPEOP_ARITH2(evsrws);
+GEN_SPEOP_ARITH2(evslw);
+GEN_SPEOP_ARITH2(evrlw);
+GEN_SPEOP_ARITH2(evmergehi);
+GEN_SPEOP_ARITH2(evmergelo);
+GEN_SPEOP_ARITH2(evmergehilo);
+GEN_SPEOP_ARITH2(evmergelohi);
+
+/* Arithmetic */
+GEN_SPEOP_ARITH2(evaddw);
+GEN_SPEOP_ARITH2(evsubfw);
+GEN_SPEOP_ARITH1(evabs);
+GEN_SPEOP_ARITH1(evneg);
+GEN_SPEOP_ARITH1(evextsb);
+GEN_SPEOP_ARITH1(evextsh);
+GEN_SPEOP_ARITH1(evrndw);
+GEN_SPEOP_ARITH1(evcntlzw);
+GEN_SPEOP_ARITH1(evcntlsw);
+static inline void gen_brinc (DisasContext *ctx)
+{
+    /* Note: brinc is usable even if SPE is disabled */
+    gen_op_load_gpr64_T0(rA(ctx->opcode));
+    gen_op_load_gpr64_T1(rB(ctx->opcode));
+    gen_op_brinc();
+    gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+#define GEN_SPEOP_ARITH_IMM2(name)                                            \
+static inline void gen_##name##i (DisasContext *ctx)                          \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rB(ctx->opcode));                                    \
+    gen_op_splatwi_T1_64(rA(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+#define GEN_SPEOP_LOGIC_IMM2(name)                                            \
+static inline void gen_##name##i (DisasContext *ctx)                          \
+{                                                                             \
+    if (unlikely(!ctx->spe_enabled)) {                                        \
+        GEN_EXCP_NO_AP(ctx);                                                  \
+        return;                                                               \
+    }                                                                         \
+    gen_op_load_gpr64_T0(rA(ctx->opcode));                                    \
+    gen_op_splatwi_T1_64(rB(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+GEN_SPEOP_ARITH_IMM2(evaddw);
+#define gen_evaddiw gen_evaddwi
+GEN_SPEOP_ARITH_IMM2(evsubfw);
+#define gen_evsubifw gen_evsubfwi
+GEN_SPEOP_LOGIC_IMM2(evslw);
+GEN_SPEOP_LOGIC_IMM2(evsrwu);
+#define gen_evsrwis gen_evsrwsi
+GEN_SPEOP_LOGIC_IMM2(evsrws);
+#define gen_evsrwiu gen_evsrwui
+GEN_SPEOP_LOGIC_IMM2(evrlw);
+
+static inline void gen_evsplati (DisasContext *ctx)
+{
+    int32_t imm = (int32_t)(rA(ctx->opcode) << 27) >> 27;
+
+    gen_op_splatwi_T0_64(imm);
+    gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+static inline void gen_evsplatfi (DisasContext *ctx)
+{
+    uint32_t imm = rA(ctx->opcode) << 27;
+
+    gen_op_splatwi_T0_64(imm);
+    gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+/* Comparison */
+GEN_SPEOP_COMP(evcmpgtu);
+GEN_SPEOP_COMP(evcmpgts);
+GEN_SPEOP_COMP(evcmpltu);
+GEN_SPEOP_COMP(evcmplts);
+GEN_SPEOP_COMP(evcmpeq);
+
+GEN_SPE(evaddw,         speundef,      0x00, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evaddiw,        speundef,      0x01, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evsubfw,        speundef,      0x02, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsubifw,       speundef,      0x03, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evabs,          evneg,         0x04, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evextsb,        evextsh,       0x05, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evrndw,         evcntlzw,      0x06, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evcntlsw,       brinc,         0x07, 0x08, 0x00000000, PPC_SPE); //
+GEN_SPE(speundef,       evand,         0x08, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evandc,         speundef,      0x09, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evxor,          evor,          0x0B, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnor,          eveqv,         0x0C, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(speundef,       evorc,         0x0D, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnand,         speundef,      0x0F, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwu,         evsrws,        0x10, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwiu,        evsrwis,       0x11, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evslw,          speundef,      0x12, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evslwi,         speundef,      0x13, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evrlw,          evsplati,      0x14, 0x08, 0x00000000, PPC_SPE); //
+GEN_SPE(evrlwi,         evsplatfi,     0x15, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evmergehi,      evmergelo,     0x16, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmergehilo,    evmergelohi,   0x17, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evcmpgtu,       evcmpgts,      0x18, 0x08, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpltu,       evcmplts,      0x19, 0x08, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpeq,        speundef,      0x1A, 0x08, 0x00600000, PPC_SPE); ////
+
+static inline void gen_evsel (DisasContext *ctx)
+{
+    if (unlikely(!ctx->spe_enabled)) {
+        GEN_EXCP_NO_AP(ctx);
+        return;
+    }
+    gen_op_load_crf_T0(ctx->opcode & 0x7);
+    gen_op_load_gpr64_T0(rA(ctx->opcode));
+    gen_op_load_gpr64_T1(rB(ctx->opcode));
+    gen_op_evsel();
+    gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+GEN_HANDLER(evsel0, 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE)
+{
+    gen_evsel(ctx);
+}
+GEN_HANDLER(evsel1, 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE)
+{
+    gen_evsel(ctx);
+}
+GEN_HANDLER(evsel2, 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE)
+{
+    gen_evsel(ctx);
+}
+GEN_HANDLER(evsel3, 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE)
+{
+    gen_evsel(ctx);
+}
+
+/* Load and stores */
+#if defined(TARGET_PPC64)
+/* In that case, we already have 64 bits load & stores
+ * so, spe_ldd is equivalent to ld and spe_std is equivalent to std
+ */
+#if defined(CONFIG_USER_ONLY)
+#define gen_op_spe_ldd_raw gen_op_ld_raw
+#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw
+#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw
+#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw
+#define gen_op_spe_stdd_raw gen_op_ld_raw
+#define gen_op_spe_stdd_64_raw gen_op_std_64_raw
+#define gen_op_spe_stdd_le_raw gen_op_std_le_raw
+#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw
+#else /* defined(CONFIG_USER_ONLY) */
+#define gen_op_spe_ldd_kernel gen_op_ld_kernel
+#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel
+#define gen_op_spe_ldd_le_kernel gen_op_ld_kernel
+#define gen_op_spe_ldd_le_64_kernel gen_op_ld_64_kernel
+#define gen_op_spe_ldd_user gen_op_ld_user
+#define gen_op_spe_ldd_64_user gen_op_ld_64_user
+#define gen_op_spe_ldd_le_user gen_op_ld_le_user
+#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user
+#define gen_op_spe_stdd_kernel gen_op_std_kernel
+#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel
+#define gen_op_spe_stdd_le_kernel gen_op_std_kernel
+#define gen_op_spe_stdd_le_64_kernel gen_op_std_64_kernel
+#define gen_op_spe_stdd_user gen_op_std_user
+#define gen_op_spe_stdd_64_user gen_op_std_64_user
+#define gen_op_spe_stdd_le_user gen_op_std_le_user
+#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user
+#endif /* defined(CONFIG_USER_ONLY) */
+#endif /* defined(TARGET_PPC64) */
+GEN_SPEOP_LDST(dd, 3);
+GEN_SPEOP_LDST(dw, 3);
+GEN_SPEOP_LDST(dh, 3);
+GEN_SPEOP_LDST(whe, 2);
+GEN_SPEOP_LD(whou, 2);
+GEN_SPEOP_LD(whos, 2);
+GEN_SPEOP_ST(who, 2);
+
+#if defined(TARGET_PPC64)
+/* In that case, spe_stwwo is equivalent to stw */
+#if defined(CONFIG_USER_ONLY)
+#define gen_op_spe_stwwo_raw gen_op_stw_raw
+#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw
+#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw
+#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw
+#else
+#define gen_op_spe_stwwo_user gen_op_stw_user
+#define gen_op_spe_stwwo_le_user gen_op_stw_le_user
+#define gen_op_spe_stwwo_64_user gen_op_stw_64_user
+#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user
+#define gen_op_spe_stwwo_kernel gen_op_stw_kernel
+#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel
+#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel
+#define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel
+#endif
+#endif
+#define _GEN_OP_SPE_STWWE(suffix)                                             \
+static inline void gen_op_spe_stwwe_##suffix (void)                           \
+{                                                                             \
+    gen_op_srli32_T1_64();                                                    \
+    gen_op_spe_stwwo_##suffix();                                              \
+}
+#define _GEN_OP_SPE_STWWE_LE(suffix)                                          \
+static inline void gen_op_spe_stwwe_le_##suffix (void)                        \
+{                                                                             \
+    gen_op_srli32_T1_64();                                                    \
+    gen_op_spe_stwwo_le_##suffix();                                           \
+}
+#if defined(TARGET_PPC64)
+#define GEN_OP_SPE_STWWE(suffix)                                              \
+_GEN_OP_SPE_STWWE(suffix);                                                    \
+_GEN_OP_SPE_STWWE_LE(suffix);                                                 \
+static inline void gen_op_spe_stwwe_64_##suffix (void)                        \
+{                                                                             \
+    gen_op_srli32_T1_64();                                                    \
+    gen_op_spe_stwwo_64_##suffix();                                           \
+}                                                                             \
+static inline void gen_op_spe_stwwe_le_64_##suffix (void)                     \
+{                                                                             \
+    gen_op_srli32_T1_64();                                                    \
+    gen_op_spe_stwwo_le_64_##suffix();                                        \
+}
+#else
+#define GEN_OP_SPE_STWWE(suffix)                                              \
+_GEN_OP_SPE_STWWE(suffix);                                                    \
+_GEN_OP_SPE_STWWE_LE(suffix)
+#endif
+#if defined(CONFIG_USER_ONLY)
+GEN_OP_SPE_STWWE(raw);
+#else /* defined(CONFIG_USER_ONLY) */
+GEN_OP_SPE_STWWE(kernel);
+GEN_OP_SPE_STWWE(user);
+#endif /* defined(CONFIG_USER_ONLY) */
+GEN_SPEOP_ST(wwe, 2);
+GEN_SPEOP_ST(wwo, 2);
+
+#define GEN_SPE_LDSPLAT(name, op, suffix)                                     \
+static inline void gen_op_spe_l##name##_##suffix (void)                       \
+{                                                                             \
+    gen_op_##op##_##suffix();                                                 \
+    gen_op_splatw_T1_64();                                                    \
+}
+
+#define GEN_OP_SPE_LHE(suffix)                                                \
+static inline void gen_op_spe_lhe_##suffix (void)                             \
+{                                                                             \
+    gen_op_spe_lh_##suffix();                                                 \
+    gen_op_sli16_T1_64();                                                     \
+}
+
+#define GEN_OP_SPE_LHX(suffix)                                                \
+static inline void gen_op_spe_lhx_##suffix (void)                             \
+{                                                                             \
+    gen_op_spe_lh_##suffix();                                                 \
+    gen_op_extsh_T1_64();                                                     \
+}
+
+#if defined(CONFIG_USER_ONLY)
+GEN_OP_SPE_LHE(raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, raw);
+GEN_OP_SPE_LHE(le_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_raw);
+GEN_OP_SPE_LHX(raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, raw);
+GEN_OP_SPE_LHX(le_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_raw);
+#if defined(TARGET_PPC64)
+GEN_OP_SPE_LHE(64_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_raw);
+GEN_OP_SPE_LHE(le_64_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_raw);
+GEN_OP_SPE_LHX(64_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_raw);
+GEN_OP_SPE_LHX(le_64_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw);
+#endif
+#else
+GEN_OP_SPE_LHE(kernel);
+GEN_OP_SPE_LHE(user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user);
+GEN_OP_SPE_LHE(le_kernel);
+GEN_OP_SPE_LHE(le_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user);
+GEN_OP_SPE_LHX(kernel);
+GEN_OP_SPE_LHX(user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user);
+GEN_OP_SPE_LHX(le_kernel);
+GEN_OP_SPE_LHX(le_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user);
+#if defined(TARGET_PPC64)
+GEN_OP_SPE_LHE(64_kernel);
+GEN_OP_SPE_LHE(64_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user);
+GEN_OP_SPE_LHE(le_64_kernel);
+GEN_OP_SPE_LHE(le_64_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user);
+GEN_OP_SPE_LHX(64_kernel);
+GEN_OP_SPE_LHX(64_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user);
+GEN_OP_SPE_LHX(le_64_kernel);
+GEN_OP_SPE_LHX(le_64_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user);
+#endif
+#endif
+GEN_SPEOP_LD(hhesplat, 1);
+GEN_SPEOP_LD(hhousplat, 1);
+GEN_SPEOP_LD(hhossplat, 1);
+GEN_SPEOP_LD(wwsplat, 2);
+GEN_SPEOP_LD(whsplat, 2);
+
+GEN_SPE(evlddx,         evldd,         0x00, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evldwx,         evldw,         0x01, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evldhx,         evldh,         0x02, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhesplatx,   evlhhesplat,   0x04, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhousplatx,  evlhhousplat,  0x06, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhossplatx,  evlhhossplat,  0x07, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhex,        evlwhe,        0x08, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhoux,       evlwhou,       0x0A, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhosx,       evlwhos,       0x0B, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwwsplatx,    evlwwsplat,    0x0C, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhsplatx,    evlwhsplat,    0x0E, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstddx,        evstdd,        0x10, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstdwx,        evstdw,        0x11, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstdhx,        evstdh,        0x12, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwhex,       evstwhe,       0x18, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwhox,       evstwho,       0x1A, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwwex,       evstwwe,       0x1C, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwwox,       evstwwo,       0x1E, 0x0C, 0x00000000, PPC_SPE); //
+
+/* Multiply and add - TODO */
+#if 0
+GEN_SPE(speundef,       evmhessf,      0x01, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossf,      0x03, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumi,       evmhesmi,      0x04, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmf,      0x05, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumi,       evmhosmi,      0x06, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmf,      0x07, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfa,     0x11, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfa,     0x13, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumia,      evmhesmia,     0x14, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfa,     0x15, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumia,      evmhosmia,     0x16, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfa,     0x17, 0x10, 0x00000000, PPC_SPE);
+
+GEN_SPE(speundef,       evmwhssf,      0x03, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumi,       speundef,      0x04, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwhumi,       evmwhsmi,      0x06, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmf,      0x07, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssf,       0x09, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumi,        evmwsmi,       0x0C, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmf,       0x0D, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhssfa,     0x13, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumia,      speundef,      0x14, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwhumia,      evmwhsmia,     0x16, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwhsmfa,     0x17, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfa,      0x19, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumia,       evmwsmia,      0x1C, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfa,      0x1D, 0x11, 0x00000000, PPC_SPE);
+
+GEN_SPE(evadduiaaw,     evaddsiaaw,    0x00, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfusiaaw,   evsubfssiaaw,  0x01, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evaddumiaaw,    evaddsmiaaw,   0x04, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfumiaaw,   evsubfsmiaaw,  0x05, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evdivws,        evdivwu,       0x06, 0x13, 0x00000000, PPC_SPE);
+GEN_SPE(evmra,          speundef,      0x07, 0x13, 0x0000F800, PPC_SPE);
+
+GEN_SPE(evmheusiaaw,    evmhessiaaw,   0x00, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfaaw,   0x01, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousiaaw,    evmhossiaaw,   0x02, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfaaw,   0x03, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumiaaw,    evmhesmiaaw,   0x04, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfaaw,   0x05, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumiaaw,    evmhosmiaaw,   0x06, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfaaw,   0x07, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumiaa,    evmhegsmiaa,   0x14, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfaa,   0x15, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhogumiaa,    evmhogsmiaa,   0x16, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfaa,   0x17, 0x14, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusiaaw,    evmwlssiaaw,   0x00, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumiaaw,    evmwlsmiaaw,   0x04, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfaa,     0x09, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumiaa,      evmwsmiaa,     0x0C, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfaa,     0x0D, 0x15, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusianw,    evmhessianw,   0x00, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhessfanw,   0x01, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousianw,    evmhossianw,   0x02, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhossfanw,   0x03, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumianw,    evmhesmianw,   0x04, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhesmfanw,   0x05, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumianw,    evmhosmianw,   0x06, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhosmfanw,   0x07, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumian,    evmhegsmian,   0x14, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhegsmfan,   0x15, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhigumian,    evmhigsmian,   0x16, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmhogsmfan,   0x17, 0x16, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusianw,    evmwlssianw,   0x00, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumianw,    evmwlsmianw,   0x04, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwssfan,     0x09, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumian,      evmwsmian,     0x0C, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef,       evmwsmfan,     0x0D, 0x17, 0x00000000, PPC_SPE);
+#endif
+
+/***                      SPE floating-point extension                     ***/
+#define GEN_SPEFPUOP_CONV(name)                                               \
+static inline void gen_##name (DisasContext *ctx)                             \
+{                                                                             \
+    gen_op_load_gpr64_T0(rB(ctx->opcode));                                    \
+    gen_op_##name();                                                          \
+    gen_op_store_T0_gpr64(rD(ctx->opcode));                                   \
+}
+
+/* Single precision floating-point vectors operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(evfsadd);
+GEN_SPEOP_ARITH2(evfssub);
+GEN_SPEOP_ARITH2(evfsmul);
+GEN_SPEOP_ARITH2(evfsdiv);
+GEN_SPEOP_ARITH1(evfsabs);
+GEN_SPEOP_ARITH1(evfsnabs);
+GEN_SPEOP_ARITH1(evfsneg);
+/* Conversion */
+GEN_SPEFPUOP_CONV(evfscfui);
+GEN_SPEFPUOP_CONV(evfscfsi);
+GEN_SPEFPUOP_CONV(evfscfuf);
+GEN_SPEFPUOP_CONV(evfscfsf);
+GEN_SPEFPUOP_CONV(evfsctui);
+GEN_SPEFPUOP_CONV(evfsctsi);
+GEN_SPEFPUOP_CONV(evfsctuf);
+GEN_SPEFPUOP_CONV(evfsctsf);
+GEN_SPEFPUOP_CONV(evfsctuiz);
+GEN_SPEFPUOP_CONV(evfsctsiz);
+/* Comparison */
+GEN_SPEOP_COMP(evfscmpgt);
+GEN_SPEOP_COMP(evfscmplt);
+GEN_SPEOP_COMP(evfscmpeq);
+GEN_SPEOP_COMP(evfststgt);
+GEN_SPEOP_COMP(evfststlt);
+GEN_SPEOP_COMP(evfststeq);
+
+/* Opcodes definitions */
+GEN_SPE(evfsadd,        evfssub,       0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(evfsabs,        evfsnabs,      0x02, 0x0A, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(evfsneg,        speundef,      0x03, 0x0A, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(evfsmul,        evfsdiv,       0x04, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(evfscmpgt,      evfscmplt,     0x06, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfscmpeq,      speundef,      0x07, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfscfui,       evfscfsi,      0x08, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfscfuf,       evfscfsf,      0x09, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctui,       evfsctsi,      0x0A, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctuf,       evfsctsf,      0x0B, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctuiz,      speundef,      0x0C, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctsiz,      speundef,      0x0D, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfststgt,      evfststlt,     0x0E, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfststeq,      speundef,      0x0F, 0x0A, 0x00600000, PPC_SPEFPU); //
+
+/* Single precision floating-point operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(efsadd);
+GEN_SPEOP_ARITH2(efssub);
+GEN_SPEOP_ARITH2(efsmul);
+GEN_SPEOP_ARITH2(efsdiv);
+GEN_SPEOP_ARITH1(efsabs);
+GEN_SPEOP_ARITH1(efsnabs);
+GEN_SPEOP_ARITH1(efsneg);
+/* Conversion */
+GEN_SPEFPUOP_CONV(efscfui);
+GEN_SPEFPUOP_CONV(efscfsi);
+GEN_SPEFPUOP_CONV(efscfuf);
+GEN_SPEFPUOP_CONV(efscfsf);
+GEN_SPEFPUOP_CONV(efsctui);
+GEN_SPEFPUOP_CONV(efsctsi);
+GEN_SPEFPUOP_CONV(efsctuf);
+GEN_SPEFPUOP_CONV(efsctsf);
+GEN_SPEFPUOP_CONV(efsctuiz);
+GEN_SPEFPUOP_CONV(efsctsiz);
+GEN_SPEFPUOP_CONV(efscfd);
+/* Comparison */
+GEN_SPEOP_COMP(efscmpgt);
+GEN_SPEOP_COMP(efscmplt);
+GEN_SPEOP_COMP(efscmpeq);
+GEN_SPEOP_COMP(efststgt);
+GEN_SPEOP_COMP(efststlt);
+GEN_SPEOP_COMP(efststeq);
+
+/* Opcodes definitions */
+GEN_SPE(efsadd,         efssub,        0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efsabs,         efsnabs,       0x02, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efsneg,         speundef,      0x03, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efsmul,         efsdiv,        0x04, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efscmpgt,       efscmplt,      0x06, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efscmpeq,       efscfd,        0x07, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efscfui,        efscfsi,       0x08, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efscfuf,        efscfsf,       0x09, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctui,        efsctsi,       0x0A, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctuf,        efsctsf,       0x0B, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctuiz,       efsctsiz,      0x0C, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efststgt,       efststlt,      0x0E, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efststeq,       speundef,      0x0F, 0x0B, 0x00600000, PPC_SPEFPU); //
+
+/* Double precision floating-point operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(efdadd);
+GEN_SPEOP_ARITH2(efdsub);
+GEN_SPEOP_ARITH2(efdmul);
+GEN_SPEOP_ARITH2(efddiv);
+GEN_SPEOP_ARITH1(efdabs);
+GEN_SPEOP_ARITH1(efdnabs);
+GEN_SPEOP_ARITH1(efdneg);
+/* Conversion */
+
+GEN_SPEFPUOP_CONV(efdcfui);
+GEN_SPEFPUOP_CONV(efdcfsi);
+GEN_SPEFPUOP_CONV(efdcfuf);
+GEN_SPEFPUOP_CONV(efdcfsf);
+GEN_SPEFPUOP_CONV(efdctui);
+GEN_SPEFPUOP_CONV(efdctsi);
+GEN_SPEFPUOP_CONV(efdctuf);
+GEN_SPEFPUOP_CONV(efdctsf);
+GEN_SPEFPUOP_CONV(efdctuiz);
+GEN_SPEFPUOP_CONV(efdctsiz);
+GEN_SPEFPUOP_CONV(efdcfs);
+GEN_SPEFPUOP_CONV(efdcfuid);
+GEN_SPEFPUOP_CONV(efdcfsid);
+GEN_SPEFPUOP_CONV(efdctuidz);
+GEN_SPEFPUOP_CONV(efdctsidz);
+/* Comparison */
+GEN_SPEOP_COMP(efdcmpgt);
+GEN_SPEOP_COMP(efdcmplt);
+GEN_SPEOP_COMP(efdcmpeq);
+GEN_SPEOP_COMP(efdtstgt);
+GEN_SPEOP_COMP(efdtstlt);
+GEN_SPEOP_COMP(efdtsteq);
+
+/* Opcodes definitions */
+GEN_SPE(efdadd,         efdsub,        0x10, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efdcfuid,       efdcfsid,      0x11, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdabs,         efdnabs,       0x12, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efdneg,         speundef,      0x13, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efdmul,         efddiv,        0x14, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efdctuidz,      efdctsidz,     0x15, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdcmpgt,       efdcmplt,      0x16, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdcmpeq,       efdcfs,        0x17, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdcfui,        efdcfsi,       0x18, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdcfuf,        efdcfsf,       0x19, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctui,        efdctsi,       0x1A, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctuf,        efdctsf,       0x1B, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctuiz,       speundef,      0x1C, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctsiz,       speundef,      0x1D, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdtstgt,       efdtstlt,      0x1E, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdtsteq,       speundef,      0x1F, 0x0B, 0x00600000, PPC_SPEFPU); //
+#endif
+
 /* End opcode list */
 GEN_OPCODE_MARK(end);
 
@@ -2439,50 +6036,70 @@
 
 /*****************************************************************************/
 /* Misc PowerPC helpers */
-void cpu_dump_state(CPUState *env, FILE *f, 
-                    int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
-                    int flags)
+static inline uint32_t load_xer (CPUState *env)
+{
+    return (xer_so << XER_SO) |
+        (xer_ov << XER_OV) |
+        (xer_ca << XER_CA) |
+        (xer_bc << XER_BC) |
+        (xer_cmp << XER_CMP);
+}
+
+void cpu_dump_state (CPUState *env, FILE *f,
+                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                     int flags)
 {
 #if defined(TARGET_PPC64) || 1
 #define FILL ""
-#define REGX "%016" PRIx64
 #define RGPL  4
 #define RFPL  4
 #else
 #define FILL "        "
-#define REGX "%08" PRIx64
 #define RGPL  8
 #define RFPL  4
 #endif
 
     int i;
 
-    cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n",
+    cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX "\n",
                 env->nip, env->lr, env->ctr);
-    cpu_fprintf(f, "MSR " REGX FILL " XER %08x      TB %08x %08x DECR %08x\n",
-                do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env),
-                cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
-        for (i = 0; i < 32; i++) {
+    cpu_fprintf(f, "MSR " REGX FILL " XER %08x      "
+#if !defined(NO_TIMER_DUMP)
+                "TB %08x %08x "
+#if !defined(CONFIG_USER_ONLY)
+                "DECR %08x"
+#endif
+#endif
+                "\n",
+                do_load_msr(env), load_xer(env)
+#if !defined(NO_TIMER_DUMP)
+                , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
+#if !defined(CONFIG_USER_ONLY)
+                , cpu_ppc_load_decr(env)
+#endif
+#endif
+                );
+    for (i = 0; i < 32; i++) {
         if ((i & (RGPL - 1)) == 0)
             cpu_fprintf(f, "GPR%02d", i);
-        cpu_fprintf(f, " " REGX, env->gpr[i]);
+        cpu_fprintf(f, " " REGX, (target_ulong)env->gpr[i]);
         if ((i & (RGPL - 1)) == (RGPL - 1))
             cpu_fprintf(f, "\n");
-        }
+    }
     cpu_fprintf(f, "CR ");
-        for (i = 0; i < 8; i++)
+    for (i = 0; i < 8; i++)
         cpu_fprintf(f, "%01x", env->crf[i]);
     cpu_fprintf(f, "  [");
-        for (i = 0; i < 8; i++) {
-            char a = '-';
-            if (env->crf[i] & 0x08)
-                a = 'L';
-            else if (env->crf[i] & 0x04)
-                a = 'G';
-            else if (env->crf[i] & 0x02)
-                a = 'E';
+    for (i = 0; i < 8; i++) {
+        char a = '-';
+        if (env->crf[i] & 0x08)
+            a = 'L';
+        else if (env->crf[i] & 0x04)
+            a = 'G';
+        else if (env->crf[i] & 0x02)
+            a = 'E';
         cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
-        }
+    }
     cpu_fprintf(f, " ]             " FILL "RES " REGX "\n", env->reserve);
     for (i = 0; i < 32; i++) {
         if ((i & (RFPL - 1)) == 0)
@@ -2495,15 +6112,62 @@
                 "SDR1 " REGX "\n",
                 env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
 
-#undef REGX
 #undef RGPL
 #undef RFPL
 #undef FILL
 }
 
+void cpu_dump_statistics (CPUState *env, FILE*f,
+                          int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+                          int flags)
+{
+#if defined(DO_PPC_STATISTICS)
+    opc_handler_t **t1, **t2, **t3, *handler;
+    int op1, op2, op3;
+
+    t1 = env->opcodes;
+    for (op1 = 0; op1 < 64; op1++) {
+        handler = t1[op1];
+        if (is_indirect_opcode(handler)) {
+            t2 = ind_table(handler);
+            for (op2 = 0; op2 < 32; op2++) {
+                handler = t2[op2];
+                if (is_indirect_opcode(handler)) {
+                    t3 = ind_table(handler);
+                    for (op3 = 0; op3 < 32; op3++) {
+                        handler = t3[op3];
+                        if (handler->count == 0)
+                            continue;
+                        cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: "
+                                    "%016llx %lld\n",
+                                    op1, op2, op3, op1, (op3 << 5) | op2,
+                                    handler->oname,
+                                    handler->count, handler->count);
+                    }
+                } else {
+                    if (handler->count == 0)
+                        continue;
+                    cpu_fprintf(f, "%02x %02x    (%02x %04d) %16s: "
+                                "%016llx %lld\n",
+                                op1, op2, op1, op2, handler->oname,
+                                handler->count, handler->count);
+                }
+            }
+        } else {
+            if (handler->count == 0)
+                continue;
+            cpu_fprintf(f, "%02x       (%02x     ) %16s: %016llx %lld\n",
+                        op1, op1, handler->oname,
+                        handler->count, handler->count);
+        }
+    }
+#endif
+}
+
 /*****************************************************************************/
-int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
-                                    int search_pc)
+static inline int gen_intermediate_code_internal (CPUState *env,
+                                                  TranslationBlock *tb,
+                                                  int search_pc)
 {
     DisasContext ctx, *ctxp = &ctx;
     opc_handler_t **table, *handler;
@@ -2518,32 +6182,49 @@
     nb_gen_labels = 0;
     ctx.nip = pc_start;
     ctx.tb = tb;
-    ctx.exception = EXCP_NONE;
+    ctx.exception = POWERPC_EXCP_NONE;
     ctx.spr_cb = env->spr_cb;
 #if defined(CONFIG_USER_ONLY)
     ctx.mem_idx = msr_le;
+#if defined(TARGET_PPC64)
+    ctx.mem_idx |= msr_sf << 1;
+#endif
 #else
-    ctx.supervisor = 1 - msr_pr;
+#if defined(TARGET_PPC64H)
+    if (msr_pr == 0 && msr_hv == 1)
+        ctx.supervisor = 2;
+    else
+#endif
+        ctx.supervisor = 1 - msr_pr;
     ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
+#if defined(TARGET_PPC64)
+    ctx.mem_idx |= msr_sf << 2;
+#endif
+#endif
+#if defined(TARGET_PPC64)
+    ctx.sf_mode = msr_sf;
 #endif
     ctx.fpu_enabled = msr_fp;
+#if defined(TARGET_PPCEMB)
+    ctx.spe_enabled = msr_spe;
+#endif
     ctx.singlestep_enabled = env->singlestep_enabled;
 #if defined (DO_SINGLE_STEP) && 0
     /* Single step trace mode */
     msr_se = 1;
 #endif
     /* Set env in case of segfault during code fetch */
-    while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
-        if (env->nb_breakpoints > 0) {
-            for(j = 0; j < env->nb_breakpoints; j++) {
+    while (ctx.exception == POWERPC_EXCP_NONE && gen_opc_ptr < gen_opc_end) {
+        if (unlikely(env->nb_breakpoints > 0)) {
+            for (j = 0; j < env->nb_breakpoints; j++) {
                 if (env->breakpoints[j] == ctx.nip) {
-                    gen_op_update_nip(ctx.nip); 
+                    gen_update_nip(&ctx, ctx.nip);
                     gen_op_debug();
                     break;
                 }
             }
         }
-        if (search_pc) {
+        if (unlikely(search_pc)) {
             j = gen_opc_ptr - gen_opc_buf;
             if (lj < j) {
                 lj++;
@@ -2556,7 +6237,7 @@
 #if defined PPC_DEBUG_DISAS
         if (loglevel & CPU_LOG_TB_IN_ASM) {
             fprintf(logfile, "----------------\n");
-            fprintf(logfile, "nip=%08x super=%d ir=%d\n",
+            fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n",
                     ctx.nip, 1 - msr_pr, msr_ir);
         }
 #endif
@@ -2586,101 +6267,99 @@
             }
         }
         /* Is opcode *REALLY* valid ? */
-                if (handler->handler == &gen_invalid) {
-            if (loglevel > 0) {
-                    fprintf(logfile, "invalid/unsupported opcode: "
-                        "%02x - %02x - %02x (%08x) 0x%08x %d\n",
-                            opc1(ctx.opcode), opc2(ctx.opcode),
+        if (unlikely(handler->handler == &gen_invalid)) {
+            if (loglevel != 0) {
+                fprintf(logfile, "invalid/unsupported opcode: "
+                        "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
+                        opc1(ctx.opcode), opc2(ctx.opcode),
                         opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
             } else {
                 printf("invalid/unsupported opcode: "
-                       "%02x - %02x - %02x (%08x) 0x%08x %d\n",
+                       "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
                        opc1(ctx.opcode), opc2(ctx.opcode),
                        opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
             }
-                } else {
-            if ((ctx.opcode & handler->inval) != 0) {
-                if (loglevel > 0) {
+        } else {
+            if (unlikely((ctx.opcode & handler->inval) != 0)) {
+                if (loglevel != 0) {
                     fprintf(logfile, "invalid bits: %08x for opcode: "
-                            "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
+                            "%02x - %02x - %02x (%08x) 0x" ADDRX "\n",
                             ctx.opcode & handler->inval, opc1(ctx.opcode),
                             opc2(ctx.opcode), opc3(ctx.opcode),
                             ctx.opcode, ctx.nip - 4);
                 } else {
                     printf("invalid bits: %08x for opcode: "
-                           "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
-                            ctx.opcode & handler->inval, opc1(ctx.opcode),
-                            opc2(ctx.opcode), opc3(ctx.opcode),
+                           "%02x - %02x - %02x (%08x) 0x" ADDRX "\n",
+                           ctx.opcode & handler->inval, opc1(ctx.opcode),
+                           opc2(ctx.opcode), opc3(ctx.opcode),
                            ctx.opcode, ctx.nip - 4);
-            }
-                RET_INVAL(ctxp);
+                }
+                GEN_EXCP_INVAL(ctxp);
                 break;
             }
         }
         (*(handler->handler))(&ctx);
+#if defined(DO_PPC_STATISTICS)
+        handler->count++;
+#endif
         /* Check trace mode exceptions */
-        if ((msr_be && ctx.exception == EXCP_BRANCH) ||
-            /* Check in single step trace mode
-             * we need to stop except if:
-             * - rfi, trap or syscall
-             * - first instruction of an exception handler
-             */
-            (msr_se && (ctx.nip < 0x100 ||
-                        ctx.nip > 0xF00 ||
-                        (ctx.nip & 0xFC) != 0x04) &&
-             ctx.exception != EXCP_SYSCALL &&
-             ctx.exception != EXCP_SYSCALL_USER &&
-             ctx.exception != EXCP_TRAP)) {
-            RET_EXCP(ctxp, EXCP_TRACE, 0);
+#if 0 // XXX: buggy on embedded PowerPC
+        if (unlikely((msr_be && ctx.exception == POWERPC_EXCP_BRANCH) ||
+                     /* Check in single step trace mode
+                      * we need to stop except if:
+                      * - rfi, trap or syscall
+                      * - first instruction of an exception handler
+                      */
+                     (msr_se && (ctx.nip < 0x100 ||
+                                 ctx.nip > 0xF00 ||
+                                 (ctx.nip & 0xFC) != 0x04) &&
+#if defined(CONFIG_USER_ONLY)
+                      ctx.exception != POWERPC_EXCP_SYSCALL_USER &&
+#else
+                      ctx.exception != POWERPC_EXCP_SYSCALL &&
+#endif
+                      ctx.exception != POWERPC_EXCP_TRAP))) {
+            GEN_EXCP(ctxp, POWERPC_EXCP_TRACE, 0);
         }
-
+#endif
         /* if we reach a page boundary or are single stepping, stop
          * generation
          */
-        if (((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
-            (env->singlestep_enabled)) {
+        if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
+                     (env->singlestep_enabled))) {
             break;
-    }
+        }
 #if defined (DO_SINGLE_STEP)
         break;
 #endif
     }
-    if (ctx.exception == EXCP_NONE) {
+    if (ctx.exception == POWERPC_EXCP_NONE) {
         gen_goto_tb(&ctx, 0, ctx.nip);
-    } else if (ctx.exception != EXCP_BRANCH) {
-        gen_op_set_T0(0);
+    } else if (ctx.exception != POWERPC_EXCP_BRANCH) {
+        gen_op_reset_T0();
+        /* Generate the return instruction */
+        gen_op_exit_tb();
     }
-#if 1
-    /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
-     *              do bad business and then qemu crashes !
-     */
-    gen_op_set_T0(0);
-#endif
-    /* Generate the return instruction */
-    gen_op_exit_tb();
     *gen_opc_ptr = INDEX_op_end;
-    if (search_pc) {
+    if (unlikely(search_pc)) {
         j = gen_opc_ptr - gen_opc_buf;
         lj++;
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
-        tb->size = 0;
-#if 0
-        if (loglevel > 0) {
-            page_dump(logfile);
-        }
-#endif
     } else {
         tb->size = ctx.nip - pc_start;
     }
-#ifdef DEBUG_DISAS
+#if defined(DEBUG_DISAS)
     if (loglevel & CPU_LOG_TB_CPU) {
         fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
         cpu_dump_state(env, logfile, fprintf, 0);
     }
     if (loglevel & CPU_LOG_TB_IN_ASM) {
+        int flags;
+        flags = env->bfd_mach;
+        flags |= msr_le << 16;
         fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-	target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
+        target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
         fprintf(logfile, "\n");
     }
     if (loglevel & CPU_LOG_TB_OP) {
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index ddf0c91..88d67d9 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -1,7 +1,7 @@
 /*
  *  PowerPC CPU initialization for qemu.
- * 
- *  Copyright (c) 2003-2005 Jocelyn Mayer
+ *
+ *  Copyright (c) 2003-2007 Jocelyn Mayer
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -23,21 +23,55 @@
  * inside "#if defined(TODO) ... #endif" statements to make tests easier.
  */
 
+#include "dis-asm.h"
+
 //#define PPC_DUMP_CPU
 //#define PPC_DEBUG_SPR
+//#define PPC_DEBUG_IRQ
 
 struct ppc_def_t {
     const unsigned char *name;
     uint32_t pvr;
     uint32_t pvr_mask;
-    uint32_t insns_flags;
-    uint32_t flags;
+    uint64_t insns_flags;
     uint64_t msr_mask;
+    uint8_t mmu_model;
+    uint8_t excp_model;
+    uint8_t bus_model;
+    uint8_t pad;
+    int bfd_mach;
+    void (*init_proc)(CPUPPCState *env);
 };
 
+/* For user-mode emulation, we don't emulate any IRQ controller */
+#if defined(CONFIG_USER_ONLY)
+#define PPC_IRQ_INIT_FN(name)                                                 \
+static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env)         \
+{                                                                             \
+}
+#else
+#define PPC_IRQ_INIT_FN(name)                                                 \
+void glue(glue(ppc, name),_irq_init) (CPUPPCState *env);
+#endif
+
+PPC_IRQ_INIT_FN(40x);
+PPC_IRQ_INIT_FN(6xx);
+PPC_IRQ_INIT_FN(970);
+
 /* Generic callbacks:
  * do nothing but store/retrieve spr value
  */
+#ifdef PPC_DUMP_SPR_ACCESSES
+static void spr_read_generic (void *opaque, int sprn)
+{
+    gen_op_load_dump_spr(sprn);
+}
+
+static void spr_write_generic (void *opaque, int sprn)
+{
+    gen_op_store_dump_spr(sprn);
+}
+#else
 static void spr_read_generic (void *opaque, int sprn)
 {
     gen_op_load_spr(sprn);
@@ -47,8 +81,16 @@
 {
     gen_op_store_spr(sprn);
 }
+#endif
 
-/* SPR common to all PPC */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_clear (void *opaque, int sprn)
+{
+    gen_op_mask_spr(sprn);
+}
+#endif
+
+/* SPR common to all PowerPC */
 /* XER */
 static void spr_read_xer (void *opaque, int sprn)
 {
@@ -93,8 +135,9 @@
     gen_op_load_spr(sprn + 0x10);
 }
 
-/* SPR common to all non-embedded PPC (ie not 4xx) */
+/* SPR common to all non-embedded PowerPC */
 /* DECR */
+#if !defined(CONFIG_USER_ONLY)
 static void spr_read_decr (void *opaque, int sprn)
 {
     gen_op_load_decr();
@@ -104,29 +147,57 @@
 {
     gen_op_store_decr();
 }
+#endif
 
-/* SPR common to all non-embedded PPC, except 601 */
+/* SPR common to all non-embedded PowerPC, except 601 */
 /* Time base */
 static void spr_read_tbl (void *opaque, int sprn)
 {
     gen_op_load_tbl();
 }
 
-static void spr_write_tbl (void *opaque, int sprn)
-{
-    gen_op_store_tbl();
-}
-
 static void spr_read_tbu (void *opaque, int sprn)
 {
     gen_op_load_tbu();
 }
 
+__attribute__ (( unused ))
+static void spr_read_atbl (void *opaque, int sprn)
+{
+    gen_op_load_atbl();
+}
+
+__attribute__ (( unused ))
+static void spr_read_atbu (void *opaque, int sprn)
+{
+    gen_op_load_atbu();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_tbl (void *opaque, int sprn)
+{
+    gen_op_store_tbl();
+}
+
 static void spr_write_tbu (void *opaque, int sprn)
 {
     gen_op_store_tbu();
 }
 
+__attribute__ (( unused ))
+static void spr_write_atbl (void *opaque, int sprn)
+{
+    gen_op_store_atbl();
+}
+
+__attribute__ (( unused ))
+static void spr_write_atbu (void *opaque, int sprn)
+{
+    gen_op_store_atbu();
+}
+#endif
+
+#if !defined(CONFIG_USER_ONLY)
 /* IBAT0U...IBAT0U */
 /* IBAT0L...IBAT7L */
 static void spr_read_ibat (void *opaque, int sprn)
@@ -141,34 +212,22 @@
 
 static void spr_write_ibatu (void *opaque, int sprn)
 {
-    DisasContext *ctx = opaque;
-
     gen_op_store_ibatu((sprn - SPR_IBAT0U) / 2);
-    RET_STOP(ctx);
 }
 
 static void spr_write_ibatu_h (void *opaque, int sprn)
 {
-    DisasContext *ctx = opaque;
-
     gen_op_store_ibatu((sprn - SPR_IBAT4U) / 2);
-    RET_STOP(ctx);
 }
 
 static void spr_write_ibatl (void *opaque, int sprn)
 {
-    DisasContext *ctx = opaque;
-
     gen_op_store_ibatl((sprn - SPR_IBAT0L) / 2);
-    RET_STOP(ctx);
 }
 
 static void spr_write_ibatl_h (void *opaque, int sprn)
 {
-    DisasContext *ctx = opaque;
-
     gen_op_store_ibatl((sprn - SPR_IBAT4L) / 2);
-    RET_STOP(ctx);
 }
 
 /* DBAT0U...DBAT7U */
@@ -185,34 +244,22 @@
 
 static void spr_write_dbatu (void *opaque, int sprn)
 {
-    DisasContext *ctx = opaque;
-
     gen_op_store_dbatu((sprn - SPR_DBAT0U) / 2);
-    RET_STOP(ctx);
 }
 
 static void spr_write_dbatu_h (void *opaque, int sprn)
 {
-    DisasContext *ctx = opaque;
-
     gen_op_store_dbatu((sprn - SPR_DBAT4U) / 2);
-    RET_STOP(ctx);
 }
 
 static void spr_write_dbatl (void *opaque, int sprn)
 {
-    DisasContext *ctx = opaque;
-
     gen_op_store_dbatl((sprn - SPR_DBAT0L) / 2);
-    RET_STOP(ctx);
 }
 
 static void spr_write_dbatl_h (void *opaque, int sprn)
 {
-    DisasContext *ctx = opaque;
-
     gen_op_store_dbatl((sprn - SPR_DBAT4L) / 2);
-    RET_STOP(ctx);
 }
 
 /* SDR1 */
@@ -223,17 +270,162 @@
 
 static void spr_write_sdr1 (void *opaque, int sprn)
 {
+    gen_op_store_sdr1();
+}
+
+/* 64 bits PowerPC specific SPRs */
+/* ASR */
+#if defined(TARGET_PPC64)
+__attribute__ (( unused ))
+static void spr_read_asr (void *opaque, int sprn)
+{
+    gen_op_load_asr();
+}
+
+__attribute__ (( unused ))
+static void spr_write_asr (void *opaque, int sprn)
+{
+    gen_op_store_asr();
+}
+#endif
+#endif
+
+/* PowerPC 601 specific registers */
+/* RTC */
+static void spr_read_601_rtcl (void *opaque, int sprn)
+{
+    gen_op_load_601_rtcl();
+}
+
+static void spr_read_601_rtcu (void *opaque, int sprn)
+{
+    gen_op_load_601_rtcu();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_601_rtcu (void *opaque, int sprn)
+{
+    gen_op_store_601_rtcu();
+}
+
+static void spr_write_601_rtcl (void *opaque, int sprn)
+{
+    gen_op_store_601_rtcl();
+}
+#endif
+
+/* Unified bats */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_601_ubat (void *opaque, int sprn)
+{
+    gen_op_load_601_bat(sprn & 1, (sprn - SPR_IBAT0U) / 2);
+}
+
+static void spr_write_601_ubatu (void *opaque, int sprn)
+{
+    gen_op_store_601_batu((sprn - SPR_IBAT0U) / 2);
+}
+
+static void spr_write_601_ubatl (void *opaque, int sprn)
+{
+    gen_op_store_601_batl((sprn - SPR_IBAT0L) / 2);
+}
+#endif
+
+/* PowerPC 40x specific registers */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_40x_pit (void *opaque, int sprn)
+{
+    gen_op_load_40x_pit();
+}
+
+static void spr_write_40x_pit (void *opaque, int sprn)
+{
+    gen_op_store_40x_pit();
+}
+
+static void spr_write_40x_dbcr0 (void *opaque, int sprn)
+{
     DisasContext *ctx = opaque;
 
-    gen_op_store_sdr1();
-    RET_STOP(ctx);
+    gen_op_store_40x_dbcr0();
+    /* We must stop translation as we may have rebooted */
+    GEN_STOP(ctx);
+}
+
+static void spr_write_40x_sler (void *opaque, int sprn)
+{
+    gen_op_store_40x_sler();
+}
+
+static void spr_write_booke_tcr (void *opaque, int sprn)
+{
+    gen_op_store_booke_tcr();
+}
+
+static void spr_write_booke_tsr (void *opaque, int sprn)
+{
+    gen_op_store_booke_tsr();
+}
+#endif
+
+/* PowerPC 403 specific registers */
+/* PBL1 / PBU1 / PBL2 / PBU2 */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_403_pbr (void *opaque, int sprn)
+{
+    gen_op_load_403_pb(sprn - SPR_403_PBL1);
+}
+
+static void spr_write_403_pbr (void *opaque, int sprn)
+{
+    gen_op_store_403_pb(sprn - SPR_403_PBL1);
 }
 
 static void spr_write_pir (void *opaque, int sprn)
 {
     gen_op_store_pir();
 }
+#endif
 
+#if !defined(CONFIG_USER_ONLY)
+/* Callback used to write the exception vector base */
+static void spr_write_excp_prefix (void *opaque, int sprn)
+{
+    gen_op_store_excp_prefix();
+    gen_op_store_spr(sprn);
+}
+
+static void spr_write_excp_vector (void *opaque, int sprn)
+{
+    DisasContext *ctx = opaque;
+
+    if (sprn >= SPR_BOOKE_IVOR0 && sprn <= SPR_BOOKE_IVOR15) {
+        gen_op_store_excp_vector(sprn - SPR_BOOKE_IVOR0);
+        gen_op_store_spr(sprn);
+    } else if (sprn >= SPR_BOOKE_IVOR32 && sprn <= SPR_BOOKE_IVOR37) {
+        gen_op_store_excp_vector(sprn - SPR_BOOKE_IVOR32 + 32);
+        gen_op_store_spr(sprn);
+    } else {
+        printf("Trying to write an unknown exception vector %d %03x\n",
+               sprn, sprn);
+        GEN_EXCP_PRIVREG(ctx);
+    }
+}
+#endif
+
+#if defined(CONFIG_USER_ONLY)
+#define spr_register(env, num, name, uea_read, uea_write,                     \
+                     oea_read, oea_write, initial_value)                      \
+do {                                                                          \
+     _spr_register(env, num, name, uea_read, uea_write, initial_value);       \
+} while (0)
+static inline void _spr_register (CPUPPCState *env, int num,
+                                  const unsigned char *name,
+                                  void (*uea_read)(void *opaque, int sprn),
+                                  void (*uea_write)(void *opaque, int sprn),
+                                  target_ulong initial_value)
+#else
 static inline void spr_register (CPUPPCState *env, int num,
                                  const unsigned char *name,
                                  void (*uea_read)(void *opaque, int sprn),
@@ -241,25 +433,30 @@
                                  void (*oea_read)(void *opaque, int sprn),
                                  void (*oea_write)(void *opaque, int sprn),
                                  target_ulong initial_value)
+#endif
 {
     ppc_spr_t *spr;
 
     spr = &env->spr_cb[num];
     if (spr->name != NULL ||env-> spr[num] != 0x00000000 ||
-        spr->uea_read != NULL || spr->uea_write != NULL ||
-        spr->oea_read != NULL || spr->oea_write != NULL) {
+#if !defined(CONFIG_USER_ONLY)
+        spr->oea_read != NULL || spr->oea_write != NULL ||
+#endif
+        spr->uea_read != NULL || spr->uea_write != NULL) {
         printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num);
         exit(1);
     }
 #if defined(PPC_DEBUG_SPR)
-    printf("*** register spr %d (%03x) %s val %08" PRIx64 "\n", num, num, name,
-           (unsigned long long)initial_value);
+    printf("*** register spr %d (%03x) %s val " ADDRX "\n", num, num, name,
+           initial_value);
 #endif
     spr->name = name;
     spr->uea_read = uea_read;
     spr->uea_write = uea_write;
+#if !defined(CONFIG_USER_ONLY)
     spr->oea_read = oea_read;
     spr->oea_write = oea_write;
+#endif
     env->spr[num] = initial_value;
 }
 
@@ -399,7 +596,7 @@
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_dbat, &spr_write_dbatl,
                  0x00000000);
-    env->nb_BATs = 4;
+    env->nb_BATs += 4;
 }
 
 /* BATs 4-7 */
@@ -469,7 +666,7 @@
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_dbat_h, &spr_write_dbatl_h,
                  0x00000000);
-    env->nb_BATs = 8;
+    env->nb_BATs += 4;
 }
 
 /* Generic PowerPC time base */
@@ -493,6 +690,70 @@
                  0x00000000);
 }
 
+/* Softare table search registers */
+static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
+{
+    env->nb_tlb = nb_tlbs;
+    env->nb_ways = nb_ways;
+    env->id_tlbs = 1;
+    spr_register(env, SPR_DMISS, "DMISS",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_DCMP, "DCMP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_HASH1, "HASH1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_HASH2, "HASH2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_IMISS, "IMISS",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_ICMP, "ICMP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_RPA, "RPA",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR common to MPC755 and G2 */
+static void gen_spr_G2_755 (CPUPPCState *env)
+{
+    /* SGPRs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
 /* SPR common to all 7xx PowerPC implementations */
 static void gen_spr_7xx (CPUPPCState *env)
 {
@@ -513,6 +774,11 @@
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2CR, "L2CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
     /* Performance monitors */
     /* XXX : not implemented */
     spr_register(env, SPR_MMCR0, "MMCR0",
@@ -545,38 +811,55 @@
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
     /* XXX : not implemented */
-    spr_register(env, SPR_SIA, "SIA",
+    spr_register(env, SPR_SIAR, "SIAR",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, SPR_NOACCESS,
                  0x00000000);
+    /* XXX : not implemented */
     spr_register(env, SPR_UMMCR0, "UMMCR0",
                  &spr_read_ureg, SPR_NOACCESS,
                  &spr_read_ureg, SPR_NOACCESS,
                  0x00000000);
+    /* XXX : not implemented */
     spr_register(env, SPR_UMMCR1, "UMMCR1",
                  &spr_read_ureg, SPR_NOACCESS,
                  &spr_read_ureg, SPR_NOACCESS,
                  0x00000000);
+    /* XXX : not implemented */
     spr_register(env, SPR_UPMC1, "UPMC1",
                  &spr_read_ureg, SPR_NOACCESS,
                  &spr_read_ureg, SPR_NOACCESS,
                  0x00000000);
+    /* XXX : not implemented */
     spr_register(env, SPR_UPMC2, "UPMC2",
                  &spr_read_ureg, SPR_NOACCESS,
                  &spr_read_ureg, SPR_NOACCESS,
                  0x00000000);
+    /* XXX : not implemented */
     spr_register(env, SPR_UPMC3, "UPMC3",
                  &spr_read_ureg, SPR_NOACCESS,
                  &spr_read_ureg, SPR_NOACCESS,
                  0x00000000);
+    /* XXX : not implemented */
     spr_register(env, SPR_UPMC4, "UPMC4",
                  &spr_read_ureg, SPR_NOACCESS,
                  &spr_read_ureg, SPR_NOACCESS,
                  0x00000000);
-    spr_register(env, SPR_USIA, "USIA",
+    /* XXX : not implemented */
+    spr_register(env, SPR_USIAR, "USIAR",
                  &spr_read_ureg, SPR_NOACCESS,
                  &spr_read_ureg, SPR_NOACCESS,
                  0x00000000);
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_spr_thrm (CPUPPCState *env)
+{
     /* Thermal management */
     /* XXX : not implemented */
     spr_register(env, SPR_THRM1, "THRM1",
@@ -593,12 +876,6 @@
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
-    /* External access control */
-    /* XXX : not implemented */
-    spr_register(env, SPR_EAR, "EAR",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                 &spr_read_generic, &spr_write_generic,
-                 0x00000000);
 }
 
 /* SPR specific to PowerPC 604 implementation */
@@ -652,7 +929,7 @@
                  &spr_read_generic, &spr_write_generic,
                  0x00000000);
     /* XXX : not implemented */
-    spr_register(env, SPR_SIA, "SIA",
+    spr_register(env, SPR_SIAR, "SIAR",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, SPR_NOACCESS,
                  0x00000000);
@@ -669,159 +946,4619 @@
                  0x00000000);
 }
 
-// XXX: TODO (64 bits PPC sprs)
+/* SPR specific to PowerPC 603 implementation */
+static void gen_spr_603 (CPUPPCState *env)
+{
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC G2 implementation */
+static void gen_spr_G2 (CPUPPCState *env)
+{
+    /* Memory base address */
+    /* MBAR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MBAR, "MBAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* System version register */
+    /* SVR */
+    /* XXX : TODO: initialize it to an appropriate value */
+    spr_register(env, SPR_SVR, "SVR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* Exception processing */
+    spr_register(env, SPR_BOOKE_CSRR0, "CSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_CSRR1, "CSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Breakpoints */
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR, "DABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DABR2, "DABR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR2, "IABR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IBCR, "IBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DBCR, "DBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 602 implementation */
+static void gen_spr_602 (CPUPPCState *env)
+{
+    /* ESA registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_SER, "SER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_SEBR, "SEBR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_ESASRR, "ESASRR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Floating point status */
+    /* XXX : not implemented */
+    spr_register(env, SPR_SP, "SP",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_LT, "LT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Watchdog timer */
+    /* XXX : not implemented */
+    spr_register(env, SPR_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Interrupt base */
+    spr_register(env, SPR_IBR, "IBR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 601 implementation */
+static void gen_spr_601 (CPUPPCState *env)
+{
+    /* Multiplication/division register */
+    /* MQ */
+    spr_register(env, SPR_MQ, "MQ",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* RTC registers */
+    spr_register(env, SPR_601_RTCU, "RTCU",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_601_rtcu,
+                 0x00000000);
+    spr_register(env, SPR_601_VRTCU, "RTCU",
+                 &spr_read_601_rtcu, SPR_NOACCESS,
+                 &spr_read_601_rtcu, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_601_RTCL, "RTCL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_601_rtcl,
+                 0x00000000);
+    spr_register(env, SPR_601_VRTCL, "RTCL",
+                 &spr_read_601_rtcl, SPR_NOACCESS,
+                 &spr_read_601_rtcl, SPR_NOACCESS,
+                 0x00000000);
+    /* Timer */
+#if 0 /* ? */
+    spr_register(env, SPR_601_UDECR, "UDECR",
+                 &spr_read_decr, SPR_NOACCESS,
+                 &spr_read_decr, SPR_NOACCESS,
+                 0x00000000);
+#endif
+    /* External access control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_EAR, "EAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    spr_register(env, SPR_IBAT0U, "IBAT0U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT0L, "IBAT0L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1U, "IBAT1U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT1L, "IBAT1L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2U, "IBAT2U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT2L, "IBAT2L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3U, "IBAT3U",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatu,
+                 0x00000000);
+    spr_register(env, SPR_IBAT3L, "IBAT3L",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_601_ubat, &spr_write_601_ubatl,
+                 0x00000000);
+    env->nb_BATs = 4;
+}
+
+static void gen_spr_74xx (CPUPPCState *env)
+{
+    /* Processor identification */
+    spr_register(env, SPR_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MMCR2, "MMCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UMMCR2, "UMMCR2",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX: not implemented */
+    spr_register(env, SPR_BAMR, "BAMR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UBAMR, "UBAMR",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSCR0, "MSSCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Altivec */
+    spr_register(env, SPR_VRSAVE, "VRSAVE",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_l3_ctrl (CPUPPCState *env)
+{
+    /* L3CR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3CR, "L3CR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR0, "L3ITCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR1 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR1, "L3ITCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR2 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR2, "L3ITCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3ITCR3 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3ITCR3, "L3ITCR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3OHCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3OHCR, "L3OHCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* L3PM */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L3PM, "L3PM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_74xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
+{
+    env->nb_tlb = nb_tlbs;
+    env->nb_ways = nb_ways;
+    env->id_tlbs = 1;
+    /* XXX : not implemented */
+    spr_register(env, SPR_PTEHI, "PTEHI",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PTELO, "PTELO",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_TLBMISS, "TLBMISS",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* PowerPC BookE SPR */
+static void gen_spr_BookE (CPUPPCState *env)
+{
+    /* Processor identification */
+    spr_register(env, SPR_BOOKE_PIR, "PIR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_pir,
+                 0x00000000);
+    /* Interrupt processing */
+    spr_register(env, SPR_BOOKE_CSRR0, "CSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_CSRR1, "CSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#if 0
+    spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_DSRR1, "DSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+#endif
+    /* Debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC1, "IAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DAC1, "DAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR0, "DBCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR1, "DBCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBCR2, "DBCR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_DEAR, "DEAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_ESR, "ESR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVPR, "IVPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_prefix,
+                 0x00000000);
+    /* Exception vectors */
+    spr_register(env, SPR_BOOKE_IVOR0, "IVOR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR1, "IVOR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR2, "IVOR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR3, "IVOR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR4, "IVOR4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR5, "IVOR5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR6, "IVOR6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR7, "IVOR7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR8, "IVOR8",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR9, "IVOR9",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR10, "IVOR10",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR11, "IVOR11",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR12, "IVOR12",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR13, "IVOR13",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR14, "IVOR14",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR15, "IVOR15",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+#if 0
+    spr_register(env, SPR_BOOKE_IVOR32, "IVOR32",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR33, "IVOR33",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR34, "IVOR34",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR35, "IVOR35",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR36, "IVOR36",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_IVOR37, "IVOR37",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_vector,
+                 0x00000000);
+#endif
+    spr_register(env, SPR_BOOKE_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tcr,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_TSR, "TSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tsr,
+                 0x00000000);
+    /* Timer */
+    spr_register(env, SPR_DECR, "DECR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_decr, &spr_write_decr,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_DECAR, "DECAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_generic,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_USPRG0, "USPRG0",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+}
+
+/* FSL storage control registers */
+static void gen_spr_BookE_FSL (CPUPPCState *env)
+{
+    /* TLB assist registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MAS0, "MAS0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MAS1, "MAS2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MAS2, "MAS3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MAS3, "MAS4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MAS4, "MAS5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MAS6, "MAS6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MAS7, "MAS7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    if (env->nb_pids > 1) {
+        /* XXX : not implemented */
+        spr_register(env, SPR_BOOKE_PID1, "PID1",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+    }
+    if (env->nb_pids > 2) {
+        /* XXX : not implemented */
+        spr_register(env, SPR_BOOKE_PID2, "PID2",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, &spr_write_generic,
+                     0x00000000);
+    }
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MMUCFG, "MMUCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000); /* TOFIX */
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MMUCSR0, "MMUCSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000); /* TOFIX */
+    switch (env->nb_ways) {
+    case 4:
+        /* XXX : not implemented */
+        spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, SPR_NOACCESS,
+                     0x00000000); /* TOFIX */
+        /* Fallthru */
+    case 3:
+        /* XXX : not implemented */
+        spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, SPR_NOACCESS,
+                     0x00000000); /* TOFIX */
+        /* Fallthru */
+    case 2:
+        /* XXX : not implemented */
+        spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, SPR_NOACCESS,
+                     0x00000000); /* TOFIX */
+        /* Fallthru */
+    case 1:
+        /* XXX : not implemented */
+        spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
+                     SPR_NOACCESS, SPR_NOACCESS,
+                     &spr_read_generic, SPR_NOACCESS,
+                     0x00000000); /* TOFIX */
+        /* Fallthru */
+    case 0:
+    default:
+        break;
+    }
+}
+
+/* SPR specific to PowerPC 440 implementation */
+static void gen_spr_440 (CPUPPCState *env)
+{
+    /* Cache control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV0, "DNV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV1, "DNV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV2, "DNV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DNV3, "DNV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DTV0, "DTV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DTV1, "DTV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DTV2, "DTV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DTV3, "DTV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DVLIM, "DVLIM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV0, "INV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV1, "INV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV2, "INV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_INV3, "INV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ITV0, "ITV0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ITV1, "ITV1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ITV2, "ITV2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_ITV3, "ITV3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_IVLIM, "IVLIM",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Cache debug */
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DCDBTRH, "DCDBTRH",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_DCDBTRL, "DCDBTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_ICDBTRH, "ICDBTRH",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_ICDBTRL, "ICDBTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_DBDR, "DBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Processor control */
+    spr_register(env, SPR_4xx_CCR0, "CCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_440_RSTCFG, "RSTCFG",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* Storage control */
+    spr_register(env, SPR_440_MMUCR, "MMUCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR shared between PowerPC 40x implementations */
+static void gen_spr_40x (CPUPPCState *env)
+{
+    /* Cache */
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_DCCR, "DCCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_ICCR, "ICCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_BOOKE_ICDBDR, "ICDBDR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, SPR_NOACCESS,
+                 0x00000000);
+    /* Exception */
+    spr_register(env, SPR_40x_DEAR, "DEAR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_ESR, "ESR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_EVPR, "EVPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_excp_prefix,
+                 0x00000000);
+    spr_register(env, SPR_40x_SRR2, "SRR2",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_SRR3, "SRR3",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Timers */
+    spr_register(env, SPR_40x_PIT, "PIT",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_40x_pit, &spr_write_40x_pit,
+                 0x00000000);
+    spr_register(env, SPR_40x_TCR, "TCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tcr,
+                 0x00000000);
+    spr_register(env, SPR_40x_TSR, "TSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_booke_tsr,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 405 implementation */
+static void gen_spr_405 (CPUPPCState *env)
+{
+    /* MMU */
+    spr_register(env, SPR_40x_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_4xx_CCR0, "CCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00700000);
+    /* Debug interface */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBCR0, "DBCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_dbcr0,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DBCR1, "DBCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 /* Last reset was system reset */
+                 0x00000300);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC1, "DAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DVC1, "DVC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_DVC2, "DVC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC1, "IAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_IAC3, "IAC3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_IAC4, "IAC4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Storage control */
+    /* XXX: TODO: not implemented */
+    spr_register(env, SPR_405_SLER, "SLER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_sler,
+                 0x00000000);
+    spr_register(env, SPR_40x_ZPR, "ZPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_405_SU0R, "SU0R",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* SPRG */
+    spr_register(env, SPR_USPRG0, "USPRG0",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+}
+
+/* SPR shared between PowerPC 401 & 403 implementations */
+static void gen_spr_401_403 (CPUPPCState *env)
+{
+    /* Time base */
+    spr_register(env, SPR_403_VTBL,  "TBL",
+                 &spr_read_tbl, SPR_NOACCESS,
+                 &spr_read_tbl, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_403_TBL,   "TBL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_tbl,
+                 0x00000000);
+    spr_register(env, SPR_403_VTBU,  "TBU",
+                 &spr_read_tbu, SPR_NOACCESS,
+                 &spr_read_tbu, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_403_TBU,   "TBU",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 SPR_NOACCESS, &spr_write_tbu,
+                 0x00000000);
+    /* Debug */
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_403_CDBCR, "CDBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 401 implementation */
+static void gen_spr_401 (CPUPPCState *env)
+{
+    /* Debug interface */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBCR0, "DBCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_dbcr0,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 /* Last reset was system reset */
+                 0x00000300);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC1, "DAC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC1, "IAC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Storage control */
+    /* XXX: TODO: not implemented */
+    spr_register(env, SPR_405_SLER, "SLER",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_sler,
+                 0x00000000);
+    /* not emulated, as Qemu never does speculative access */
+    spr_register(env, SPR_40x_SGR, "SGR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFFFFFFF);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_DCWR, "DCWR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_spr_401x2 (CPUPPCState *env)
+{
+    gen_spr_401(env);
+    spr_register(env, SPR_40x_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_ZPR, "ZPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC 403 implementation */
+static void gen_spr_403 (CPUPPCState *env)
+{
+    /* Debug interface */
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBCR0, "DBCR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_40x_dbcr0,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DBSR, "DBSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_clear,
+                 /* Last reset was system reset */
+                 0x00000300);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC1, "DAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_DAC2, "DAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC1, "IAC1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_40x_IAC2, "IAC2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+static void gen_spr_403_real (CPUPPCState *env)
+{
+    spr_register(env, SPR_403_PBL1,  "PBL1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBU1,  "PBU1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBL2,  "PBL2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+    spr_register(env, SPR_403_PBU2,  "PBU2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_403_pbr, &spr_write_403_pbr,
+                 0x00000000);
+}
+
+static void gen_spr_403_mmu (CPUPPCState *env)
+{
+    /* MMU */
+    spr_register(env, SPR_40x_PID, "PID",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_40x_ZPR, "ZPR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+/* SPR specific to PowerPC compression coprocessor extension */
+static void gen_spr_compress (CPUPPCState *env)
+{
+    /* XXX : not implemented */
+    spr_register(env, SPR_401_SKR, "SKR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+
+#if defined (TARGET_PPC64)
+/* SPR specific to PowerPC 620 */
+static void gen_spr_620 (CPUPPCState *env)
+{
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR0, "PMR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR1, "PMR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR2, "PMR2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR3, "PMR3",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR4, "PMR4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR5, "PMR5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR6, "PMR6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR7, "PMR7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR8, "PMR8",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMR9, "PMR9",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRA, "PMR10",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRB, "PMR11",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRC, "PMR12",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRD, "PMR13",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRE, "PMR14",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_PMRF, "PMR15",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_HID8, "HID8",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_620_HID9, "HID9",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+}
+#endif /* defined (TARGET_PPC64) */
+
+// XXX: TODO
 /*
- * ASR => SPR 280 (64 bits)
- * FPECR => SPR 1022 (?)
- * VRSAVE => SPR 256 (Altivec)
- * SCOMC => SPR 276 (64 bits ?)
- * SCOMD => SPR 277 (64 bits ?)
- * HSPRG0 => SPR 304 (hypervisor)
- * HSPRG1 => SPR 305 (hypervisor)
- * HDEC => SPR 310 (hypervisor)
- * HIOR => SPR 311 (hypervisor)
- * RMOR => SPR 312 (970)
- * HRMOR => SPR 313 (hypervisor)
- * HSRR0 => SPR 314 (hypervisor)
- * HSRR1 => SPR 315 (hypervisor)
- * LPCR => SPR 316 (970)
- * LPIDR => SPR 317 (970)
+ * AMR     => SPR 29 (Power 2.04)
+ * CTRL    => SPR 136 (Power 2.04)
+ * CTRL    => SPR 152 (Power 2.04)
+ * SCOMC   => SPR 276 (64 bits ?)
+ * SCOMD   => SPR 277 (64 bits ?)
+ * TBU40   => SPR 286 (Power 2.04 hypv)
+ * HSPRG0  => SPR 304 (Power 2.04 hypv)
+ * HSPRG1  => SPR 305 (Power 2.04 hypv)
+ * HDSISR  => SPR 306 (Power 2.04 hypv)
+ * HDAR    => SPR 307 (Power 2.04 hypv)
+ * PURR    => SPR 309 (Power 2.04 hypv)
+ * HDEC    => SPR 310 (Power 2.04 hypv)
+ * HIOR    => SPR 311 (hypv)
+ * RMOR    => SPR 312 (970)
+ * HRMOR   => SPR 313 (Power 2.04 hypv)
+ * HSRR0   => SPR 314 (Power 2.04 hypv)
+ * HSRR1   => SPR 315 (Power 2.04 hypv)
+ * LPCR    => SPR 316 (970)
+ * LPIDR   => SPR 317 (970)
+ * SPEFSCR => SPR 512 (Power 2.04 emb)
+ * EPR     => SPR 702 (Power 2.04 emb)
+ * perf    => 768-783 (Power 2.04)
+ * perf    => 784-799 (Power 2.04)
+ * PPR     => SPR 896 (Power 2.04)
+ * EPLC    => SPR 947 (Power 2.04 emb)
+ * EPSC    => SPR 948 (Power 2.04 emb)
+ * DABRX   => 1015    (Power 2.04 hypv)
+ * FPECR   => SPR 1022 (?)
  * ... and more (thermal management, performance counters, ...)
  */
 
+/*****************************************************************************/
+/* Exception vectors models                                                  */
+static void init_excp_4xx_real (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
+    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
+    env->excp_prefix = 0x00000000;
+    env->ivor_mask = 0x0000FFF0;
+    env->ivpr_mask = 0xFFFF0000;
+#endif
+}
+
+static void init_excp_4xx_softmmu (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_PIT]      = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00001010;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001020;
+    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00002000;
+    env->excp_prefix = 0x00000000;
+    env->ivor_mask = 0x0000FFF0;
+    env->ivpr_mask = 0xFFFF0000;
+#endif
+}
+
+static void init_excp_BookE (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_APU]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_FIT]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DTLB]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_ITLB]     = 0x00000000;
+    env->excp_vectors[POWERPC_EXCP_DEBUG]    = 0x00000000;
+    env->excp_prefix = 0x00000000;
+    env->ivor_mask = 0x0000FFE0;
+    env->ivpr_mask = 0xFFFF0000;
+#endif
+}
+
+static void init_excp_601 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_IO]       = 0x00000A00;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_RUNM]     = 0x00002000;
+    env->excp_prefix = 0xFFF00000;
+#endif
+}
+
+static void init_excp_602 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_WDT]      = 0x00001500;
+    env->excp_vectors[POWERPC_EXCP_EMUL]     = 0x00001600;
+    env->excp_prefix = 0xFFF00000;
+#endif
+}
+
+static void init_excp_603 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+#endif
+}
+
+static void init_excp_G2 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_CRITICAL] = 0x00000A00;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+#endif
+}
+
+static void init_excp_604 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+#endif
+}
+
+#if defined(TARGET_PPC64)
+static void init_excp_620 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_FPA]      = 0x00000E00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+#endif
+}
+#endif /* defined(TARGET_PPC64) */
+
+static void init_excp_7x0 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+#endif
+}
+
+static void init_excp_750FX (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+#endif
+}
+
+static void init_excp_7400 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001700;
+#endif
+}
+
+static void init_excp_7450 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IFTLB]    = 0x00001000;
+    env->excp_vectors[POWERPC_EXCP_DLTLB]    = 0x00001100;
+    env->excp_vectors[POWERPC_EXCP_DSTLB]    = 0x00001200;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_SMI]      = 0x00001400;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001600;
+#endif
+}
+
+#if defined (TARGET_PPC64)
+static void init_excp_970 (CPUPPCState *env)
+{
+#if !defined(CONFIG_USER_ONLY)
+    env->excp_vectors[POWERPC_EXCP_RESET]    = 0x00000100;
+    env->excp_vectors[POWERPC_EXCP_MCHECK]   = 0x00000200;
+    env->excp_vectors[POWERPC_EXCP_DSI]      = 0x00000300;
+    env->excp_vectors[POWERPC_EXCP_DSEG]     = 0x00000380;
+    env->excp_vectors[POWERPC_EXCP_ISI]      = 0x00000400;
+    env->excp_vectors[POWERPC_EXCP_ISEG]     = 0x00000480;
+    env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
+    env->excp_vectors[POWERPC_EXCP_ALIGN]    = 0x00000600;
+    env->excp_vectors[POWERPC_EXCP_PROGRAM]  = 0x00000700;
+    env->excp_vectors[POWERPC_EXCP_FPU]      = 0x00000800;
+    env->excp_vectors[POWERPC_EXCP_DECR]     = 0x00000900;
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+    env->excp_vectors[POWERPC_EXCP_HDECR]    = 0x00000980;
+#endif
+    env->excp_vectors[POWERPC_EXCP_SYSCALL]  = 0x00000C00;
+    env->excp_vectors[POWERPC_EXCP_TRACE]    = 0x00000D00;
+    env->excp_vectors[POWERPC_EXCP_PERFM]    = 0x00000F00;
+    env->excp_vectors[POWERPC_EXCP_VPU]      = 0x00000F20;
+    env->excp_vectors[POWERPC_EXCP_IABR]     = 0x00001300;
+    env->excp_vectors[POWERPC_EXCP_MAINT]    = 0x00001600;
+    env->excp_vectors[POWERPC_EXCP_VPUA]     = 0x00001700;
+    env->excp_vectors[POWERPC_EXCP_THERM]    = 0x00001800;
+#endif
+}
+#endif
+
+/*****************************************************************************/
+/* PowerPC implementations definitions                                       */
+
+/* PowerPC 40x instruction set                                               */
+#define POWERPC_INSNS_EMB    (PPC_INSNS_BASE | PPC_EMB_COMMON)
+
+/* PowerPC 401                                                               */
+#define POWERPC_INSNS_401    (POWERPC_INSNS_EMB |                             \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT)
+#define POWERPC_MSRM_401     (0x00000000000FD201ULL)
+#define POWERPC_MMU_401      (POWERPC_MMU_REAL_4xx)
+#define POWERPC_EXCP_401     (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_401    (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_401     (bfd_mach_ppc_403)
+
+static void init_proc_401 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_401(env);
+    init_excp_4xx_real(env);
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 401x2                                                             */
+#define POWERPC_INSNS_401x2  (POWERPC_INSNS_EMB |                             \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_CACHE_DCBA | PPC_MFTB |                     \
+                              PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT)
+#define POWERPC_MSRM_401x2   (0x00000000001FD231ULL)
+#define POWERPC_MMU_401x2    (POWERPC_MMU_SOFT_4xx_Z)
+#define POWERPC_EXCP_401x2   (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_401x2  (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_401x2   (bfd_mach_ppc_403)
+
+static void init_proc_401x2 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_401x2(env);
+    gen_spr_compress(env);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_4xx_softmmu(env);
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 401x3                                                             */
+#define POWERPC_INSNS_401x3  (POWERPC_INSNS_EMB |                             \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_CACHE_DCBA | PPC_MFTB |                     \
+                              PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT)
+#define POWERPC_MSRM_401x3   (0x00000000001FD631ULL)
+#define POWERPC_MMU_401x3    (POWERPC_MMU_SOFT_4xx_Z)
+#define POWERPC_EXCP_401x3   (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_401x3  (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_401x3   (bfd_mach_ppc_403)
+
+__attribute__ (( unused ))
+static void init_proc_401x3 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_401(env);
+    gen_spr_401x2(env);
+    gen_spr_compress(env);
+    init_excp_4xx_softmmu(env);
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* IOP480                                                                    */
+#define POWERPC_INSNS_IOP480 (POWERPC_INSNS_EMB |                             \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_CACHE_DCBA |                                \
+                              PPC_4xx_COMMON | PPC_40x_EXCP |  PPC_40x_ICBT)
+#define POWERPC_MSRM_IOP480  (0x00000000001FD231ULL)
+#define POWERPC_MMU_IOP480   (POWERPC_MMU_SOFT_4xx_Z)
+#define POWERPC_EXCP_IOP480  (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_IOP480 (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_IOP480  (bfd_mach_ppc_403)
+
+static void init_proc_IOP480 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_401x2(env);
+    gen_spr_compress(env);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_4xx_softmmu(env);
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 403                                                               */
+#define POWERPC_INSNS_403    (POWERPC_INSNS_EMB |                             \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT)
+#define POWERPC_MSRM_403     (0x000000000007D00DULL)
+#define POWERPC_MMU_403      (POWERPC_MMU_REAL_4xx)
+#define POWERPC_EXCP_403     (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_403    (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_403     (bfd_mach_ppc_403)
+
+static void init_proc_403 (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_403(env);
+    gen_spr_403_real(env);
+    init_excp_4xx_real(env);
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 403 GCX                                                           */
+#define POWERPC_INSNS_403GCX (POWERPC_INSNS_EMB |                             \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO |                  \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT)
+#define POWERPC_MSRM_403GCX  (0x000000000007D00DULL)
+#define POWERPC_MMU_403GCX   (POWERPC_MMU_SOFT_4xx_Z)
+#define POWERPC_EXCP_403GCX  (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_403GCX (PPC_FLAGS_INPUT_401)
+#define POWERPC_BFDM_403GCX  (bfd_mach_ppc_403)
+
+static void init_proc_403GCX (CPUPPCState *env)
+{
+    gen_spr_40x(env);
+    gen_spr_401_403(env);
+    gen_spr_403(env);
+    gen_spr_403_real(env);
+    gen_spr_403_mmu(env);
+    /* Bus access control */
+    /* not emulated, as Qemu never does speculative access */
+    spr_register(env, SPR_40x_SGR, "SGR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFFFFFFF);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_DCWR, "DCWR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_4xx_softmmu(env);
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 405                                                               */
+#define POWERPC_INSNS_405    (POWERPC_INSNS_EMB | PPC_MFTB |                  \
+                              PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_CACHE_DCBA | \
+                              PPC_40x_TLB | PPC_MEM_TLBIA | PPC_MEM_TLBSYNC | \
+                              PPC_4xx_COMMON | PPC_40x_EXCP | PPC_40x_ICBT |  \
+                              PPC_405_MAC)
+#define POWERPC_MSRM_405     (0x000000000006E630ULL)
+#define POWERPC_MMU_405      (POWERPC_MMU_SOFT_4xx)
+#define POWERPC_EXCP_405     (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_405    (PPC_FLAGS_INPUT_405)
+#define POWERPC_BFDM_405     (bfd_mach_ppc_403)
+
+static void init_proc_405 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_40x(env);
+    gen_spr_405(env);
+    /* Bus access control */
+    /* not emulated, as Qemu never does speculative access */
+    spr_register(env, SPR_40x_SGR, "SGR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0xFFFFFFFF);
+    /* not emulated, as Qemu do not emulate caches */
+    spr_register(env, SPR_40x_DCWR, "DCWR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_4xx_softmmu(env);
+    /* Allocate hardware IRQ controller */
+    ppc40x_irq_init(env);
+}
+
+/* PowerPC 440 EP                                                            */
+#define POWERPC_INSNS_440EP  (POWERPC_INSNS_EMB |                             \
+                              PPC_CACHE_DCBA | PPC_MEM_TLBSYNC |              \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC | PPC_RFMCI)
+#define POWERPC_MSRM_440EP   (0x000000000006D630ULL)
+#define POWERPC_MMU_440EP    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_440EP   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_440EP  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_440EP   (bfd_mach_ppc_403)
+
+static void init_proc_440EP (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env);
+    gen_spr_440(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_CCR1, "CCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_BookE(env);
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 440 GP                                                            */
+#define POWERPC_INSNS_440GP  (POWERPC_INSNS_EMB |                             \
+                              PPC_CACHE_DCBA | PPC_MEM_TLBSYNC |              \
+                              PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON |    \
+                              PPC_405_MAC | PPC_440_SPEC)
+#define POWERPC_MSRM_440GP   (0x000000000006FF30ULL)
+#define POWERPC_MMU_440GP    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_440GP   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_440GP  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_440GP   (bfd_mach_ppc_403)
+
+static void init_proc_440GP (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env);
+    gen_spr_440(env);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_BookE(env);
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 440x4                                                             */
+#define POWERPC_INSNS_440x4  (POWERPC_INSNS_EMB |                             \
+                              PPC_CACHE_DCBA | PPC_MEM_TLBSYNC |              \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC)
+#define POWERPC_MSRM_440x4   (0x000000000006FF30ULL)
+#define POWERPC_MMU_440x4    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_440x4   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_440x4  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_440x4   (bfd_mach_ppc_403)
+
+__attribute__ (( unused ))
+static void init_proc_440x4 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env);
+    gen_spr_440(env);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_BookE(env);
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 440x5                                                             */
+#define POWERPC_INSNS_440x5  (POWERPC_INSNS_EMB |                             \
+                              PPC_CACHE_DCBA | PPC_MEM_TLBSYNC |              \
+                              PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |      \
+                              PPC_440_SPEC | PPC_RFMCI)
+#define POWERPC_MSRM_440x5   (0x000000000006FF30ULL)
+#define POWERPC_MMU_440x5    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_440x5   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_440x5  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_440x5   (bfd_mach_ppc_403)
+
+static void init_proc_440x5 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env);
+    gen_spr_440(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_CCR1, "CCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_BookE(env);
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 460 (guessed)                                                     */
+#define POWERPC_INSNS_460    (POWERPC_INSNS_EMB |                             \
+                              PPC_CACHE_DCBA | PPC_MEM_TLBSYNC |              \
+                              PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON |    \
+                              PPC_405_MAC | PPC_440_SPEC | PPC_DCRUX)
+#define POWERPC_MSRM_460     (0x000000000006FF30ULL)
+#define POWERPC_MMU_460      (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_460     (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_460    (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_460     (bfd_mach_ppc_403)
+
+__attribute__ (( unused ))
+static void init_proc_460 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env);
+    gen_spr_440(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_CCR1, "CCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DCRIPR, "SPR_DCRIPR",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_BookE(env);
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 460F (guessed)                                                    */
+#define POWERPC_INSNS_460F   (POWERPC_INSNS_EMB |                             \
+                              PPC_CACHE_DCBA | PPC_MEM_TLBSYNC |              \
+                              PPC_FLOAT | PPC_FLOAT_FSQRT | PPC_FLOAT_FRES |  \
+                              PPC_FLOAT_FRSQRTE | PPC_FLOAT_FSEL |            \
+                              PPC_FLOAT_STFIWX |                              \
+                              PPC_BOOKE | PPC_BOOKE_EXT | PPC_4xx_COMMON |    \
+                              PPC_405_MAC | PPC_440_SPEC | PPC_DCRUX)
+#define POWERPC_MSRM_460     (0x000000000006FF30ULL)
+#define POWERPC_MMU_460F     (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_460F    (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_460F   (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_460F    (bfd_mach_ppc_403)
+
+__attribute__ (( unused ))
+static void init_proc_460F (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env);
+    gen_spr_440(env);
+    /* XXX : not implemented */
+    spr_register(env, SPR_BOOKE_MCSR, "MCSR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_440_CCR1, "CCR1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_DCRIPR, "SPR_DCRIPR",
+                 &spr_read_generic, &spr_write_generic,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_BookE(env);
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* Generic BookE PowerPC                                                     */
+#define POWERPC_INSNS_BookE  (POWERPC_INSNS_EMB |                             \
+                              PPC_MEM_EIEIO | PPC_MEM_TLBSYNC |               \
+                              PPC_CACHE_DCBA |                                \
+                              PPC_FLOAT | PPC_FLOAT_FSQRT |                   \
+                              PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE |            \
+                              PPC_FLOAT_FSEL | PPC_FLOAT_STFIW |              \
+                              PPC_BOOKE)
+#define POWERPC_MSRM_BookE   (0x000000000006D630ULL)
+#define POWERPC_MMU_BookE    (POWERPC_MMU_BOOKE)
+#define POWERPC_EXCP_BookE   (POWERPC_EXCP_BOOKE)
+#define POWERPC_INPUT_BookE  (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_BookE   (bfd_mach_ppc_403)
+
+__attribute__ (( unused ))
+static void init_proc_BookE (CPUPPCState *env)
+{
+    init_excp_BookE(env);
+}
+
+/* e200 core                                                                 */
+
+/* e300 core                                                                 */
+
+/* e500 core                                                                 */
+#define POWERPC_INSNS_e500   (POWERPC_INSNS_EMB |                             \
+                              PPC_MEM_EIEIO | PPC_MEM_TLBSYNC |               \
+                              PPC_CACHE_DCBA |                                \
+                              PPC_BOOKE | PPC_E500_VECTOR)
+#define POWERPC_MMU_e500     (POWERPC_MMU_SOFT_4xx)
+#define POWERPC_EXCP_e500    (POWERPC_EXCP_40x)
+#define POWERPC_INPUT_e500   (PPC_FLAGS_INPUT_BookE)
+#define POWERPC_BFDM_e500    (bfd_mach_ppc_403)
+
+__attribute__ (( unused ))
+static void init_proc_e500 (CPUPPCState *env)
+{
+    /* Time base */
+    gen_tbl(env);
+    gen_spr_BookE(env);
+    /* Memory management */
+    gen_spr_BookE_FSL(env);
+    env->nb_tlb = 64;
+    env->nb_ways = 1;
+    env->id_tlbs = 0;
+    init_excp_BookE(env);
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* e600 core                                                                 */
+
+/* Non-embedded PowerPC                                                      */
+/* Base instructions set for all 6xx/7xx/74xx/970 PowerPC                    */
+#define POWERPC_INSNS_6xx    (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC |     \
+                              PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE)
+/* Instructions common to all 6xx/7xx/74xx/970 PowerPC except 601 & 602      */
+#define POWERPC_INSNS_WORKS  (POWERPC_INSNS_6xx | PPC_FLOAT_FSQRT |           \
+                              PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE |            \
+                              PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX |             \
+                              PPC_MEM_TLBSYNC | PPC_MFTB)
+
+/* POWER : same as 601, without mfmsr, mfsr                                  */
+#if defined(TODO)
+#define POWERPC_INSNS_POWER  (XXX_TODO)
+/* POWER RSC (from RAD6000) */
+#define POWERPC_MSRM_POWER   (0x00000000FEF0ULL)
+#endif /* TODO */
+
+/* PowerPC 601                                                               */
+#define POWERPC_INSNS_601    (POWERPC_INSNS_6xx | PPC_EXTERN | PPC_POWER_BR)
+#define POWERPC_MSRM_601     (0x000000000000FE70ULL)
+//#define POWERPC_MMU_601      (POWERPC_MMU_601)
+//#define POWERPC_EXCP_601     (POWERPC_EXCP_601)
+#define POWERPC_INPUT_601    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_601     (bfd_mach_ppc_601)
+
+static void init_proc_601 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_601(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_601_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_601_HID5, "HID5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_601_HID15, "HID15",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    env->nb_tlb = 64;
+    env->nb_ways = 2;
+    env->id_tlbs = 0;
+    env->id_tlbs = 0;
+    init_excp_601(env);
+    /* XXX: TODO: allocate internal IRQ controller */
+}
+
+/* PowerPC 602                                                               */
+#define POWERPC_INSNS_602    (POWERPC_INSNS_6xx | PPC_MFTB |                  \
+                              PPC_FLOAT_FRES | PPC_FLOAT_FRSQRTE |            \
+                              PPC_FLOAT_FSEL | PPC_FLOAT_STFIWX |             \
+                              PPC_6xx_TLB | PPC_MEM_TLBSYNC | PPC_602_SPEC)
+#define POWERPC_MSRM_602     (0x000000000033FF73ULL)
+#define POWERPC_MMU_602      (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_602     (POWERPC_EXCP_602)
+#define POWERPC_INPUT_602    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_602     (bfd_mach_ppc_602)
+
+static void init_proc_602 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_602(env);
+    /* Time base */
+    gen_tbl(env);
+    /* hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_602(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 603                                                               */
+#define POWERPC_INSNS_603    (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN)
+#define POWERPC_MSRM_603     (0x000000000001FF73ULL)
+#define POWERPC_MMU_603      (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_603     (POWERPC_EXCP_603)
+#define POWERPC_INPUT_603    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_603     (bfd_mach_ppc_603)
+
+static void init_proc_603 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_603(env);
+    /* Time base */
+    gen_tbl(env);
+    /* hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_603(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 603e                                                              */
+#define POWERPC_INSNS_603E   (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN)
+#define POWERPC_MSRM_603E    (0x000000000007FF73ULL)
+#define POWERPC_MMU_603E     (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_603E    (POWERPC_EXCP_603E)
+#define POWERPC_INPUT_603E   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_603E    (bfd_mach_ppc_ec603e)
+
+static void init_proc_603E (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_603(env);
+    /* Time base */
+    gen_tbl(env);
+    /* hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_IABR, "IABR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_603(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC G2                                                                */
+#define POWERPC_INSNS_G2     (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN)
+#define POWERPC_MSRM_G2      (0x000000000006FFF2ULL)
+#define POWERPC_MMU_G2       (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_G2      (POWERPC_EXCP_G2)
+#define POWERPC_INPUT_G2     (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_G2      (bfd_mach_ppc_ec603e)
+
+static void init_proc_G2 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_G2_755(env);
+    gen_spr_G2(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation register */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_G2(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC G2LE                                                              */
+#define POWERPC_INSNS_G2LE   (POWERPC_INSNS_WORKS | PPC_6xx_TLB | PPC_EXTERN)
+#define POWERPC_MSRM_G2LE    (0x000000000007FFF3ULL)
+#define POWERPC_MMU_G2LE     (POWERPC_MMU_SOFT_6xx)
+#define POWERPC_EXCP_G2LE    (POWERPC_EXCP_G2)
+#define POWERPC_INPUT_G2LE   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_G2LE    (bfd_mach_ppc_ec603e)
+
+static void init_proc_G2LE (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_G2_755(env);
+    gen_spr_G2(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation register */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    init_excp_G2(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 604                                                               */
+#define POWERPC_INSNS_604    (POWERPC_INSNS_WORKS | PPC_EXTERN)
+#define POWERPC_MSRM_604     (0x000000000005FF77ULL)
+#define POWERPC_MMU_604      (POWERPC_MMU_32B)
+//#define POWERPC_EXCP_604     (POWERPC_EXCP_604)
+#define POWERPC_INPUT_604    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_604     (bfd_mach_ppc_604)
+
+static void init_proc_604 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_604(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_604(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 740/750 (aka G3)                                                  */
+#define POWERPC_INSNS_7x0    (POWERPC_INSNS_WORKS | PPC_EXTERN)
+#define POWERPC_MSRM_7x0     (0x000000000007FF77ULL)
+#define POWERPC_MMU_7x0      (POWERPC_MMU_32B)
+//#define POWERPC_EXCP_7x0     (POWERPC_EXCP_7x0)
+#define POWERPC_INPUT_7x0    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7x0     (bfd_mach_ppc_750)
+
+static void init_proc_7x0 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_7x0(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 750FX/GX                                                          */
+#define POWERPC_INSNS_750fx  (POWERPC_INSNS_WORKS | PPC_EXTERN)
+#define POWERPC_MSRM_750fx   (0x000000000007FF77ULL)
+#define POWERPC_MMU_750fx    (POWERPC_MMU_32B)
+#define POWERPC_EXCP_750fx   (POWERPC_EXCP_7x0)
+#define POWERPC_INPUT_750fx  (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_750fx   (bfd_mach_ppc_750)
+
+static void init_proc_750fx (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
+    gen_high_BATs(env);
+    init_excp_750FX(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 745/755                                                           */
+#define POWERPC_INSNS_7x5    (POWERPC_INSNS_WORKS | PPC_EXTERN | PPC_6xx_TLB)
+#define POWERPC_MSRM_7x5     (0x000000000007FF77ULL)
+#define POWERPC_MMU_7x5      (POWERPC_MMU_SOFT_6xx)
+//#define POWERPC_EXCP_7x5     (POWERPC_EXCP_7x5)
+#define POWERPC_INPUT_7x5    (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7x5     (bfd_mach_ppc_750)
+
+static void init_proc_7x5 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_G2_755(env);
+    /* Time base */
+    gen_tbl(env);
+    /* L2 cache control */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTC, "ICTC",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2PMCR, "L2PMCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_6xx_7xx_soft_tlb(env, 64, 2);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7400 (aka G4)                                                     */
+#define POWERPC_INSNS_7400   (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA |          \
+                              PPC_EXTERN | PPC_MEM_TLBIA |                    \
+                              PPC_ALTIVEC)
+#define POWERPC_MSRM_7400    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7400     (POWERPC_MMU_32B)
+#define POWERPC_EXCP_7400    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7400   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7400    (bfd_mach_ppc_7400)
+
+static void init_proc_7400 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_7400(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7410 (aka G4)                                                     */
+#define POWERPC_INSNS_7410   (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA |          \
+                              PPC_EXTERN | PPC_MEM_TLBIA |                    \
+                              PPC_ALTIVEC)
+#define POWERPC_MSRM_7410    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7410     (POWERPC_MMU_32B)
+#define POWERPC_EXCP_7410    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7410   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7410    (bfd_mach_ppc_7400)
+
+static void init_proc_7410 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* Thermal management */
+    gen_spr_thrm(env);
+    /* L2PMCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_L2PMCR, "L2PMCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* LDSTDB */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTDB, "LDSTDB",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    init_excp_7400(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7440 (aka G4)                                                     */
+#define POWERPC_INSNS_7440   (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA |          \
+                              PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA |     \
+                              PPC_ALTIVEC)
+#define POWERPC_MSRM_7440    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7440     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7440    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7440   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7440    (bfd_mach_ppc_7400)
+
+__attribute__ (( unused ))
+static void init_proc_7440 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7450 (aka G4)                                                     */
+#define POWERPC_INSNS_7450   (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA |          \
+                              PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA |     \
+                              PPC_ALTIVEC)
+#define POWERPC_MSRM_7450    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7450     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7450    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7450   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7450    (bfd_mach_ppc_7400)
+
+__attribute__ (( unused ))
+static void init_proc_7450 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* Level 3 cache control */
+    gen_l3_ctrl(env);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7445 (aka G4)                                                     */
+#define POWERPC_INSNS_7445   (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA |          \
+                              PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA |     \
+                              PPC_ALTIVEC)
+#define POWERPC_MSRM_7445    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7445     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7445    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7445   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7445    (bfd_mach_ppc_7400)
+
+__attribute__ (( unused ))
+static void init_proc_7445 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+/* PowerPC 7455 (aka G4)                                                     */
+#define POWERPC_INSNS_7455   (POWERPC_INSNS_WORKS | PPC_CACHE_DCBA |          \
+                              PPC_EXTERN | PPC_74xx_TLB | PPC_MEM_TLBIA |     \
+                              PPC_ALTIVEC)
+#define POWERPC_MSRM_7455    (0x000000000205FF77ULL)
+#define POWERPC_MMU_7455     (POWERPC_MMU_SOFT_74xx)
+#define POWERPC_EXCP_7455    (POWERPC_EXCP_74xx)
+#define POWERPC_INPUT_7455   (PPC_FLAGS_INPUT_6xx)
+#define POWERPC_BFDM_7455    (bfd_mach_ppc_7400)
+
+__attribute__ (( unused ))
+static void init_proc_7455 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* 74xx specific SPR */
+    gen_spr_74xx(env);
+    /* Level 3 cache control */
+    gen_l3_ctrl(env);
+    /* LDSTCR */
+    /* XXX : not implemented */
+    spr_register(env, SPR_LDSTCR, "LDSTCR",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* ICTRL */
+    /* XXX : not implemented */
+    spr_register(env, SPR_ICTRL, "ICTRL",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* MSSSR0 */
+    /* XXX : not implemented */
+    spr_register(env, SPR_MSSSR0, "MSSSR0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* PMC */
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC5, "PMC5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC5, "UPMC5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_PMC6, "PMC6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_UPMC6, "UPMC6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* SPRGs */
+    spr_register(env, SPR_SPRG4, "SPRG4",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG4, "USPRG4",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG5, "SPRG5",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG5, "USPRG5",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG6, "SPRG6",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG6, "USPRG6",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    spr_register(env, SPR_SPRG7, "SPRG7",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    spr_register(env, SPR_USPRG7, "USPRG7",
+                 &spr_read_ureg, SPR_NOACCESS,
+                 &spr_read_ureg, SPR_NOACCESS,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    gen_74xx_soft_tlb(env, 128, 2);
+    init_excp_7450(env);
+    /* Allocate hardware IRQ controller */
+    ppc6xx_irq_init(env);
+}
+
+#if defined (TARGET_PPC64)
+/* PowerPC 970                                                               */
+#define POWERPC_INSNS_970    (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT |         \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_64_BRIDGE | PPC_SLBI)
+#define POWERPC_MSRM_970     (0x900000000204FF36ULL)
+#define POWERPC_MMU_970      (POWERPC_MMU_64BRIDGE)
+//#define POWERPC_EXCP_970     (POWERPC_EXCP_970)
+#define POWERPC_INPUT_970    (PPC_FLAGS_INPUT_970)
+#define POWERPC_BFDM_970     (bfd_mach_ppc64)
+
+static void init_proc_970 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    /* XXX: not correct */
+    gen_low_BATs(env);
+#if 0 // TODO
+    env->slb_nr = 32;
+#endif
+    init_excp_970(env);
+    /* Allocate hardware IRQ controller */
+    ppc970_irq_init(env);
+}
+
+/* PowerPC 970FX (aka G5)                                                    */
+#define POWERPC_INSNS_970FX  (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT |         \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_64_BRIDGE | PPC_SLBI)
+#define POWERPC_MSRM_970FX   (0x800000000204FF36ULL)
+#define POWERPC_MMU_970FX    (POWERPC_MMU_64BRIDGE)
+#define POWERPC_EXCP_970FX   (POWERPC_EXCP_970)
+#define POWERPC_INPUT_970FX  (PPC_FLAGS_INPUT_970)
+#define POWERPC_BFDM_970FX   (bfd_mach_ppc64)
+
+static void init_proc_970FX (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    /* XXX: not correct */
+    gen_low_BATs(env);
+#if 0 // TODO
+    env->slb_nr = 32;
+#endif
+    init_excp_970(env);
+    /* Allocate hardware IRQ controller */
+    ppc970_irq_init(env);
+}
+
+/* PowerPC 970 GX                                                            */
+#define POWERPC_INSNS_970GX  (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT |         \
+                              PPC_64B | PPC_ALTIVEC |                         \
+                              PPC_64_BRIDGE | PPC_SLBI)
+#define POWERPC_MSRM_970GX   (0x800000000204FF36ULL)
+#define POWERPC_MMU_970GX    (POWERPC_MMU_64BRIDGE)
+#define POWERPC_EXCP_970GX   (POWERPC_EXCP_970)
+#define POWERPC_INPUT_970GX  (PPC_FLAGS_INPUT_970)
+#define POWERPC_BFDM_970GX   (bfd_mach_ppc64)
+
+static void init_proc_970GX (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_7xx(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID1, "HID1",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* XXX : not implemented */
+    spr_register(env, SPR_750_HID2, "HID2",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    /* XXX: not correct */
+    gen_low_BATs(env);
+#if 0 // TODO
+    env->slb_nr = 32;
+#endif
+    init_excp_970(env);
+    /* Allocate hardware IRQ controller */
+    ppc970_irq_init(env);
+}
+
+/* PowerPC 620                                                               */
+#define POWERPC_INSNS_620    (POWERPC_INSNS_WORKS | PPC_FLOAT_FSQRT |         \
+                              PPC_64B | PPC_SLBI)
+#define POWERPC_MSRM_620     (0x800000000005FF73ULL)
+#define POWERPC_MMU_620      (POWERPC_MMU_64B)
+#define POWERPC_EXCP_620     (POWERPC_EXCP_970)
+#define POWERPC_INPUT_620    (PPC_FLAGS_INPUT_970)
+#define POWERPC_BFDM_620     (bfd_mach_ppc64)
+
+__attribute__ (( unused ))
+static void init_proc_620 (CPUPPCState *env)
+{
+    gen_spr_ne_601(env);
+    gen_spr_620(env);
+    /* Time base */
+    gen_tbl(env);
+    /* Hardware implementation registers */
+    /* XXX : not implemented */
+    spr_register(env, SPR_HID0, "HID0",
+                 SPR_NOACCESS, SPR_NOACCESS,
+                 &spr_read_generic, &spr_write_generic,
+                 0x00000000);
+    /* Memory management */
+    gen_low_BATs(env);
+    gen_high_BATs(env);
+    init_excp_620(env);
+    /* XXX: TODO: initialize internal interrupt controller */
+}
+#endif /* defined (TARGET_PPC64) */
+
+/* Default 32 bits PowerPC target will be 604 */
+#define CPU_POWERPC_PPC32     CPU_POWERPC_604
+#define POWERPC_INSNS_PPC32   POWERPC_INSNS_604
+#define POWERPC_MSRM_PPC32    POWERPC_MSRM_604
+#define POWERPC_MMU_PPC32     POWERPC_MMU_604
+#define POWERPC_EXCP_PPC32    POWERPC_EXCP_604
+#define POWERPC_INPUT_PPC32   POWERPC_INPUT_604
+#define init_proc_PPC32       init_proc_604
+#define POWERPC_BFDM_PPC32    POWERPC_BFDM_604
+
+/* Default 64 bits PowerPC target will be 970 FX */
+#define CPU_POWERPC_PPC64     CPU_POWERPC_970FX
+#define POWERPC_INSNS_PPC64   POWERPC_INSNS_970FX
+#define POWERPC_MSRM_PPC64    POWERPC_MSRM_970FX
+#define POWERPC_MMU_PPC64     POWERPC_MMU_970FX
+#define POWERPC_EXCP_PPC64    POWERPC_EXCP_970FX
+#define POWERPC_INPUT_PPC64   POWERPC_INPUT_970FX
+#define init_proc_PPC64       init_proc_970FX
+#define POWERPC_BFDM_PPC64    POWERPC_BFDM_970FX
+
+/* Default PowerPC target will be PowerPC 32 */
+#if defined (TARGET_PPC64) && 0 // XXX: TODO
+#define CPU_POWERPC_DEFAULT   CPU_POWERPC_PPC64
+#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC64
+#define POWERPC_MSRM_DEFAULT  POWERPC_MSRM_PPC64
+#define POWERPC_MMU_DEFAULT   POWERPC_MMU_PPC64
+#define POWERPC_EXCP_DEFAULT  POWERPC_EXCP_PPC64
+#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC64
+#define init_proc_DEFAULT     init_proc_PPC64
+#define POWERPC_BFDM_DEFAULT  POWERPC_BFDM_PPC64
+#else
+#define CPU_POWERPC_DEFAULT   CPU_POWERPC_PPC32
+#define POWERPC_INSNS_DEFAULT POWERPC_INSNS_PPC32
+#define POWERPC_MSRM_DEFAULT  POWERPC_MSRM_PPC32
+#define POWERPC_MMU_DEFAULT   POWERPC_MMU_PPC32
+#define POWERPC_EXCP_DEFAULT  POWERPC_EXCP_PPC32
+#define POWERPC_INPUT_DEFAULT POWERPC_INPUT_PPC32
+#define init_proc_DEFAULT     init_proc_PPC32
+#define POWERPC_BFDM_DEFAULT  POWERPC_BFDM_PPC32
+#endif
+
+/*****************************************************************************/
+/* PVR definitions for most known PowerPC                                    */
+enum {
+    /* PowerPC 401 family */
+    /* Generic PowerPC 401 */
+#define CPU_POWERPC_401       CPU_POWERPC_401G2
+    /* PowerPC 401 cores */
+    CPU_POWERPC_401A1       = 0x00210000,
+    CPU_POWERPC_401B2       = 0x00220000,
+#if 0
+    CPU_POWERPC_401B3       = xxx,
+#endif
+    CPU_POWERPC_401C2       = 0x00230000,
+    CPU_POWERPC_401D2       = 0x00240000,
+    CPU_POWERPC_401E2       = 0x00250000,
+    CPU_POWERPC_401F2       = 0x00260000,
+    CPU_POWERPC_401G2       = 0x00270000,
+    /* PowerPC 401 microcontrolers */
+#if 0
+    CPU_POWERPC_401GF       = xxx,
+#endif
+#define CPU_POWERPC_IOP480    CPU_POWERPC_401B2
+    /* IBM Processor for Network Resources */
+    CPU_POWERPC_COBRA       = 0x10100000, /* XXX: 405 ? */
+#if 0
+    CPU_POWERPC_XIPCHIP     = xxx,
+#endif
+    /* PowerPC 403 family */
+    /* Generic PowerPC 403 */
+#define CPU_POWERPC_403       CPU_POWERPC_403GC
+    /* PowerPC 403 microcontrollers */
+    CPU_POWERPC_403GA       = 0x00200011,
+    CPU_POWERPC_403GB       = 0x00200100,
+    CPU_POWERPC_403GC       = 0x00200200,
+    CPU_POWERPC_403GCX      = 0x00201400,
+#if 0
+    CPU_POWERPC_403GP       = xxx,
+#endif
+    /* PowerPC 405 family */
+    /* Generic PowerPC 405 */
+#define CPU_POWERPC_405       CPU_POWERPC_405D4
+    /* PowerPC 405 cores */
+#if 0
+    CPU_POWERPC_405A3       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405A4       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405B3       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405B4       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405C3       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405C4       = xxx,
+#endif
+    CPU_POWERPC_405D2       = 0x20010000,
+#if 0
+    CPU_POWERPC_405D3       = xxx,
+#endif
+    CPU_POWERPC_405D4       = 0x41810000,
+#if 0
+    CPU_POWERPC_405D5       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405E4       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405F4       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405F5       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405F6       = xxx,
+#endif
+    /* PowerPC 405 microcontrolers */
+    /* XXX: missing 0x200108a0 */
+#define CPU_POWERPC_405CR     CPU_POWERPC_405CRc
+    CPU_POWERPC_405CRa      = 0x40110041,
+    CPU_POWERPC_405CRb      = 0x401100C5,
+    CPU_POWERPC_405CRc      = 0x40110145,
+    CPU_POWERPC_405EP       = 0x51210950,
+#if 0
+    CPU_POWERPC_405EXr      = xxx,
+#endif
+    CPU_POWERPC_405EZ       = 0x41511460, /* 0x51210950 ? */
+#if 0
+    CPU_POWERPC_405FX       = xxx,
+#endif
+#define CPU_POWERPC_405GP     CPU_POWERPC_405GPd
+    CPU_POWERPC_405GPa      = 0x40110000,
+    CPU_POWERPC_405GPb      = 0x40110040,
+    CPU_POWERPC_405GPc      = 0x40110082,
+    CPU_POWERPC_405GPd      = 0x401100C4,
+#define CPU_POWERPC_405GPe    CPU_POWERPC_405CRc
+    CPU_POWERPC_405GPR      = 0x50910951,
+#if 0
+    CPU_POWERPC_405H        = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405L        = xxx,
+#endif
+    CPU_POWERPC_405LP       = 0x41F10000,
+#if 0
+    CPU_POWERPC_405PM       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405PS       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_405S        = xxx,
+#endif
+    /* IBM network processors */
+    CPU_POWERPC_NPE405H     = 0x414100C0,
+    CPU_POWERPC_NPE405H2    = 0x41410140,
+    CPU_POWERPC_NPE405L     = 0x416100C0,
+    CPU_POWERPC_NPE4GS3     = 0x40B10000,
+#if 0
+    CPU_POWERPC_NPCxx1      = xxx,
+#endif
+#if 0
+    CPU_POWERPC_NPR161      = xxx,
+#endif
+#if 0
+    CPU_POWERPC_LC77700     = xxx,
+#endif
+    /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */
+#if 0
+    CPU_POWERPC_STB01000    = xxx,
+#endif
+#if 0
+    CPU_POWERPC_STB01010    = xxx,
+#endif
+#if 0
+    CPU_POWERPC_STB0210     = xxx, /* 401B3 */
+#endif
+    CPU_POWERPC_STB03       = 0x40310000, /* 0x40130000 ? */
+#if 0
+    CPU_POWERPC_STB043      = xxx,
+#endif
+#if 0
+    CPU_POWERPC_STB045      = xxx,
+#endif
+    CPU_POWERPC_STB04       = 0x41810000,
+    CPU_POWERPC_STB25       = 0x51510950,
+#if 0
+    CPU_POWERPC_STB130      = xxx,
+#endif
+    /* Xilinx cores */
+    CPU_POWERPC_X2VP4       = 0x20010820,
+#define CPU_POWERPC_X2VP7     CPU_POWERPC_X2VP4
+    CPU_POWERPC_X2VP20      = 0x20010860,
+#define CPU_POWERPC_X2VP50    CPU_POWERPC_X2VP20
+#if 0
+    CPU_POWERPC_ZL10310     = xxx,
+#endif
+#if 0
+    CPU_POWERPC_ZL10311     = xxx,
+#endif
+#if 0
+    CPU_POWERPC_ZL10320     = xxx,
+#endif
+#if 0
+    CPU_POWERPC_ZL10321     = xxx,
+#endif
+    /* PowerPC 440 family */
+    /* Generic PowerPC 440 */
+#define CPU_POWERPC_440       CPU_POWERPC_440GXf
+    /* PowerPC 440 cores */
+#if 0
+    CPU_POWERPC_440A4       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440A5       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440B4       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440F5       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440G5       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440H4       = xxx,
+#endif
+#if 0
+    CPU_POWERPC_440H6       = xxx,
+#endif
+    /* PowerPC 440 microcontrolers */
+#define CPU_POWERPC_440EP     CPU_POWERPC_440EPb
+    CPU_POWERPC_440EPa      = 0x42221850,
+    CPU_POWERPC_440EPb      = 0x422218D3,
+#define CPU_POWERPC_440GP     CPU_POWERPC_440GPc
+    CPU_POWERPC_440GPb      = 0x40120440,
+    CPU_POWERPC_440GPc      = 0x40120481,
+#define CPU_POWERPC_440GR     CPU_POWERPC_440GRa
+#define CPU_POWERPC_440GRa    CPU_POWERPC_440EPb
+    CPU_POWERPC_440GRX      = 0x200008D0,
+#define CPU_POWERPC_440EPX    CPU_POWERPC_440GRX
+#define CPU_POWERPC_440GX     CPU_POWERPC_440GXf
+    CPU_POWERPC_440GXa      = 0x51B21850,
+    CPU_POWERPC_440GXb      = 0x51B21851,
+    CPU_POWERPC_440GXc      = 0x51B21892,
+    CPU_POWERPC_440GXf      = 0x51B21894,
+#if 0
+    CPU_POWERPC_440S        = xxx,
+#endif
+    CPU_POWERPC_440SP       = 0x53221850,
+    CPU_POWERPC_440SP2      = 0x53221891,
+    CPU_POWERPC_440SPE      = 0x53421890,
+    /* PowerPC 460 family */
+#if 0
+    /* Generic PowerPC 464 */
+#define CPU_POWERPC_464       CPU_POWERPC_464H90
+#endif
+    /* PowerPC 464 microcontrolers */
+#if 0
+    CPU_POWERPC_464H90      = xxx,
+#endif
+#if 0
+    CPU_POWERPC_464H90FP    = xxx,
+#endif
+    /* Freescale embedded PowerPC cores */
+    /* e200 family */
+#define CPU_POWERPC_e200      CPU_POWERPC_e200z6
+#if 0
+    CPU_POWERPC_e200z0      = xxx,
+#endif
+#if 0
+    CPU_POWERPC_e200z3      = xxx,
+#endif
+    CPU_POWERPC_e200z5      = 0x81000000,
+    CPU_POWERPC_e200z6      = 0x81120000,
+    /* e300 family */
+#define CPU_POWERPC_e300      CPU_POWERPC_e300c3
+    CPU_POWERPC_e300c1      = 0x00830000,
+    CPU_POWERPC_e300c2      = 0x00840000,
+    CPU_POWERPC_e300c3      = 0x00850000,
+    /* e500 family */
+#define CPU_POWERPC_e500      CPU_POWERPC_e500_v22
+    CPU_POWERPC_e500_v11    = 0x80200010,
+    CPU_POWERPC_e500_v12    = 0x80200020,
+    CPU_POWERPC_e500_v21    = 0x80210010,
+    CPU_POWERPC_e500_v22    = 0x80210020,
+#if 0
+    CPU_POWERPC_e500mc      = xxx,
+#endif
+    /* e600 family */
+    CPU_POWERPC_e600        = 0x80040010,
+    /* PowerPC MPC 5xx cores */
+    CPU_POWERPC_5xx         = 0x00020020,
+    /* PowerPC MPC 8xx cores (aka PowerQUICC) */
+    CPU_POWERPC_8xx         = 0x00500000,
+    /* PowerPC MPC 8xxx cores (aka PowerQUICC-II) */
+    CPU_POWERPC_82xx_HIP3   = 0x00810101,
+    CPU_POWERPC_82xx_HIP4   = 0x80811014,
+    CPU_POWERPC_827x        = 0x80822013,
+    /* PowerPC 6xx cores */
+    CPU_POWERPC_601         = 0x00010001,
+    CPU_POWERPC_601a        = 0x00010002,
+    CPU_POWERPC_602         = 0x00050100,
+    CPU_POWERPC_603         = 0x00030100,
+#define CPU_POWERPC_603E      CPU_POWERPC_603E_v41
+    CPU_POWERPC_603E_v11    = 0x00060101,
+    CPU_POWERPC_603E_v12    = 0x00060102,
+    CPU_POWERPC_603E_v13    = 0x00060103,
+    CPU_POWERPC_603E_v14    = 0x00060104,
+    CPU_POWERPC_603E_v22    = 0x00060202,
+    CPU_POWERPC_603E_v3     = 0x00060300,
+    CPU_POWERPC_603E_v4     = 0x00060400,
+    CPU_POWERPC_603E_v41    = 0x00060401,
+    CPU_POWERPC_603E7t      = 0x00071201,
+    CPU_POWERPC_603E7v      = 0x00070100,
+    CPU_POWERPC_603E7v1     = 0x00070101,
+    CPU_POWERPC_603E7v2     = 0x00070201,
+    CPU_POWERPC_603E7       = 0x00070200,
+    CPU_POWERPC_603P        = 0x00070000,
+#define CPU_POWERPC_603R      CPU_POWERPC_603E7t
+    CPU_POWERPC_G2          = 0x00810011,
+#if 0 // Linux pretends the MSB is zero...
+    CPU_POWERPC_G2H4        = 0x80811010,
+    CPU_POWERPC_G2gp        = 0x80821010,
+    CPU_POWERPC_G2ls        = 0x90810010,
+    CPU_POWERPC_G2LE        = 0x80820010,
+    CPU_POWERPC_G2LEgp      = 0x80822010,
+    CPU_POWERPC_G2LEls      = 0xA0822010,
+#else
+    CPU_POWERPC_G2H4        = 0x00811010,
+    CPU_POWERPC_G2gp        = 0x00821010,
+    CPU_POWERPC_G2ls        = 0x10810010,
+    CPU_POWERPC_G2LE        = 0x00820010,
+    CPU_POWERPC_G2LEgp      = 0x00822010,
+    CPU_POWERPC_G2LEls      = 0x20822010,
+#endif
+    CPU_POWERPC_604         = 0x00040103,
+#define CPU_POWERPC_604E      CPU_POWERPC_604E_v24
+    CPU_POWERPC_604E_v10    = 0x00090100, /* Also 2110 & 2120 */
+    CPU_POWERPC_604E_v22    = 0x00090202,
+    CPU_POWERPC_604E_v24    = 0x00090204,
+    CPU_POWERPC_604R        = 0x000a0101, /* Also 0x00093102 */
+#if 0
+    CPU_POWERPC_604EV       = xxx,
+#endif
+    /* PowerPC 740/750 cores (aka G3) */
+    /* XXX: missing 0x00084202 */
+#define CPU_POWERPC_7x0       CPU_POWERPC_7x0_v31
+    CPU_POWERPC_7x0_v20     = 0x00080200,
+    CPU_POWERPC_7x0_v21     = 0x00080201,
+    CPU_POWERPC_7x0_v22     = 0x00080202,
+    CPU_POWERPC_7x0_v30     = 0x00080300,
+    CPU_POWERPC_7x0_v31     = 0x00080301,
+    CPU_POWERPC_740E        = 0x00080100,
+    CPU_POWERPC_7x0P        = 0x10080000,
+    /* XXX: missing 0x00087010 (CL ?) */
+    CPU_POWERPC_750CL       = 0x00087200,
+#define CPU_POWERPC_750CX     CPU_POWERPC_750CX_v22
+    CPU_POWERPC_750CX_v21   = 0x00082201,
+    CPU_POWERPC_750CX_v22   = 0x00082202,
+#define CPU_POWERPC_750CXE    CPU_POWERPC_750CXE_v31b
+    CPU_POWERPC_750CXE_v21  = 0x00082211,
+    CPU_POWERPC_750CXE_v22  = 0x00082212,
+    CPU_POWERPC_750CXE_v23  = 0x00082213,
+    CPU_POWERPC_750CXE_v24  = 0x00082214,
+    CPU_POWERPC_750CXE_v24b = 0x00083214,
+    CPU_POWERPC_750CXE_v31  = 0x00083211,
+    CPU_POWERPC_750CXE_v31b = 0x00083311,
+    CPU_POWERPC_750CXR      = 0x00083410,
+    CPU_POWERPC_750E        = 0x00080200,
+    CPU_POWERPC_750FL       = 0x700A0203,
+#define CPU_POWERPC_750FX     CPU_POWERPC_750FX_v23
+    CPU_POWERPC_750FX_v10   = 0x70000100,
+    CPU_POWERPC_750FX_v20   = 0x70000200,
+    CPU_POWERPC_750FX_v21   = 0x70000201,
+    CPU_POWERPC_750FX_v22   = 0x70000202,
+    CPU_POWERPC_750FX_v23   = 0x70000203,
+    CPU_POWERPC_750GL       = 0x70020102,
+#define CPU_POWERPC_750GX     CPU_POWERPC_750GX_v12
+    CPU_POWERPC_750GX_v10   = 0x70020100,
+    CPU_POWERPC_750GX_v11   = 0x70020101,
+    CPU_POWERPC_750GX_v12   = 0x70020102,
+#define CPU_POWERPC_750L      CPU_POWERPC_750L_v32 /* Aka LoneStar */
+    CPU_POWERPC_750L_v22    = 0x00088202,
+    CPU_POWERPC_750L_v30    = 0x00088300,
+    CPU_POWERPC_750L_v32    = 0x00088302,
+    /* PowerPC 745/755 cores */
+#define CPU_POWERPC_7x5       CPU_POWERPC_7x5_v28
+    CPU_POWERPC_7x5_v10     = 0x00083100,
+    CPU_POWERPC_7x5_v11     = 0x00083101,
+    CPU_POWERPC_7x5_v20     = 0x00083200,
+    CPU_POWERPC_7x5_v21     = 0x00083201,
+    CPU_POWERPC_7x5_v22     = 0x00083202, /* aka D */
+    CPU_POWERPC_7x5_v23     = 0x00083203, /* aka E */
+    CPU_POWERPC_7x5_v24     = 0x00083204,
+    CPU_POWERPC_7x5_v25     = 0x00083205,
+    CPU_POWERPC_7x5_v26     = 0x00083206,
+    CPU_POWERPC_7x5_v27     = 0x00083207,
+    CPU_POWERPC_7x5_v28     = 0x00083208,
+#if 0
+    CPU_POWERPC_7x5P        = xxx,
+#endif
+    /* PowerPC 74xx cores (aka G4) */
+    /* XXX: missing 0x000C1101 */
+#define CPU_POWERPC_7400      CPU_POWERPC_7400_v29
+    CPU_POWERPC_7400_v10    = 0x000C0100,
+    CPU_POWERPC_7400_v11    = 0x000C0101,
+    CPU_POWERPC_7400_v20    = 0x000C0200,
+    CPU_POWERPC_7400_v22    = 0x000C0202,
+    CPU_POWERPC_7400_v26    = 0x000C0206,
+    CPU_POWERPC_7400_v27    = 0x000C0207,
+    CPU_POWERPC_7400_v28    = 0x000C0208,
+    CPU_POWERPC_7400_v29    = 0x000C0209,
+#define CPU_POWERPC_7410      CPU_POWERPC_7410_v14
+    CPU_POWERPC_7410_v10    = 0x800C1100,
+    CPU_POWERPC_7410_v11    = 0x800C1101,
+    CPU_POWERPC_7410_v12    = 0x800C1102, /* aka C */
+    CPU_POWERPC_7410_v13    = 0x800C1103, /* aka D */
+    CPU_POWERPC_7410_v14    = 0x800C1104, /* aka E */
+#define CPU_POWERPC_7448      CPU_POWERPC_7448_v21
+    CPU_POWERPC_7448_v10    = 0x80040100,
+    CPU_POWERPC_7448_v11    = 0x80040101,
+    CPU_POWERPC_7448_v20    = 0x80040200,
+    CPU_POWERPC_7448_v21    = 0x80040201,
+#define CPU_POWERPC_7450      CPU_POWERPC_7450_v21
+    CPU_POWERPC_7450_v10    = 0x80000100,
+    CPU_POWERPC_7450_v11    = 0x80000101,
+    CPU_POWERPC_7450_v12    = 0x80000102,
+    CPU_POWERPC_7450_v20    = 0x80000200, /* aka D: 2.04 */
+    CPU_POWERPC_7450_v21    = 0x80000201, /* aka E */
+    CPU_POWERPC_74x1        = 0x80000203,
+    CPU_POWERPC_74x1G       = 0x80000210, /* aka G: 2.3 */
+    /* XXX: missing 0x80010200 */
+#define CPU_POWERPC_74x5      CPU_POWERPC_74x5_v32
+    CPU_POWERPC_74x5_v10    = 0x80010100,
+    CPU_POWERPC_74x5_v21    = 0x80010201, /* aka C: 2.1 */
+    CPU_POWERPC_74x5_v32    = 0x80010302,
+    CPU_POWERPC_74x5_v33    = 0x80010303, /* aka F: 3.3 */
+    CPU_POWERPC_74x5_v34    = 0x80010304, /* aka G: 3.4 */
+#define CPU_POWERPC_74x7      CPU_POWERPC_74x7_v12
+    CPU_POWERPC_74x7_v10    = 0x80020100, /* aka A: 1.0 */
+    CPU_POWERPC_74x7_v11    = 0x80030101, /* aka B: 1.1 */
+    CPU_POWERPC_74x7_v12    = 0x80020102, /* aka C: 1.2 */
+    /* 64 bits PowerPC */
+    CPU_POWERPC_620         = 0x00140000,
+    CPU_POWERPC_630         = 0x00400000,
+    CPU_POWERPC_631         = 0x00410104,
+    CPU_POWERPC_POWER4      = 0x00350000,
+    CPU_POWERPC_POWER4P     = 0x00380000,
+    CPU_POWERPC_POWER5      = 0x003A0203,
+#define CPU_POWERPC_POWER5GR  CPU_POWERPC_POWER5
+    CPU_POWERPC_POWER5P     = 0x003B0000,
+#define CPU_POWERPC_POWER5GS  CPU_POWERPC_POWER5P
+    CPU_POWERPC_POWER6      = 0x003E0000,
+    CPU_POWERPC_POWER6_5    = 0x0F000001, /* POWER6 running POWER5 mode */
+    CPU_POWERPC_POWER6A     = 0x0F000002,
+    CPU_POWERPC_970         = 0x00390202,
+#define CPU_POWERPC_970FX     CPU_POWERPC_970FX_v31
+    CPU_POWERPC_970FX_v10   = 0x00391100,
+    CPU_POWERPC_970FX_v20   = 0x003C0200,
+    CPU_POWERPC_970FX_v21   = 0x003C0201,
+    CPU_POWERPC_970FX_v30   = 0x003C0300,
+    CPU_POWERPC_970FX_v31   = 0x003C0301,
+    CPU_POWERPC_970GX       = 0x00450000,
+#define CPU_POWERPC_970MP     CPU_POWERPC_970MP_v11
+    CPU_POWERPC_970MP_v10   = 0x00440100,
+    CPU_POWERPC_970MP_v11   = 0x00440101,
+#define CPU_POWERPC_CELL      CPU_POWERPC_CELL_v32
+    CPU_POWERPC_CELL_v10    = 0x00700100,
+    CPU_POWERPC_CELL_v20    = 0x00700400,
+    CPU_POWERPC_CELL_v30    = 0x00700500,
+    CPU_POWERPC_CELL_v31    = 0x00700501,
+#define CPU_POWERPC_CELL_v32  CPU_POWERPC_CELL_v31
+    CPU_POWERPC_RS64        = 0x00330000,
+    CPU_POWERPC_RS64II      = 0x00340000,
+    CPU_POWERPC_RS64III     = 0x00360000,
+    CPU_POWERPC_RS64IV      = 0x00370000,
+    /* Original POWER */
+    /* XXX: should be POWER (RIOS), RSC3308, RSC4608,
+     * POWER2 (RIOS2) & RSC2 (P2SC) here
+     */
+#if 0
+    CPU_POWER           = xxx, /* 0x20000 ? 0x30000 for RSC ? */
+#endif
+#if 0
+    CPU_POWER2          = xxx, /* 0x40000 ? */
+#endif
+    /* PA Semi core */
+    CPU_POWERPC_PA6T        = 0x00900000,
+};
+
+/* System version register (used on MPC 8xxx)                                */
+enum {
+    PPC_SVR_8540      = 0x80300000,
+    PPC_SVR_8541E     = 0x807A0010,
+    PPC_SVR_8543v10   = 0x80320010,
+    PPC_SVR_8543v11   = 0x80320011,
+    PPC_SVR_8543v20   = 0x80320020,
+    PPC_SVR_8543Ev10  = 0x803A0010,
+    PPC_SVR_8543Ev11  = 0x803A0011,
+    PPC_SVR_8543Ev20  = 0x803A0020,
+    PPC_SVR_8545      = 0x80310220,
+    PPC_SVR_8545E     = 0x80390220,
+    PPC_SVR_8547E     = 0x80390120,
+    PPC_SCR_8548v10   = 0x80310010,
+    PPC_SCR_8548v11   = 0x80310011,
+    PPC_SCR_8548v20   = 0x80310020,
+    PPC_SVR_8548Ev10  = 0x80390010,
+    PPC_SVR_8548Ev11  = 0x80390011,
+    PPC_SVR_8548Ev20  = 0x80390020,
+    PPC_SVR_8555E     = 0x80790010,
+    PPC_SVR_8560v10   = 0x80700010,
+    PPC_SVR_8560v20   = 0x80700020,
+};
+
+/*****************************************************************************/
+/* PowerPC CPU definitions                                                   */
+#define POWERPC_DEF(_name, _pvr, _pvr_mask, _type)                            \
+    {                                                                         \
+        .name        = _name,                                                 \
+        .pvr         = _pvr,                                                  \
+        .pvr_mask    = _pvr_mask,                                             \
+        .insns_flags = glue(POWERPC_INSNS_,_type),                            \
+        .msr_mask    = glue(POWERPC_MSRM_,_type),                             \
+        .mmu_model   = glue(POWERPC_MMU_,_type),                              \
+        .excp_model  = glue(POWERPC_EXCP_,_type),                             \
+        .bus_model   = glue(POWERPC_INPUT_,_type),                            \
+        .bfd_mach    = glue(POWERPC_BFDM_,_type),                             \
+        .init_proc   = &glue(init_proc_,_type),                               \
+    }
+
+static ppc_def_t ppc_defs[] = {
+    /* Embedded PowerPC                                                      */
+    /* PowerPC 401 family                                                    */
+    /* Generic PowerPC 401 */
+    POWERPC_DEF("401",         CPU_POWERPC_401,         0xFFFF0000, 401),
+    /* PowerPC 401 cores                                                     */
+    /* PowerPC 401A1 */
+    POWERPC_DEF("401A1",       CPU_POWERPC_401A1,       0xFFFFFFFF, 401),
+    /* PowerPC 401B2                                                         */
+    POWERPC_DEF("401B2",       CPU_POWERPC_401B2,       0xFFFFFFFF, 401x2),
+#if defined (TODO)
+    /* PowerPC 401B3                                                         */
+    POWERPC_DEF("401B3",       CPU_POWERPC_401B3,       0xFFFFFFFF, 401x3),
+#endif
+    /* PowerPC 401C2                                                         */
+    POWERPC_DEF("401C2",       CPU_POWERPC_401C2,       0xFFFFFFFF, 401x2),
+    /* PowerPC 401D2                                                         */
+    POWERPC_DEF("401D2",       CPU_POWERPC_401D2,       0xFFFFFFFF, 401x2),
+    /* PowerPC 401E2                                                         */
+    POWERPC_DEF("401E2",       CPU_POWERPC_401E2,       0xFFFFFFFF, 401x2),
+    /* PowerPC 401F2                                                         */
+    POWERPC_DEF("401F2",       CPU_POWERPC_401F2,       0xFFFFFFFF, 401x2),
+    /* PowerPC 401G2                                                         */
+    /* XXX: to be checked */
+    POWERPC_DEF("401G2",       CPU_POWERPC_401G2,       0xFFFFFFFF, 401x2),
+    /* PowerPC 401 microcontrolers                                           */
+#if defined (TODO)
+    /* PowerPC 401GF                                                         */
+    POWERPC_DEF("401GF",       CPU_POWERPC_401GF,       0xFFFFFFFF, 401),
+#endif
+    /* IOP480 (401 microcontroler)                                           */
+    POWERPC_DEF("IOP480",      CPU_POWERPC_IOP480,      0xFFFFFFFF, IOP480),
+    /* IBM Processor for Network Resources                                   */
+    POWERPC_DEF("Cobra",       CPU_POWERPC_COBRA,       0xFFFFFFFF, 401),
+#if defined (TODO)
+    POWERPC_DEF("Xipchip",     CPU_POWERPC_XIPCHIP,     0xFFFFFFFF, 401),
+#endif
+    /* PowerPC 403 family                                                    */
+    /* Generic PowerPC 403                                                   */
+    POWERPC_DEF("403",         CPU_POWERPC_403,         0xFFFF0000, 403),
+    /* PowerPC 403 microcontrolers                                           */
+    /* PowerPC 403 GA                                                        */
+    POWERPC_DEF("403GA",       CPU_POWERPC_403GA,       0xFFFFFFFF, 403),
+    /* PowerPC 403 GB                                                        */
+    POWERPC_DEF("403GB",       CPU_POWERPC_403GB,       0xFFFFFFFF, 403),
+    /* PowerPC 403 GC                                                        */
+    POWERPC_DEF("403GC",       CPU_POWERPC_403GC,       0xFFFFFFFF, 403),
+    /* PowerPC 403 GCX                                                       */
+    POWERPC_DEF("403GCX",      CPU_POWERPC_403GCX,      0xFFFFFFFF, 403GCX),
+#if defined (TODO)
+    /* PowerPC 403 GP                                                        */
+    POWERPC_DEF("403GP",       CPU_POWERPC_403GP,       0xFFFFFFFF, 403),
+#endif
+    /* PowerPC 405 family                                                    */
+    /* Generic PowerPC 405                                                   */
+    POWERPC_DEF("405",         CPU_POWERPC_405,         0xFFFF0000, 405),
+    /* PowerPC 405 cores                                                     */
+#if defined (TODO)
+    /* PowerPC 405 A3                                                        */
+    POWERPC_DEF("405A3",       CPU_POWERPC_405A3,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 A4                                                        */
+    POWERPC_DEF("405A4",       CPU_POWERPC_405A4,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 B3                                                        */
+    POWERPC_DEF("405B3",       CPU_POWERPC_405B3,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 B4                                                        */
+    POWERPC_DEF("405B4",       CPU_POWERPC_405B4,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 C3                                                        */
+    POWERPC_DEF("405C3",       CPU_POWERPC_405C3,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 C4                                                        */
+    POWERPC_DEF("405C4",       CPU_POWERPC_405C4,       0xFFFFFFFF, 405),
+#endif
+    /* PowerPC 405 D2                                                        */
+    POWERPC_DEF("405D2",       CPU_POWERPC_405D2,       0xFFFFFFFF, 405),
+#if defined (TODO)
+    /* PowerPC 405 D3                                                        */
+    POWERPC_DEF("405D3",       CPU_POWERPC_405D3,       0xFFFFFFFF, 405),
+#endif
+    /* PowerPC 405 D4                                                        */
+    POWERPC_DEF("405D4",       CPU_POWERPC_405D4,       0xFFFFFFFF, 405),
+#if defined (TODO)
+    /* PowerPC 405 D5                                                        */
+    POWERPC_DEF("405D5",       CPU_POWERPC_405D5,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 E4                                                        */
+    POWERPC_DEF("405E4",       CPU_POWERPC_405E4,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 F4                                                        */
+    POWERPC_DEF("405F4",       CPU_POWERPC_405F4,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 F5                                                        */
+    POWERPC_DEF("405F5",       CPU_POWERPC_405F5,       0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC 405 F6                                                        */
+    POWERPC_DEF("405F6",       CPU_POWERPC_405F6,       0xFFFFFFFF, 405),
+#endif
+    /* PowerPC 405 microcontrolers                                           */
+    /* PowerPC 405 CR                                                        */
+    POWERPC_DEF("405CR",       CPU_POWERPC_405CR,       0xFFFFFFFF, 405),
+    /* PowerPC 405 CRa                                                       */
+    POWERPC_DEF("405CRa",      CPU_POWERPC_405CRa,      0xFFFFFFFF, 405),
+    /* PowerPC 405 CRb                                                       */
+    POWERPC_DEF("405CRb",      CPU_POWERPC_405CRb,      0xFFFFFFFF, 405),
+    /* PowerPC 405 CRc                                                       */
+    POWERPC_DEF("405CRc",      CPU_POWERPC_405CRc,      0xFFFFFFFF, 405),
+    /* PowerPC 405 EP                                                        */
+    POWERPC_DEF("405EP",       CPU_POWERPC_405EP,       0xFFFFFFFF, 405),
+#if defined(TODO)
+    /* PowerPC 405 EXr                                                       */
+    POWERPC_DEF("405EXr",      CPU_POWERPC_405EXr,      0xFFFFFFFF, 405),
+#endif
+    /* PowerPC 405 EZ                                                        */
+    POWERPC_DEF("405EZ",       CPU_POWERPC_405EZ,       0xFFFFFFFF, 405),
+#if defined(TODO)
+    /* PowerPC 405 FX                                                        */
+    POWERPC_DEF("405FX",       CPU_POWERPC_405FX,       0xFFFFFFFF, 405),
+#endif
+    /* PowerPC 405 GP                                                        */
+    POWERPC_DEF("405GP",       CPU_POWERPC_405GP,       0xFFFFFFFF, 405),
+    /* PowerPC 405 GPa                                                       */
+    POWERPC_DEF("405GPa",      CPU_POWERPC_405GPa,      0xFFFFFFFF, 405),
+    /* PowerPC 405 GPb                                                       */
+    POWERPC_DEF("405GPb",      CPU_POWERPC_405GPb,      0xFFFFFFFF, 405),
+    /* PowerPC 405 GPc                                                       */
+    POWERPC_DEF("405GPc",      CPU_POWERPC_405GPc,      0xFFFFFFFF, 405),
+    /* PowerPC 405 GPd                                                       */
+    POWERPC_DEF("405GPd",      CPU_POWERPC_405GPd,      0xFFFFFFFF, 405),
+    /* PowerPC 405 GPe                                                       */
+    POWERPC_DEF("405GPe",      CPU_POWERPC_405GPe,      0xFFFFFFFF, 405),
+    /* PowerPC 405 GPR                                                       */
+    POWERPC_DEF("405GPR",      CPU_POWERPC_405GPR,      0xFFFFFFFF, 405),
+#if defined(TODO)
+    /* PowerPC 405 H                                                         */
+    POWERPC_DEF("405H",        CPU_POWERPC_405H,        0xFFFFFFFF, 405),
+#endif
+#if defined(TODO)
+    /* PowerPC 405 L                                                         */
+    POWERPC_DEF("405L",        CPU_POWERPC_405L,        0xFFFFFFFF, 405),
+#endif
+    /* PowerPC 405 LP                                                        */
+    POWERPC_DEF("405LP",       CPU_POWERPC_405LP,       0xFFFFFFFF, 405),
+#if defined(TODO)
+    /* PowerPC 405 PM                                                        */
+    POWERPC_DEF("405PM",       CPU_POWERPC_405PM,       0xFFFFFFFF, 405),
+#endif
+#if defined(TODO)
+    /* PowerPC 405 PS                                                        */
+    POWERPC_DEF("405PS",       CPU_POWERPC_405PS,       0xFFFFFFFF, 405),
+#endif
+#if defined(TODO)
+    /* PowerPC 405 S                                                         */
+    POWERPC_DEF("405S",        CPU_POWERPC_405S,        0xFFFFFFFF, 405),
+#endif
+    /* Npe405 H                                                              */
+    POWERPC_DEF("Npe405H",     CPU_POWERPC_NPE405H,     0xFFFFFFFF, 405),
+    /* Npe405 H2                                                             */
+    POWERPC_DEF("Npe405H2",    CPU_POWERPC_NPE405H2,    0xFFFFFFFF, 405),
+    /* Npe405 L                                                              */
+    POWERPC_DEF("Npe405L",     CPU_POWERPC_NPE405L,     0xFFFFFFFF, 405),
+    /* Npe4GS3                                                               */
+    POWERPC_DEF("Npe4GS3",     CPU_POWERPC_NPE4GS3,     0xFFFFFFFF, 405),
+#if defined (TODO)
+    POWERPC_DEF("Npcxx1",      CPU_POWERPC_NPCxx1,      0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    POWERPC_DEF("Npr161",      CPU_POWERPC_NPR161,      0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* PowerPC LC77700 (Sanyo)                                               */
+    POWERPC_DEF("LC77700",     CPU_POWERPC_LC77700,     0xFFFFFFFF, 405),
+#endif
+    /* PowerPC 401/403/405 based set-top-box microcontrolers                 */
+#if defined (TODO)
+    /* STB010000                                                             */
+    POWERPC_DEF("STB01000",    CPU_POWERPC_STB01000,    0xFFFFFFFF, 401x2),
+#endif
+#if defined (TODO)
+    /* STB01010                                                              */
+    POWERPC_DEF("STB01010",    CPU_POWERPC_STB01010,    0xFFFFFFFF, 401x2),
+#endif
+#if defined (TODO)
+    /* STB0210                                                               */
+    POWERPC_DEF("STB0210",     CPU_POWERPC_STB0210,     0xFFFFFFFF, 401x3),
+#endif
+    /* STB03xx                                                               */
+    POWERPC_DEF("STB03",       CPU_POWERPC_STB03,       0xFFFFFFFF, 405),
+#if defined (TODO)
+    /* STB043x                                                               */
+    POWERPC_DEF("STB043",      CPU_POWERPC_STB043,      0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* STB045x                                                               */
+    POWERPC_DEF("STB045",      CPU_POWERPC_STB045,      0xFFFFFFFF, 405),
+#endif
+    /* STB04xx                                                               */
+    POWERPC_DEF("STB04",       CPU_POWERPC_STB04,       0xFFFF0000, 405),
+    /* STB25xx                                                               */
+    POWERPC_DEF("STB25",       CPU_POWERPC_STB25,       0xFFFFFFFF, 405),
+#if defined (TODO)
+    /* STB130                                                                */
+    POWERPC_DEF("STB130",      CPU_POWERPC_STB130,      0xFFFFFFFF, 405),
+#endif
+    /* Xilinx PowerPC 405 cores                                              */
+    POWERPC_DEF("x2vp4",       CPU_POWERPC_X2VP4,       0xFFFFFFFF, 405),
+    POWERPC_DEF("x2vp7",       CPU_POWERPC_X2VP7,       0xFFFFFFFF, 405),
+    POWERPC_DEF("x2vp20",      CPU_POWERPC_X2VP20,      0xFFFFFFFF, 405),
+    POWERPC_DEF("x2vp50",      CPU_POWERPC_X2VP50,      0xFFFFFFFF, 405),
+#if defined (TODO)
+    /* Zarlink ZL10310                                                       */
+    POWERPC_DEF("zl10310",     CPU_POWERPC_ZL10310,     0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* Zarlink ZL10311                                                       */
+    POWERPC_DEF("zl10311",     CPU_POWERPC_ZL10311,     0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* Zarlink ZL10320                                                       */
+    POWERPC_DEF("zl10320",     CPU_POWERPC_ZL10320,     0xFFFFFFFF, 405),
+#endif
+#if defined (TODO)
+    /* Zarlink ZL10321                                                       */
+    POWERPC_DEF("zl10321",     CPU_POWERPC_ZL10321,     0xFFFFFFFF, 405),
+#endif
+    /* PowerPC 440 family                                                    */
+    /* Generic PowerPC 440                                                   */
+    POWERPC_DEF("440",         CPU_POWERPC_440,         0xFFFFFFFF, 440GP),
+    /* PowerPC 440 cores                                                     */
+#if defined (TODO)
+    /* PowerPC 440 A4                                                        */
+    POWERPC_DEF("440A4",       CPU_POWERPC_440A4,       0xFFFFFFFF, 440x4),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 A5                                                        */
+    POWERPC_DEF("440A5",       CPU_POWERPC_440A5,       0xFFFFFFFF, 440x5),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 B4                                                        */
+    POWERPC_DEF("440B4",       CPU_POWERPC_440B4,       0xFFFFFFFF, 440x4),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 G4                                                        */
+    POWERPC_DEF("440G4",       CPU_POWERPC_440G4,       0xFFFFFFFF, 440x4),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 F5                                                        */
+    POWERPC_DEF("440F5",       CPU_POWERPC_440F5,       0xFFFFFFFF, 440x5),
+#endif
+#if defined (TODO)
+    /* PowerPC 440 G5                                                        */
+    POWERPC_DEF("440G5",       CPU_POWERPC_440G5,       0xFFFFFFFF, 440x5),
+#endif
+#if defined (TODO)
+    /* PowerPC 440H4                                                         */
+    POWERPC_DEF("440H4",       CPU_POWERPC_440H4,       0xFFFFFFFF, 440x4),
+#endif
+#if defined (TODO)
+    /* PowerPC 440H6                                                         */
+    POWERPC_DEF("440H6",       CPU_POWERPC_440H6,       0xFFFFFFFF, 440Gx5),
+#endif
+    /* PowerPC 440 microcontrolers                                           */
+    /* PowerPC 440 EP                                                        */
+    POWERPC_DEF("440EP",       CPU_POWERPC_440EP,       0xFFFFFFFF, 440EP),
+    /* PowerPC 440 EPa                                                       */
+    POWERPC_DEF("440EPa",      CPU_POWERPC_440EPa,      0xFFFFFFFF, 440EP),
+    /* PowerPC 440 EPb                                                       */
+    POWERPC_DEF("440EPb",      CPU_POWERPC_440EPb,      0xFFFFFFFF, 440EP),
+    /* PowerPC 440 EPX                                                       */
+    POWERPC_DEF("440EPX",      CPU_POWERPC_440EPX,      0xFFFFFFFF, 440EP),
+    /* PowerPC 440 GP                                                        */
+    POWERPC_DEF("440GP",       CPU_POWERPC_440GP,       0xFFFFFFFF, 440GP),
+    /* PowerPC 440 GPb                                                       */
+    POWERPC_DEF("440GPb",      CPU_POWERPC_440GPb,      0xFFFFFFFF, 440GP),
+    /* PowerPC 440 GPc                                                       */
+    POWERPC_DEF("440GPc",      CPU_POWERPC_440GPc,      0xFFFFFFFF, 440GP),
+    /* PowerPC 440 GR                                                        */
+    POWERPC_DEF("440GR",       CPU_POWERPC_440GR,       0xFFFFFFFF, 440x5),
+    /* PowerPC 440 GRa                                                       */
+    POWERPC_DEF("440GRa",      CPU_POWERPC_440GRa,      0xFFFFFFFF, 440x5),
+    /* PowerPC 440 GRX                                                       */
+    POWERPC_DEF("440GRX",      CPU_POWERPC_440GRX,      0xFFFFFFFF, 440x5),
+    /* PowerPC 440 GX                                                        */
+    POWERPC_DEF("440GX",       CPU_POWERPC_440GX,       0xFFFFFFFF, 440EP),
+    /* PowerPC 440 GXa                                                       */
+    POWERPC_DEF("440GXa",      CPU_POWERPC_440GXa,      0xFFFFFFFF, 440EP),
+    /* PowerPC 440 GXb                                                       */
+    POWERPC_DEF("440GXb",      CPU_POWERPC_440GXb,      0xFFFFFFFF, 440EP),
+    /* PowerPC 440 GXc                                                       */
+    POWERPC_DEF("440GXc",      CPU_POWERPC_440GXc,      0xFFFFFFFF, 440EP),
+    /* PowerPC 440 GXf                                                       */
+    POWERPC_DEF("440GXf",      CPU_POWERPC_440GXf,      0xFFFFFFFF, 440EP),
+#if defined(TODO)
+    /* PowerPC 440 S                                                         */
+    POWERPC_DEF("440S",        CPU_POWERPC_440S,        0xFFFFFFFF, 440),
+#endif
+    /* PowerPC 440 SP                                                        */
+    POWERPC_DEF("440SP",       CPU_POWERPC_440SP,       0xFFFFFFFF, 440EP),
+    /* PowerPC 440 SP2                                                       */
+    POWERPC_DEF("440SP2",      CPU_POWERPC_440SP2,      0xFFFFFFFF, 440EP),
+    /* PowerPC 440 SPE                                                       */
+    POWERPC_DEF("440SPE",      CPU_POWERPC_440SPE,      0xFFFFFFFF, 440EP),
+    /* PowerPC 460 family                                                    */
+#if defined (TODO)
+    /* Generic PowerPC 464                                                   */
+    POWERPC_DEF("464",         CPU_POWERPC_464,         0xFFFFFFFF, 460),
+#endif
+    /* PowerPC 464 microcontrolers                                           */
+#if defined (TODO)
+    /* PowerPC 464H90                                                        */
+    POWERPC_DEF("464H90",      CPU_POWERPC_464H90,      0xFFFFFFFF, 460),
+#endif
+#if defined (TODO)
+    /* PowerPC 464H90F                                                       */
+    POWERPC_DEF("464H90F",     CPU_POWERPC_464H90F,     0xFFFFFFFF, 460F),
+#endif
+    /* Freescale embedded PowerPC cores                                      */
+    /* e200 family                                                           */
+#if defined (TODO)
+    /* Generic PowerPC e200 core                                             */
+    POWERPC_DEF("e200",        CPU_POWERPC_e200,        0xFFFFFFFF, e200),
+#endif
+#if defined (TODO)
+    /* PowerPC e200z5 core                                                   */
+    POWERPC_DEF("e200z5",      CPU_POWERPC_e200z5,      0xFFFFFFFF, e200),
+#endif
+#if defined (TODO)
+    /* PowerPC e200z6 core                                                   */
+    POWERPC_DEF("e200z6",      CPU_POWERPC_e200z6,      0xFFFFFFFF, e200),
+#endif
+    /* e300 family                                                           */
+#if defined (TODO)
+    /* Generic PowerPC e300 core                                             */
+    POWERPC_DEF("e300",        CPU_POWERPC_e300,        0xFFFFFFFF, e300),
+#endif
+#if defined (TODO)
+    /* PowerPC e300c1 core                                                   */
+    POWERPC_DEF("e300c1",      CPU_POWERPC_e300c1,      0xFFFFFFFF, e300),
+#endif
+#if defined (TODO)
+    /* PowerPC e300c2 core                                                   */
+    POWERPC_DEF("e300c2",      CPU_POWERPC_e300c2,      0xFFFFFFFF, e300),
+#endif
+#if defined (TODO)
+    /* PowerPC e300c3 core                                                   */
+    POWERPC_DEF("e300c3",      CPU_POWERPC_e300c3,      0xFFFFFFFF, e300),
+#endif
+    /* e500 family                                                           */
+#if defined (TODO)
+    /* PowerPC e500 core                                                     */
+    POWERPC_DEF("e500",        CPU_POWERPC_e500,        0xFFFFFFFF, e500),
+#endif
+#if defined (TODO)
+    /* PowerPC e500 v1.1 core                                                */
+    POWERPC_DEF("e500v1.1",    CPU_POWERPC_e500_v11,    0xFFFFFFFF, e500),
+#endif
+#if defined (TODO)
+    /* PowerPC e500 v1.2 core                                                */
+    POWERPC_DEF("e500v1.2",    CPU_POWERPC_e500_v12,    0xFFFFFFFF, e500),
+#endif
+#if defined (TODO)
+    /* PowerPC e500 v2.1 core                                                */
+    POWERPC_DEF("e500v2.1",    CPU_POWERPC_e500_v21,    0xFFFFFFFF, e500),
+#endif
+#if defined (TODO)
+    /* PowerPC e500 v2.2 core                                                */
+    POWERPC_DEF("e500v2.2",    CPU_POWERPC_e500_v22,    0xFFFFFFFF, e500),
+#endif
+    /* e600 family                                                           */
+#if defined (TODO)
+    /* PowerPC e600 core                                                     */
+    POWERPC_DEF("e600",        CPU_POWERPC_e600,        0xFFFFFFFF, e600),
+#endif
+    /* PowerPC MPC 5xx cores                                                 */
+#if defined (TODO)
+    /* PowerPC MPC 5xx                                                       */
+    POWERPC_DEF("mpc5xx",      CPU_POWERPC_5xx,         0xFFFFFFFF, 5xx),
+#endif
+    /* PowerPC MPC 8xx cores                                                 */
+#if defined (TODO)
+    /* PowerPC MPC 8xx                                                       */
+    POWERPC_DEF("mpc8xx",      CPU_POWERPC_8xx,         0xFFFFFFFF, 8xx),
+#endif
+    /* PowerPC MPC 8xxx cores                                                */
+#if defined (TODO)
+    /* PowerPC MPC 82xx HIP3                                                 */
+    POWERPC_DEF("mpc82xxhip3", CPU_POWERPC_82xx_HIP3,   0xFFFFFFFF, 82xx),
+#endif
+#if defined (TODO)
+    /* PowerPC MPC 82xx HIP4                                                 */
+    POWERPC_DEF("mpc82xxhip4", CPU_POWERPC_82xx_HIP4,   0xFFFFFFFF, 82xx),
+#endif
+#if defined (TODO)
+    /* PowerPC MPC 827x                                                      */
+    POWERPC_DEF("mpc827x",     CPU_POWERPC_827x,        0xFFFFFFFF, 827x),
+#endif
+
+    /* 32 bits "classic" PowerPC                                             */
+    /* PowerPC 6xx family                                                    */
+    /* PowerPC 601                                                           */
+    POWERPC_DEF("601",         CPU_POWERPC_601,         0xFFFFFFFF, 601),
+    /* PowerPC 601v2                                                         */
+    POWERPC_DEF("601a",        CPU_POWERPC_601a,        0xFFFFFFFF, 601),
+    /* PowerPC 602                                                           */
+    POWERPC_DEF("602",         CPU_POWERPC_602,         0xFFFFFFFF, 602),
+    /* PowerPC 603                                                           */
+    POWERPC_DEF("603",         CPU_POWERPC_603,         0xFFFFFFFF, 603),
+    /* Code name for PowerPC 603                                             */
+    POWERPC_DEF("Vanilla",     CPU_POWERPC_603,         0xFFFFFFFF, 603),
+    /* PowerPC 603e                                                          */
+    POWERPC_DEF("603e",        CPU_POWERPC_603E,        0xFFFFFFFF, 603E),
+    /* Code name for PowerPC 603e                                            */
+    POWERPC_DEF("Stretch",     CPU_POWERPC_603E,        0xFFFFFFFF, 603E),
+    /* PowerPC 603e v1.1                                                     */
+    POWERPC_DEF("603e1.1",     CPU_POWERPC_603E_v11,    0xFFFFFFFF, 603E),
+    /* PowerPC 603e v1.2                                                     */
+    POWERPC_DEF("603e1.2",     CPU_POWERPC_603E_v12,    0xFFFFFFFF, 603E),
+    /* PowerPC 603e v1.3                                                     */
+    POWERPC_DEF("603e1.3",     CPU_POWERPC_603E_v13,    0xFFFFFFFF, 603E),
+    /* PowerPC 603e v1.4                                                     */
+    POWERPC_DEF("603e1.4",     CPU_POWERPC_603E_v14,    0xFFFFFFFF, 603E),
+    /* PowerPC 603e v2.2                                                     */
+    POWERPC_DEF("603e2.2",     CPU_POWERPC_603E_v22,    0xFFFFFFFF, 603E),
+    /* PowerPC 603e v3                                                       */
+    POWERPC_DEF("603e3",       CPU_POWERPC_603E_v3,     0xFFFFFFFF, 603E),
+    /* PowerPC 603e v4                                                       */
+    POWERPC_DEF("603e4",       CPU_POWERPC_603E_v4,     0xFFFFFFFF, 603E),
+    /* PowerPC 603e v4.1                                                     */
+    POWERPC_DEF("603e4.1",     CPU_POWERPC_603E_v41,    0xFFFFFFFF, 603E),
+    /* PowerPC 603e                                                          */
+    POWERPC_DEF("603e7",       CPU_POWERPC_603E7,       0xFFFFFFFF, 603E),
+    /* PowerPC 603e7t                                                        */
+    POWERPC_DEF("603e7t",      CPU_POWERPC_603E7t,      0xFFFFFFFF, 603E),
+    /* PowerPC 603e7v                                                        */
+    POWERPC_DEF("603e7v",      CPU_POWERPC_603E7v,      0xFFFFFFFF, 603E),
+    /* Code name for PowerPC 603ev                                           */
+    POWERPC_DEF("Vaillant",    CPU_POWERPC_603E7v,      0xFFFFFFFF, 603E),
+    /* PowerPC 603e7v1                                                       */
+    POWERPC_DEF("603e7v1",     CPU_POWERPC_603E7v1,     0xFFFFFFFF, 603E),
+    /* PowerPC 603e7v2                                                       */
+    POWERPC_DEF("603e7v2",     CPU_POWERPC_603E7v2,     0xFFFFFFFF, 603E),
+    /* PowerPC 603p                                                          */
+    /* to be checked */
+    POWERPC_DEF("603p",        CPU_POWERPC_603P,        0xFFFFFFFF, 603),
+    /* PowerPC 603r                                                          */
+    POWERPC_DEF("603r",        CPU_POWERPC_603R,        0xFFFFFFFF, 603E),
+    /* Code name for PowerPC 603r                                            */
+    POWERPC_DEF("Goldeneye",   CPU_POWERPC_603R,        0xFFFFFFFF, 603E),
+    /* PowerPC G2 core                                                       */
+    POWERPC_DEF("G2",          CPU_POWERPC_G2,          0xFFFFFFFF, G2),
+    /* PowerPC G2 H4                                                         */
+    POWERPC_DEF("G2H4",        CPU_POWERPC_G2H4,        0xFFFFFFFF, G2),
+    /* PowerPC G2 GP                                                         */
+    POWERPC_DEF("G2GP",        CPU_POWERPC_G2gp,        0xFFFFFFFF, G2),
+    /* PowerPC G2 LS                                                         */
+    POWERPC_DEF("G2LS",        CPU_POWERPC_G2ls,        0xFFFFFFFF, G2),
+    /* PowerPC G2LE                                                          */
+    /* Same as G2, with little-endian mode support                           */
+    POWERPC_DEF("G2le",        CPU_POWERPC_G2LE,        0xFFFFFFFF, G2LE),
+    /* PowerPC G2LE GP                                                       */
+    POWERPC_DEF("G2leGP",      CPU_POWERPC_G2LEgp,      0xFFFFFFFF, G2LE),
+    /* PowerPC G2LE LS                                                       */
+    POWERPC_DEF("G2leLS",      CPU_POWERPC_G2LEls,      0xFFFFFFFF, G2LE),
+    /* PowerPC 604                                                           */
+    POWERPC_DEF("604",         CPU_POWERPC_604,         0xFFFFFFFF, 604),
+    /* PowerPC 604e                                                          */
+    POWERPC_DEF("604e",        CPU_POWERPC_604E,        0xFFFFFFFF, 604),
+    /* PowerPC 604e v1.0                                                     */
+    POWERPC_DEF("604e1.0",     CPU_POWERPC_604E_v10,    0xFFFFFFFF, 604),
+    /* PowerPC 604e v2.2                                                     */
+    POWERPC_DEF("604e2.2",     CPU_POWERPC_604E_v22,    0xFFFFFFFF, 604),
+    /* PowerPC 604e v2.4                                                     */
+    POWERPC_DEF("604e2.4",     CPU_POWERPC_604E_v24,    0xFFFFFFFF, 604),
+    /* PowerPC 604r                                                          */
+    POWERPC_DEF("604r",        CPU_POWERPC_604R,        0xFFFFFFFF, 604),
+#if defined(TODO)
+    /* PowerPC 604ev                                                         */
+    POWERPC_DEF("604ev",       CPU_POWERPC_604EV,       0xFFFFFFFF, 604),
+#endif
+    /* PowerPC 7xx family                                                    */
+    /* Generic PowerPC 740 (G3)                                              */
+    POWERPC_DEF("740",         CPU_POWERPC_7x0,         0xFFFFFFFF, 7x0),
+    /* Generic PowerPC 750 (G3)                                              */
+    POWERPC_DEF("750",         CPU_POWERPC_7x0,         0xFFFFFFFF, 7x0),
+    /* Code name for generic PowerPC 740/750 (G3)                            */
+    POWERPC_DEF("Arthur",      CPU_POWERPC_7x0,         0xFFFFFFFF, 7x0),
+    /* PowerPC 740/750 is also known as G3                                   */
+    POWERPC_DEF("G3",          CPU_POWERPC_7x0,         0xFFFFFFFF, 7x0),
+    /* PowerPC 740 v2.0 (G3)                                                 */
+    POWERPC_DEF("740v2.0",     CPU_POWERPC_7x0_v20,     0xFFFFFFFF, 7x0),
+    /* PowerPC 750 v2.0 (G3)                                                 */
+    POWERPC_DEF("750v2.0",     CPU_POWERPC_7x0_v20,     0xFFFFFFFF, 7x0),
+    /* PowerPC 740 v2.1 (G3)                                                 */
+    POWERPC_DEF("740v2.1",     CPU_POWERPC_7x0_v21,     0xFFFFFFFF, 7x0),
+    /* PowerPC 750 v2.1 (G3)                                                 */
+    POWERPC_DEF("750v2.1",     CPU_POWERPC_7x0_v21,     0xFFFFFFFF, 7x0),
+    /* PowerPC 740 v2.2 (G3)                                                 */
+    POWERPC_DEF("740v2.2",     CPU_POWERPC_7x0_v22,     0xFFFFFFFF, 7x0),
+    /* PowerPC 750 v2.2 (G3)                                                 */
+    POWERPC_DEF("750v2.2",     CPU_POWERPC_7x0_v22,     0xFFFFFFFF, 7x0),
+    /* PowerPC 740 v3.0 (G3)                                                 */
+    POWERPC_DEF("740v3.0",     CPU_POWERPC_7x0_v30,     0xFFFFFFFF, 7x0),
+    /* PowerPC 750 v3.0 (G3)                                                 */
+    POWERPC_DEF("750v3.0",     CPU_POWERPC_7x0_v30,     0xFFFFFFFF, 7x0),
+    /* PowerPC 740 v3.1 (G3)                                                 */
+    POWERPC_DEF("740v3.1",     CPU_POWERPC_7x0_v31,     0xFFFFFFFF, 7x0),
+    /* PowerPC 750 v3.1 (G3)                                                 */
+    POWERPC_DEF("750v3.1",     CPU_POWERPC_7x0_v31,     0xFFFFFFFF, 7x0),
+    /* PowerPC 740E (G3)                                                     */
+    POWERPC_DEF("740e",        CPU_POWERPC_740E,        0xFFFFFFFF, 7x0),
+    /* PowerPC 740P (G3)                                                     */
+    POWERPC_DEF("740p",        CPU_POWERPC_7x0P,        0xFFFFFFFF, 7x0),
+    /* PowerPC 750P (G3)                                                     */
+    POWERPC_DEF("750p",        CPU_POWERPC_7x0P,        0xFFFFFFFF, 7x0),
+    /* Code name for PowerPC 740P/750P (G3)                                  */
+    POWERPC_DEF("Conan/Doyle", CPU_POWERPC_7x0P,        0xFFFFFFFF, 7x0),
+    /* PowerPC 750CL (G3 embedded)                                           */
+    POWERPC_DEF("750cl",       CPU_POWERPC_750CL,       0xFFFFFFFF, 7x0),
+    /* PowerPC 750CX (G3 embedded)                                           */
+    POWERPC_DEF("750cx",       CPU_POWERPC_750CX,       0xFFFFFFFF, 7x0),
+    /* PowerPC 750CX v2.1 (G3 embedded)                                      */
+    POWERPC_DEF("750cx2.1",    CPU_POWERPC_750CX_v21,   0xFFFFFFFF, 7x0),
+    /* PowerPC 750CX v2.2 (G3 embedded)                                      */
+    POWERPC_DEF("750cx2.2",    CPU_POWERPC_750CX_v22,   0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXe (G3 embedded)                                          */
+    POWERPC_DEF("750cxe",      CPU_POWERPC_750CXE,      0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXe v2.1 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe21",    CPU_POWERPC_750CXE_v21,  0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXe v2.2 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe22",    CPU_POWERPC_750CXE_v22,  0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXe v2.3 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe23",    CPU_POWERPC_750CXE_v23,  0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXe v2.4 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe24",    CPU_POWERPC_750CXE_v24,  0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXe v2.4b (G3 embedded)                                    */
+    POWERPC_DEF("750cxe24b",   CPU_POWERPC_750CXE_v24b, 0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXe v3.1 (G3 embedded)                                     */
+    POWERPC_DEF("750cxe31",    CPU_POWERPC_750CXE_v31,  0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXe v3.1b (G3 embedded)                                    */
+    POWERPC_DEF("750cxe3.1b",  CPU_POWERPC_750CXE_v31b, 0xFFFFFFFF, 7x0),
+    /* PowerPC 750CXr (G3 embedded)                                          */
+    POWERPC_DEF("750cxr",      CPU_POWERPC_750CXR,      0xFFFFFFFF, 7x0),
+    /* PowerPC 750E (G3)                                                     */
+    POWERPC_DEF("750e",        CPU_POWERPC_750E,        0xFFFFFFFF, 7x0),
+    /* PowerPC 750FL (G3 embedded)                                           */
+    POWERPC_DEF("750fl",       CPU_POWERPC_750FL,       0xFFFFFFFF, 750fx),
+    /* PowerPC 750FX (G3 embedded)                                           */
+    POWERPC_DEF("750fx",       CPU_POWERPC_750FX,       0xFFFFFFFF, 750fx),
+    /* PowerPC 750FX v1.0 (G3 embedded)                                      */
+    POWERPC_DEF("750fx1.0",    CPU_POWERPC_750FX_v10,   0xFFFFFFFF, 750fx),
+    /* PowerPC 750FX v2.0 (G3 embedded)                                      */
+    POWERPC_DEF("750fx2.0",    CPU_POWERPC_750FX_v20,   0xFFFFFFFF, 750fx),
+    /* PowerPC 750FX v2.1 (G3 embedded)                                      */
+    POWERPC_DEF("750fx2.1",    CPU_POWERPC_750FX_v21,   0xFFFFFFFF, 750fx),
+    /* PowerPC 750FX v2.2 (G3 embedded)                                      */
+    POWERPC_DEF("750fx2.2",    CPU_POWERPC_750FX_v22,   0xFFFFFFFF, 750fx),
+    /* PowerPC 750FX v2.3 (G3 embedded)                                      */
+    POWERPC_DEF("750fx2.3",    CPU_POWERPC_750FX_v23,   0xFFFFFFFF, 750fx),
+    /* PowerPC 750GL (G3 embedded)                                           */
+    POWERPC_DEF("750gl",       CPU_POWERPC_750GL,       0xFFFFFFFF, 750fx),
+    /* PowerPC 750GX (G3 embedded)                                           */
+    POWERPC_DEF("750gx",       CPU_POWERPC_750GX,       0xFFFFFFFF, 750fx),
+    /* PowerPC 750GX v1.0 (G3 embedded)                                      */
+    POWERPC_DEF("750gx1.0",    CPU_POWERPC_750GX_v10,   0xFFFFFFFF, 750fx),
+    /* PowerPC 750GX v1.1 (G3 embedded)                                      */
+    POWERPC_DEF("750gx1.1",    CPU_POWERPC_750GX_v11,   0xFFFFFFFF, 750fx),
+    /* PowerPC 750GX v1.2 (G3 embedded)                                      */
+    POWERPC_DEF("750gx1.2",    CPU_POWERPC_750GX_v12,   0xFFFFFFFF, 750fx),
+    /* PowerPC 750L (G3 embedded)                                            */
+    POWERPC_DEF("750l",        CPU_POWERPC_750L,        0xFFFFFFFF, 7x0),
+    /* Code name for PowerPC 750L (G3 embedded)                              */
+    POWERPC_DEF("LoneStar",    CPU_POWERPC_750L,        0xFFFFFFFF, 7x0),
+    /* PowerPC 750L v2.2 (G3 embedded)                                       */
+    POWERPC_DEF("750l2.2",     CPU_POWERPC_750L_v22,    0xFFFFFFFF, 7x0),
+    /* PowerPC 750L v3.0 (G3 embedded)                                       */
+    POWERPC_DEF("750l3.0",     CPU_POWERPC_750L_v30,    0xFFFFFFFF, 7x0),
+    /* PowerPC 750L v3.2 (G3 embedded)                                       */
+    POWERPC_DEF("750l3.2",     CPU_POWERPC_750L_v32,    0xFFFFFFFF, 7x0),
+    /* Generic PowerPC 745                                                   */
+    POWERPC_DEF("745",         CPU_POWERPC_7x5,         0xFFFFFFFF, 7x5),
+    /* Generic PowerPC 755                                                   */
+    POWERPC_DEF("755",         CPU_POWERPC_7x5,         0xFFFFFFFF, 7x5),
+    /* Code name for PowerPC 745/755                                         */
+    POWERPC_DEF("Goldfinger",  CPU_POWERPC_7x5,         0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v1.0                                                      */
+    POWERPC_DEF("745v1.0",     CPU_POWERPC_7x5_v10,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v1.0                                                      */
+    POWERPC_DEF("755v1.0",     CPU_POWERPC_7x5_v10,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v1.1                                                      */
+    POWERPC_DEF("745v1.1",     CPU_POWERPC_7x5_v11,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v1.1                                                      */
+    POWERPC_DEF("755v1.1",     CPU_POWERPC_7x5_v11,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.0                                                      */
+    POWERPC_DEF("745v2.0",     CPU_POWERPC_7x5_v20,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.0                                                      */
+    POWERPC_DEF("755v2.0",     CPU_POWERPC_7x5_v20,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.1                                                      */
+    POWERPC_DEF("745v2.1",     CPU_POWERPC_7x5_v21,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.1                                                      */
+    POWERPC_DEF("755v2.1",     CPU_POWERPC_7x5_v21,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.2                                                      */
+    POWERPC_DEF("745v2.2",     CPU_POWERPC_7x5_v22,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.2                                                      */
+    POWERPC_DEF("755v2.2",     CPU_POWERPC_7x5_v22,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.3                                                      */
+    POWERPC_DEF("745v2.3",     CPU_POWERPC_7x5_v23,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.3                                                      */
+    POWERPC_DEF("755v2.3",     CPU_POWERPC_7x5_v23,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.4                                                      */
+    POWERPC_DEF("745v2.4",     CPU_POWERPC_7x5_v24,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.4                                                      */
+    POWERPC_DEF("755v2.4",     CPU_POWERPC_7x5_v24,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.5                                                      */
+    POWERPC_DEF("745v2.5",     CPU_POWERPC_7x5_v25,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.5                                                      */
+    POWERPC_DEF("755v2.5",     CPU_POWERPC_7x5_v25,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.6                                                      */
+    POWERPC_DEF("745v2.6",     CPU_POWERPC_7x5_v26,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.6                                                      */
+    POWERPC_DEF("755v2.6",     CPU_POWERPC_7x5_v26,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.7                                                      */
+    POWERPC_DEF("745v2.7",     CPU_POWERPC_7x5_v27,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.7                                                      */
+    POWERPC_DEF("755v2.7",     CPU_POWERPC_7x5_v27,     0xFFFFFFFF, 7x5),
+    /* PowerPC 745 v2.8                                                      */
+    POWERPC_DEF("745v2.8",     CPU_POWERPC_7x5_v28,     0xFFFFFFFF, 7x5),
+    /* PowerPC 755 v2.8                                                      */
+    POWERPC_DEF("755v2.8",     CPU_POWERPC_7x5_v28,     0xFFFFFFFF, 7x5),
+#if defined (TODO)
+    /* PowerPC 745P (G3)                                                     */
+    POWERPC_DEF("745p",        CPU_POWERPC_7x5P,        0xFFFFFFFF, 7x5),
+    /* PowerPC 755P (G3)                                                     */
+    POWERPC_DEF("755p",        CPU_POWERPC_7x5P,        0xFFFFFFFF, 7x5),
+#endif
+    /* PowerPC 74xx family                                                   */
+    /* PowerPC 7400 (G4)                                                     */
+    POWERPC_DEF("7400",        CPU_POWERPC_7400,        0xFFFFFFFF, 7400),
+    /* Code name for PowerPC 7400                                            */
+    POWERPC_DEF("Max",         CPU_POWERPC_7400,        0xFFFFFFFF, 7400),
+    /* PowerPC 74xx is also well known as G4                                 */
+    POWERPC_DEF("G4",          CPU_POWERPC_7400,        0xFFFFFFFF, 7400),
+    /* PowerPC 7400 v1.0 (G4)                                                */
+    POWERPC_DEF("7400v1.0",    CPU_POWERPC_7400_v10,    0xFFFFFFFF, 7400),
+    /* PowerPC 7400 v1.1 (G4)                                                */
+    POWERPC_DEF("7400v1.1",    CPU_POWERPC_7400_v11,    0xFFFFFFFF, 7400),
+    /* PowerPC 7400 v2.0 (G4)                                                */
+    POWERPC_DEF("7400v2.0",    CPU_POWERPC_7400_v20,    0xFFFFFFFF, 7400),
+    /* PowerPC 7400 v2.2 (G4)                                                */
+    POWERPC_DEF("7400v2.2",    CPU_POWERPC_7400_v22,    0xFFFFFFFF, 7400),
+    /* PowerPC 7400 v2.6 (G4)                                                */
+    POWERPC_DEF("7400v2.6",    CPU_POWERPC_7400_v26,    0xFFFFFFFF, 7400),
+    /* PowerPC 7400 v2.7 (G4)                                                */
+    POWERPC_DEF("7400v2.7",    CPU_POWERPC_7400_v27,    0xFFFFFFFF, 7400),
+    /* PowerPC 7400 v2.8 (G4)                                                */
+    POWERPC_DEF("7400v2.8",    CPU_POWERPC_7400_v28,    0xFFFFFFFF, 7400),
+    /* PowerPC 7400 v2.9 (G4)                                                */
+    POWERPC_DEF("7400v2.9",    CPU_POWERPC_7400_v29,    0xFFFFFFFF, 7400),
+    /* PowerPC 7410 (G4)                                                     */
+    POWERPC_DEF("7410",        CPU_POWERPC_7410,        0xFFFFFFFF, 7410),
+    /* Code name for PowerPC 7410                                            */
+    POWERPC_DEF("Nitro",       CPU_POWERPC_7410,        0xFFFFFFFF, 7410),
+    /* PowerPC 7410 v1.0 (G4)                                                */
+    POWERPC_DEF("7410v1.0",    CPU_POWERPC_7410_v10,    0xFFFFFFFF, 7410),
+    /* PowerPC 7410 v1.1 (G4)                                                */
+    POWERPC_DEF("7410v1.1",    CPU_POWERPC_7410_v11,    0xFFFFFFFF, 7410),
+    /* PowerPC 7410 v1.2 (G4)                                                */
+    POWERPC_DEF("7410v1.2",    CPU_POWERPC_7410_v12,    0xFFFFFFFF, 7410),
+    /* PowerPC 7410 v1.3 (G4)                                                */
+    POWERPC_DEF("7410v1.3",    CPU_POWERPC_7410_v13,    0xFFFFFFFF, 7410),
+    /* PowerPC 7410 v1.4 (G4)                                                */
+    POWERPC_DEF("7410v1.4",    CPU_POWERPC_7410_v14,    0xFFFFFFFF, 7410),
+    /* PowerPC 7448 (G4)                                                     */
+    POWERPC_DEF("7448",        CPU_POWERPC_7448,        0xFFFFFFFF, 7400),
+    /* PowerPC 7448 v1.0 (G4)                                                */
+    POWERPC_DEF("7448v1.0",    CPU_POWERPC_7448_v10,    0xFFFFFFFF, 7400),
+    /* PowerPC 7448 v1.1 (G4)                                                */
+    POWERPC_DEF("7448v1.1",    CPU_POWERPC_7448_v11,    0xFFFFFFFF, 7400),
+    /* PowerPC 7448 v2.0 (G4)                                                */
+    POWERPC_DEF("7448v2.0",    CPU_POWERPC_7448_v20,    0xFFFFFFFF, 7400),
+    /* PowerPC 7448 v2.1 (G4)                                                */
+    POWERPC_DEF("7448v2.1",    CPU_POWERPC_7448_v21,    0xFFFFFFFF, 7400),
+#if defined (TODO)
+    /* PowerPC 7450 (G4)                                                     */
+    POWERPC_DEF("7450",        CPU_POWERPC_7450,        0xFFFFFFFF, 7450),
+    /* Code name for PowerPC 7450                                            */
+    POWERPC_DEF("Vger",        CPU_POWERPC_7450,        0xFFFFFFFF, 7450),
+#endif
+#if defined (TODO)
+    /* PowerPC 7450 v1.0 (G4)                                                */
+    POWERPC_DEF("7450v1.0",    CPU_POWERPC_7450_v10,    0xFFFFFFFF, 7450),
+#endif
+#if defined (TODO)
+    /* PowerPC 7450 v1.1 (G4)                                                */
+    POWERPC_DEF("7450v1.1",    CPU_POWERPC_7450_v11,    0xFFFFFFFF, 7450),
+#endif
+#if defined (TODO)
+    /* PowerPC 7450 v1.2 (G4)                                                */
+    POWERPC_DEF("7450v1.2",    CPU_POWERPC_7450_v12,    0xFFFFFFFF, 7450),
+#endif
+#if defined (TODO)
+    /* PowerPC 7450 v2.0 (G4)                                                */
+    POWERPC_DEF("7450v2.0",    CPU_POWERPC_7450_v20,    0xFFFFFFFF, 7450),
+#endif
+#if defined (TODO)
+    /* PowerPC 7450 v2.1 (G4)                                                */
+    POWERPC_DEF("7450v2.1",    CPU_POWERPC_7450_v21,    0xFFFFFFFF, 7450),
+#endif
+#if defined (TODO)
+    /* PowerPC 7441 (G4)                                                     */
+    POWERPC_DEF("7441",        CPU_POWERPC_74x1,        0xFFFFFFFF, 7440),
+    /* PowerPC 7451 (G4)                                                     */
+    POWERPC_DEF("7451",        CPU_POWERPC_74x1,        0xFFFFFFFF, 7450),
+#endif
+#if defined (TODO)
+    /* PowerPC 7441g (G4)                                                    */
+    POWERPC_DEF("7441g",       CPU_POWERPC_74x1G,       0xFFFFFFFF, 7440),
+    /* PowerPC 7451g (G4)                                                    */
+    POWERPC_DEF("7451g",       CPU_POWERPC_74x1G,       0xFFFFFFFF, 7450),
+#endif
+#if defined (TODO)
+    /* PowerPC 7445 (G4)                                                     */
+    POWERPC_DEF("7445",        CPU_POWERPC_74x5,        0xFFFFFFFF, 7445),
+    /* PowerPC 7455 (G4)                                                     */
+    POWERPC_DEF("7455",        CPU_POWERPC_74x5,        0xFFFFFFFF, 7455),
+    /* Code name for PowerPC 7445/7455                                       */
+    POWERPC_DEF("Apollo6",     CPU_POWERPC_74x5,        0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7445 v1.0 (G4)                                                */
+    POWERPC_DEF("7445v1.0",    CPU_POWERPC_74x5_v10,    0xFFFFFFFF, 7445),
+    /* PowerPC 7455 v1.0 (G4)                                                */
+    POWERPC_DEF("7455v1.0",    CPU_POWERPC_74x5_v10,    0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7445 v2.1 (G4)                                                */
+    POWERPC_DEF("7445v2.1",    CPU_POWERPC_74x5_v21,    0xFFFFFFFF, 7445),
+    /* PowerPC 7455 v2.1 (G4)                                                */
+    POWERPC_DEF("7455v2.1",    CPU_POWERPC_74x5_v21,    0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7445 v3.2 (G4)                                                */
+    POWERPC_DEF("7445v3.2",    CPU_POWERPC_74x5_v32,    0xFFFFFFFF, 7445),
+    /* PowerPC 7455 v3.2 (G4)                                                */
+    POWERPC_DEF("7455v3.2",    CPU_POWERPC_74x5_v32,    0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7445 v3.3 (G4)                                                */
+    POWERPC_DEF("7445v3.3",    CPU_POWERPC_74x5_v33,    0xFFFFFFFF, 7445),
+    /* PowerPC 7455 v3.3 (G4)                                                */
+    POWERPC_DEF("7455v3.3",    CPU_POWERPC_74x5_v33,    0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7445 v3.4 (G4)                                                */
+    POWERPC_DEF("7445v3.4",    CPU_POWERPC_74x5_v34,    0xFFFFFFFF, 7445),
+    /* PowerPC 7455 v3.4 (G4)                                                */
+    POWERPC_DEF("7455v3.4",    CPU_POWERPC_74x5_v34,    0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7447 (G4)                                                     */
+    POWERPC_DEF("7447",        CPU_POWERPC_74x7,        0xFFFFFFFF, 7445),
+    /* PowerPC 7457 (G4)                                                     */
+    POWERPC_DEF("7457",        CPU_POWERPC_74x7,        0xFFFFFFFF, 7455),
+    /* Code name for PowerPC 7447/7457                                       */
+    POWERPC_DEF("Apollo7",     CPU_POWERPC_74x7,        0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7447 v1.0 (G4)                                                */
+    POWERPC_DEF("7447v1.0",    CPU_POWERPC_74x7_v10,    0xFFFFFFFF, 7445),
+    /* PowerPC 7457 v1.0 (G4)                                                */
+    POWERPC_DEF("7457v1.0",    CPU_POWERPC_74x7_v10,    0xFFFFFFFF, 7455),
+    /* Code name for PowerPC 7447A/7457A                                     */
+    POWERPC_DEF("Apollo7PM",   CPU_POWERPC_74x7_v10,    0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7447 v1.1 (G4)                                                */
+    POWERPC_DEF("7447v1.1",    CPU_POWERPC_74x7_v11,    0xFFFFFFFF, 7445),
+    /* PowerPC 7457 v1.1 (G4)                                                */
+    POWERPC_DEF("7457v1.1",    CPU_POWERPC_74x7_v11,    0xFFFFFFFF, 7455),
+#endif
+#if defined (TODO)
+    /* PowerPC 7447 v1.2 (G4)                                                */
+    POWERPC_DEF("7447v1.2",    CPU_POWERPC_74x7_v12,    0xFFFFFFFF, 7445),
+    /* PowerPC 7457 v1.2 (G4)                                                */
+    POWERPC_DEF("7457v1.2",    CPU_POWERPC_74x7_v12,    0xFFFFFFFF, 7455),
+#endif
+    /* 64 bits PowerPC                                                       */
+#if defined (TARGET_PPC64)
+#if defined (TODO)
+    /* PowerPC 620                                                           */
+    POWERPC_DEF("620",         CPU_POWERPC_620,         0xFFFFFFFF, 620),
+#endif
+#if defined (TODO)
+    /* PowerPC 630 (POWER3)                                                  */
+    POWERPC_DEF("630",         CPU_POWERPC_630,         0xFFFFFFFF, 630),
+    POWERPC_DEF("POWER3",      CPU_POWERPC_630,         0xFFFFFFFF, 630),
+#endif
+#if defined (TODO)
+    /* PowerPC 631 (Power 3+)                                                */
+    POWERPC_DEF("631",         CPU_POWERPC_631,         0xFFFFFFFF, 631),
+    POWERPC_DEF("POWER3+",     CPU_POWERPC_631,         0xFFFFFFFF, 631),
+#endif
+#if defined (TODO)
+    /* POWER4                                                                */
+    POWERPC_DEF("POWER4",      CPU_POWERPC_POWER4,      0xFFFFFFFF, POWER4),
+#endif
+#if defined (TODO)
+    /* POWER4p                                                               */
+    POWERPC_DEF("POWER4+",     CPU_POWERPC_POWER4P,     0xFFFFFFFF, POWER4P),
+#endif
+#if defined (TODO)
+    /* POWER5                                                                */
+    POWERPC_DEF("POWER5",      CPU_POWERPC_POWER5,      0xFFFFFFFF, POWER5),
+    /* POWER5GR                                                              */
+    POWERPC_DEF("POWER5gr",    CPU_POWERPC_POWER5GR,    0xFFFFFFFF, POWER5),
+#endif
+#if defined (TODO)
+    /* POWER5+                                                               */
+    POWERPC_DEF("POWER5+",     CPU_POWERPC_POWER5P,     0xFFFFFFFF, POWER5P),
+    /* POWER5GS                                                              */
+    POWERPC_DEF("POWER5gs",    CPU_POWERPC_POWER5GS,    0xFFFFFFFF, POWER5P),
+#endif
+#if defined (TODO)
+    /* POWER6                                                                */
+    POWERPC_DEF("POWER6",      CPU_POWERPC_POWER6,      0xFFFFFFFF, POWER6),
+    /* POWER6 running in POWER5 mode                                         */
+    POWERPC_DEF("POWER6_5",    CPU_POWERPC_POWER6_5,    0xFFFFFFFF, POWER5),
+    /* POWER6A                                                               */
+    POWERPC_DEF("POWER6A",     CPU_POWERPC_POWER6A,     0xFFFFFFFF, POWER6),
+#endif
+    /* PowerPC 970                                                           */
+    POWERPC_DEF("970",         CPU_POWERPC_970,         0xFFFFFFFF, 970),
+    /* PowerPC 970FX (G5)                                                    */
+    POWERPC_DEF("970fx",       CPU_POWERPC_970FX,       0xFFFFFFFF, 970FX),
+    /* PowerPC 970FX v1.0 (G5)                                               */
+    POWERPC_DEF("970fx1.0",    CPU_POWERPC_970FX_v10,   0xFFFFFFFF, 970FX),
+    /* PowerPC 970FX v2.0 (G5)                                               */
+    POWERPC_DEF("970fx2.0",    CPU_POWERPC_970FX_v20,   0xFFFFFFFF, 970FX),
+    /* PowerPC 970FX v2.1 (G5)                                               */
+    POWERPC_DEF("970fx2.1",    CPU_POWERPC_970FX_v21,   0xFFFFFFFF, 970FX),
+    /* PowerPC 970FX v3.0 (G5)                                               */
+    POWERPC_DEF("970fx3.0",    CPU_POWERPC_970FX_v30,   0xFFFFFFFF, 970FX),
+    /* PowerPC 970FX v3.1 (G5)                                               */
+    POWERPC_DEF("970fx3.1",    CPU_POWERPC_970FX_v31,   0xFFFFFFFF, 970FX),
+    /* PowerPC 970GX (G5)                                                    */
+    POWERPC_DEF("970gx",       CPU_POWERPC_970GX,       0xFFFFFFFF, 970GX),
+    /* PowerPC 970MP                                                         */
+    POWERPC_DEF("970mp",       CPU_POWERPC_970MP,       0xFFFFFFFF, 970),
+    /* PowerPC 970MP v1.0                                                    */
+    POWERPC_DEF("970mp1.0",    CPU_POWERPC_970MP_v10,   0xFFFFFFFF, 970),
+    /* PowerPC 970MP v1.1                                                    */
+    POWERPC_DEF("970mp1.1",    CPU_POWERPC_970MP_v11,   0xFFFFFFFF, 970),
+#if defined (TODO)
+    /* PowerPC Cell                                                          */
+    POWERPC_DEF("Cell",        CPU_POWERPC_CELL,        0xFFFFFFFF, 970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v1.0                                                     */
+    POWERPC_DEF("Cell1.0",     CPU_POWERPC_CELL_v10,    0xFFFFFFFF, 970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v2.0                                                     */
+    POWERPC_DEF("Cell2.0",     CPU_POWERPC_CELL_v20,    0xFFFFFFFF, 970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v3.0                                                     */
+    POWERPC_DEF("Cell3.0",     CPU_POWERPC_CELL_v30,    0xFFFFFFFF, 970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v3.1                                                     */
+    POWERPC_DEF("Cell3.1",     CPU_POWERPC_CELL_v31,    0xFFFFFFFF, 970),
+#endif
+#if defined (TODO)
+    /* PowerPC Cell v3.2                                                     */
+    POWERPC_DEF("Cell3.2",     CPU_POWERPC_CELL_v32,    0xFFFFFFFF, 970),
+#endif
+#if defined (TODO)
+    /* RS64 (Apache/A35)                                                     */
+    /* This one seems to support the whole POWER2 instruction set
+     * and the PowerPC 64 one.
+     */
+    /* What about A10 & A30 ? */
+    POWERPC_DEF("RS64",        CPU_POWERPC_RS64,        0xFFFFFFFF, RS64),
+    POWERPC_DEF("Apache",      CPU_POWERPC_RS64,        0xFFFFFFFF, RS64),
+    POWERPC_DEF("A35",         CPU_POWERPC_RS64,        0xFFFFFFFF, RS64),
+#endif
+#if defined (TODO)
+    /* RS64-II (NorthStar/A50)                                               */
+    POWERPC_DEF("RS64-II",     CPU_POWERPC_RS64II,      0xFFFFFFFF, RS64),
+    POWERPC_DEF("NorthStar",   CPU_POWERPC_RS64II,      0xFFFFFFFF, RS64),
+    POWERPC_DEF("A50",         CPU_POWERPC_RS64II,      0xFFFFFFFF, RS64),
+#endif
+#if defined (TODO)
+    /* RS64-III (Pulsar)                                                     */
+    POWERPC_DEF("RS64-III",    CPU_POWERPC_RS64III,     0xFFFFFFFF, RS64),
+    POWERPC_DEF("Pulsar",      CPU_POWERPC_RS64III,     0xFFFFFFFF, RS64),
+#endif
+#if defined (TODO)
+    /* RS64-IV (IceStar/IStar/SStar)                                         */
+    POWERPC_DEF("RS64-IV",     CPU_POWERPC_RS64IV,      0xFFFFFFFF, RS64),
+    POWERPC_DEF("IceStar",     CPU_POWERPC_RS64IV,      0xFFFFFFFF, RS64),
+    POWERPC_DEF("IStar",       CPU_POWERPC_RS64IV,      0xFFFFFFFF, RS64),
+    POWERPC_DEF("SStar",       CPU_POWERPC_RS64IV,      0xFFFFFFFF, RS64),
+#endif
+#endif /* defined (TARGET_PPC64) */
+    /* POWER                                                                 */
+#if defined (TODO)
+    /* Original POWER                                                        */
+    POWERPC_DEF("POWER",       CPU_POWERPC_POWER,       0xFFFFFFFF, POWER),
+    POWERPC_DEF("RIOS",        CPU_POWERPC_POWER,       0xFFFFFFFF, POWER),
+    POWERPC_DEF("RSC",         CPU_POWERPC_POWER,       0xFFFFFFFF, POWER),
+    POWERPC_DEF("RSC3308",     CPU_POWERPC_POWER,       0xFFFFFFFF, POWER),
+    POWERPC_DEF("RSC4608",     CPU_POWERPC_POWER,       0xFFFFFFFF, POWER),
+#endif
+#if defined (TODO)
+    /* POWER2                                                                */
+    POWERPC_DEF("POWER2",      CPU_POWERPC_POWER2,      0xFFFFFFFF, POWER),
+    POWERPC_DEF("RSC2",        CPU_POWERPC_POWER2,      0xFFFFFFFF, POWER),
+    POWERPC_DEF("P2SC",        CPU_POWERPC_POWER2,      0xFFFFFFFF, POWER),
+#endif
+    /* PA semi cores                                                         */
+#if defined (TODO)
+    /* PA PA6T */
+    POWERPC_DEF("PA6T",        CPU_POWERPC_PA6T,        0xFFFFFFFF, PA6T),
+#endif
+    /* Generic PowerPCs                                                      */
+#if defined (TARGET_PPC64)
+#if defined (TODO)
+    POWERPC_DEF("ppc64",       CPU_POWERPC_PPC64,       0xFFFFFFFF, PPC64),
+#endif
+#endif
+    POWERPC_DEF("ppc32",       CPU_POWERPC_PPC32,       0xFFFFFFFF, PPC32),
+    POWERPC_DEF("ppc",         CPU_POWERPC_DEFAULT,     0xFFFFFFFF, DEFAULT),
+    /* Fallback                                                              */
+    POWERPC_DEF("default",     CPU_POWERPC_DEFAULT,     0xFFFFFFFF, DEFAULT),
+};
+
+/*****************************************************************************/
+/* Generic CPU instanciation routine                                         */
 static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
 {
+#if !defined(CONFIG_USER_ONLY)
+    int i;
+
+    env->irq_inputs = NULL;
+    /* Set all exception vectors to an invalid address */
+    for (i = 0; i < POWERPC_EXCP_NB; i++)
+        env->excp_vectors[i] = (target_ulong)(-1ULL);
+    env->excp_prefix = 0x00000000;
+    env->ivor_mask = 0x00000000;
+    env->ivpr_mask = 0x00000000;
+#endif
     /* Default MMU definitions */
-    env->nb_BATs = -1;
+    env->nb_BATs = 0;
     env->nb_tlb = 0;
     env->nb_ways = 0;
-    /* XXX: missing:
-     * 32 bits PPC:
-     * - MPC5xx(x)
-     * - MPC8xx(x)
-     * - RCPU (MPC5xx)
-     */
+    /* Register SPR common to all PowerPC implementations */
+    gen_spr_generic(env);
     spr_register(env, SPR_PVR, "PVR",
                  SPR_NOACCESS, SPR_NOACCESS,
                  &spr_read_generic, SPR_NOACCESS,
                  def->pvr);
-    switch (def->pvr & def->pvr_mask) {
-    case CPU_PPC_604:     /* PPC 604                       */
-    case CPU_PPC_604E:    /* PPC 604e                      */
-    case CPU_PPC_604R:    /* PPC 604r                      */
-        gen_spr_generic(env);
-        gen_spr_ne_601(env);
-        /* Memory management */
-        gen_low_BATs(env);
-        /* Time base */
-        gen_tbl(env);
-        gen_spr_604(env);
-        /* Hardware implementation registers */
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID0, "HID0",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID1, "HID1",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        break;
-
-    case CPU_PPC_74x:     /* PPC 740 / 750                 */
-    case CPU_PPC_74xP:    /* PPC 740P / 750P               */
-    case CPU_PPC_750CXE:  /* IBM PPC 750cxe                */
-        gen_spr_generic(env);
-        gen_spr_ne_601(env);
-        /* Memory management */
-        gen_low_BATs(env);
-        /* Time base */
-        gen_tbl(env);
-        gen_spr_7xx(env);
-        /* XXX : not implemented */
-        spr_register(env, SPR_L2CR, "L2CR",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* Hardware implementation registers */
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID0, "HID0",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID1, "HID1",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        break;
-
-    case CPU_PPC_750FX:   /* IBM PPC 750 FX                */
-    case CPU_PPC_750GX:   /* IBM PPC 750 GX                */
-        gen_spr_generic(env);
-        gen_spr_ne_601(env);
-        /* Memory management */
-        gen_low_BATs(env);
-        /* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
-        gen_high_BATs(env);
-        /* Time base */
-        gen_tbl(env);
-        gen_spr_7xx(env);
-        /* XXX : not implemented */
-        spr_register(env, SPR_L2CR, "L2CR",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* Hardware implementation registers */
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID0, "HID0",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* XXX : not implemented */
-        spr_register(env, SPR_HID1, "HID1",
-                 SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        /* XXX : not implemented */
-        spr_register(env, SPR_750_HID2, "HID2",
-                     SPR_NOACCESS, SPR_NOACCESS,
-                     &spr_read_generic, &spr_write_generic,
-                     0x00000000);
-        break;
-
-    default:
-        gen_spr_generic(env);
-        break;
+    /* PowerPC implementation specific initialisations (SPRs, timers, ...) */
+    (*def->init_proc)(env);
+    /* Allocate TLBs buffer when needed */
+    if (env->nb_tlb != 0) {
+        int nb_tlb = env->nb_tlb;
+        if (env->id_tlbs != 0)
+            nb_tlb *= 2;
+        env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t));
+        /* Pre-compute some useful values */
+        env->tlb_per_way = env->nb_tlb / env->nb_ways;
     }
-    if (env->nb_BATs == -1)
-        env->nb_BATs = 4;
+#if !defined(CONFIG_USER_ONLY)
+    if (env->irq_inputs == NULL) {
+        fprintf(stderr, "WARNING: no internal IRQ controller registered.\n"
+                " Attempt Qemu to crash very soon !\n");
+    }
+#endif
 }
 
 #if defined(PPC_DUMP_CPU)
-static void dump_sprs (CPUPPCState *env)
+static void dump_ppc_sprs (CPUPPCState *env)
 {
     ppc_spr_t *spr;
-    uint32_t pvr = env->spr[SPR_PVR];
-    uint32_t sr, sw, ur, uw;
+#if !defined(CONFIG_USER_ONLY)
+    uint32_t sr, sw;
+#endif
+    uint32_t ur, uw;
     int i, j, n;
 
-    printf("* SPRs for PVR=%08x\n", pvr);
+    printf("Special purpose registers:\n");
     for (i = 0; i < 32; i++) {
         for (j = 0; j < 32; j++) {
             n = (i << 5) | j;
             spr = &env->spr_cb[n];
-            sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS;
-            sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS;
             uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS;
             ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS;
+#if !defined(CONFIG_USER_ONLY)
+            sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS;
+            sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS;
             if (sw || sr || uw || ur) {
-                printf("%4d (%03x) %8s s%c%c u%c%c\n",
+                printf("SPR: %4d (%03x) %-8s s%c%c u%c%c\n",
                        (i << 5) | j, (i << 5) | j, spr->name,
                        sw ? 'w' : '-', sr ? 'r' : '-',
                        uw ? 'w' : '-', ur ? 'r' : '-');
             }
+#else
+            if (uw || ur) {
+                printf("SPR: %4d (%03x) %-8s u%c%c\n",
+                       (i << 5) | j, (i << 5) | j, spr->name,
+                       uw ? 'w' : '-', ur ? 'r' : '-');
+            }
+#endif
         }
     }
     fflush(stdout);
@@ -889,7 +5626,7 @@
 {
     if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
         printf("*** ERROR: opcode %02x already assigned in main "
-                "opcode table\n", idx);
+               "opcode table\n", idx);
         return -1;
     }
 
@@ -903,20 +5640,20 @@
     if (table[idx1] == &invalid_handler) {
         if (create_new_table(table, idx1) < 0) {
             printf("*** ERROR: unable to create indirect table "
-                    "idx=%02x\n", idx1);
+                   "idx=%02x\n", idx1);
             return -1;
         }
     } else {
         if (!is_indirect_opcode(table[idx1])) {
             printf("*** ERROR: idx %02x already assigned to a direct "
-                    "opcode\n", idx1);
+                   "opcode\n", idx1);
             return -1;
         }
     }
     if (handler != NULL &&
         insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
         printf("*** ERROR: opcode %02x already assigned in "
-                "opcode table %02x\n", idx2, idx1);
+               "opcode table %02x\n", idx2, idx1);
         return -1;
     }
 
@@ -925,7 +5662,7 @@
 
 static int register_ind_insn (opc_handler_t **ppc_opcodes,
                               unsigned char idx1, unsigned char idx2,
-                               opc_handler_t *handler)
+                              opc_handler_t *handler)
 {
     int ret;
 
@@ -934,19 +5671,19 @@
     return ret;
 }
 
-static int register_dblind_insn (opc_handler_t **ppc_opcodes, 
+static int register_dblind_insn (opc_handler_t **ppc_opcodes,
                                  unsigned char idx1, unsigned char idx2,
-                                  unsigned char idx3, opc_handler_t *handler)
+                                 unsigned char idx3, opc_handler_t *handler)
 {
     if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
         printf("*** ERROR: unable to join indirect table idx "
-                "[%02x-%02x]\n", idx1, idx2);
+               "[%02x-%02x]\n", idx1, idx2);
         return -1;
     }
     if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
                               handler) < 0) {
         printf("*** ERROR: unable to insert opcode "
-                "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
+               "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
         return -1;
     }
 
@@ -1011,43 +5748,21 @@
     opcode_t *opc, *start, *end;
 
     fill_new_table(env->opcodes, 0x40);
-#if defined(PPC_DUMP_CPU)
-    printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name);
-#endif
     if (&opc_start < &opc_end) {
-	start = &opc_start;
-	end = &opc_end;
+        start = &opc_start;
+        end = &opc_end;
     } else {
-	start = &opc_end;
-	end = &opc_start;
+        start = &opc_end;
+        end = &opc_start;
     }
     for (opc = start + 1; opc != end; opc++) {
         if ((opc->handler.type & def->insns_flags) != 0) {
             if (register_insn(env->opcodes, opc) < 0) {
-                printf("*** ERROR initializing PPC instruction "
-                        "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
-                        opc->opc3);
+                printf("*** ERROR initializing PowerPC instruction "
+                       "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
+                       opc->opc3);
                 return -1;
             }
-#if defined(PPC_DUMP_CPU)
-            if (opc1 != 0x00) {
-                if (opc->opc3 == 0xFF) {
-                    if (opc->opc2 == 0xFF) {
-                        printf(" %02x -- -- (%2d ----) : %s\n",
-                               opc->opc1, opc->opc1, opc->oname);
-                    } else {
-                        printf(" %02x %02x -- (%2d %4d) : %s\n",
-                               opc->opc1, opc->opc2, opc->opc1, opc->opc2,
-                                    opc->oname);
-                    }
-                } else {
-                    printf(" %02x %02x %02x (%2d %4d) : %s\n",
-                           opc->opc1, opc->opc2, opc->opc3,
-                           opc->opc1, (opc->opc3 << 5) | opc->opc2,
-                           opc->oname);
-                }
-            }
-#endif
         }
     }
     fix_opcode_tables(env->opcodes);
@@ -1057,974 +5772,193 @@
     return 0;
 }
 
+#if defined(PPC_DUMP_CPU)
+static int dump_ppc_insns (CPUPPCState *env)
+{
+    opc_handler_t **table, *handler;
+    uint8_t opc1, opc2, opc3;
+
+    printf("Instructions set:\n");
+    /* opc1 is 6 bits long */
+    for (opc1 = 0x00; opc1 < 0x40; opc1++) {
+        table = env->opcodes;
+        handler = table[opc1];
+        if (is_indirect_opcode(handler)) {
+            /* opc2 is 5 bits long */
+            for (opc2 = 0; opc2 < 0x20; opc2++) {
+                table = env->opcodes;
+                handler = env->opcodes[opc1];
+                table = ind_table(handler);
+                handler = table[opc2];
+                if (is_indirect_opcode(handler)) {
+                    table = ind_table(handler);
+                    /* opc3 is 5 bits long */
+                    for (opc3 = 0; opc3 < 0x20; opc3++) {
+                        handler = table[opc3];
+                        if (handler->handler != &gen_invalid) {
+                            printf("INSN: %02x %02x %02x (%02d %04d) : %s\n",
+                                   opc1, opc2, opc3, opc1, (opc3 << 5) | opc2,
+                                   handler->oname);
+                        }
+                    }
+                } else {
+                    if (handler->handler != &gen_invalid) {
+                        printf("INSN: %02x %02x -- (%02d %04d) : %s\n",
+                               opc1, opc2, opc1, opc2, handler->oname);
+                    }
+                }
+            }
+        } else {
+            if (handler->handler != &gen_invalid) {
+                printf("INSN: %02x -- -- (%02d ----) : %s\n",
+                       opc1, opc1, handler->oname);
+            }
+        }
+    }
+}
+#endif
+
 int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def)
 {
     env->msr_mask = def->msr_mask;
-    env->flags = def->flags;
-    if (create_ppc_opcodes(env, def) < 0) {
-        printf("Error creating opcodes table\n");
-        fflush(stdout);
-        fflush(stderr);
+    env->mmu_model = def->mmu_model;
+    env->excp_model = def->excp_model;
+    env->bus_model = def->bus_model;
+    env->bfd_mach = def->bfd_mach;
+    if (create_ppc_opcodes(env, def) < 0)
         return -1;
-    }
     init_ppc_proc(env, def);
 #if defined(PPC_DUMP_CPU)
-    dump_sprs(env);
-#endif
+    {
+        const unsigned char *mmu_model, *excp_model, *bus_model;
+        switch (env->mmu_model) {
+        case POWERPC_MMU_32B:
+            mmu_model = "PowerPC 32";
+            break;
+        case POWERPC_MMU_64B:
+            mmu_model = "PowerPC 64";
+            break;
+        case POWERPC_MMU_601:
+            mmu_model = "PowerPC 601";
+            break;
+        case POWERPC_MMU_SOFT_6xx:
+            mmu_model = "PowerPC 6xx/7xx with software driven TLBs";
+            break;
+        case POWERPC_MMU_SOFT_74xx:
+            mmu_model = "PowerPC 74xx with software driven TLBs";
+            break;
+        case POWERPC_MMU_SOFT_4xx:
+            mmu_model = "PowerPC 4xx with software driven TLBs";
+            break;
+        case POWERPC_MMU_SOFT_4xx_Z:
+            mmu_model = "PowerPC 4xx with software driven TLBs "
+                "and zones protections";
+            break;
+        case POWERPC_MMU_REAL_4xx:
+            mmu_model = "PowerPC 4xx real mode only";
+            break;
+        case POWERPC_MMU_BOOKE:
+            mmu_model = "PowerPC BookE";
+            break;
+        case POWERPC_MMU_BOOKE_FSL:
+            mmu_model = "PowerPC BookE FSL";
+            break;
+        case POWERPC_MMU_64BRIDGE:
+            mmu_model = "PowerPC 64 bridge";
+            break;
+        default:
+            mmu_model = "Unknown or invalid";
+            break;
+        }
+        switch (env->excp_model) {
+        case POWERPC_EXCP_STD:
+            excp_model = "PowerPC";
+            break;
+        case POWERPC_EXCP_40x:
+            excp_model = "PowerPC 40x";
+            break;
+        case POWERPC_EXCP_601:
+            excp_model = "PowerPC 601";
+            break;
+        case POWERPC_EXCP_602:
+            excp_model = "PowerPC 602";
+            break;
+        case POWERPC_EXCP_603:
+            excp_model = "PowerPC 603";
+            break;
+        case POWERPC_EXCP_603E:
+            excp_model = "PowerPC 603e";
+            break;
+        case POWERPC_EXCP_604:
+            excp_model = "PowerPC 604";
+            break;
+        case POWERPC_EXCP_7x0:
+            excp_model = "PowerPC 740/750";
+            break;
+        case POWERPC_EXCP_7x5:
+            excp_model = "PowerPC 745/755";
+            break;
+        case POWERPC_EXCP_74xx:
+            excp_model = "PowerPC 74xx";
+            break;
+        case POWERPC_EXCP_970:
+            excp_model = "PowerPC 970";
+            break;
+        case POWERPC_EXCP_BOOKE:
+            excp_model = "PowerPC BookE";
+            break;
+        default:
+            excp_model = "Unknown or invalid";
+            break;
+        }
+        switch (env->bus_model) {
+        case PPC_FLAGS_INPUT_6xx:
+            bus_model = "PowerPC 6xx";
+            break;
+        case PPC_FLAGS_INPUT_BookE:
+            bus_model = "PowerPC BookE";
+            break;
+        case PPC_FLAGS_INPUT_405:
+            bus_model = "PowerPC 405";
+            break;
+        case PPC_FLAGS_INPUT_970:
+            bus_model = "PowerPC 970";
+            break;
+        case PPC_FLAGS_INPUT_401:
+            bus_model = "PowerPC 401/403";
+            break;
+        default:
+            bus_model = "Unknown or invalid";
+            break;
+        }
+        printf("PowerPC %-12s : PVR %08x MSR %016" PRIx64 "\n"
+               "    MMU model        : %s\n",
+               def->name, def->pvr, def->msr_mask, mmu_model);
+        if (env->tlb != NULL) {
+            printf("                       %d %s TLB in %d ways\n",
+                   env->nb_tlb, env->id_tlbs ? "splitted" : "merged",
+                   env->nb_ways);
+        }
+        printf("    Exceptions model : %s\n"
+               "    Bus model        : %s\n",
+               excp_model, bus_model);
+    }
+    dump_ppc_insns(env);
+    dump_ppc_sprs(env);
     fflush(stdout);
-    fflush(stderr);
+#endif
 
     return 0;
 }
 
-CPUPPCState *cpu_ppc_init(void)
-{
-    CPUPPCState *env;
-
-    env = qemu_mallocz(sizeof(CPUPPCState));
-    if (!env)
-        return NULL;
-    cpu_exec_init(env);
-    tlb_flush(env, 1);
-#if defined (DO_SINGLE_STEP) && 0
-    /* Single step trace mode */
-    msr_se = 1;
-    msr_be = 1;
-#endif
-    msr_fp = 1; /* Allow floating point exceptions */
-    msr_me = 1; /* Allow machine check exceptions  */
-#if defined(CONFIG_USER_ONLY)
-    msr_pr = 1;
-#else
-    env->nip = 0xFFFFFFFC;
-#endif
-    do_compute_hflags(env);
-    env->reserve = -1;
-    return env;
-}
-
-void cpu_ppc_close(CPUPPCState *env)
-{
-    /* Should also remove all opcode tables... */
-    free(env);
-}
-
-/*****************************************************************************/
-/* PowerPC CPU definitions */
-static ppc_def_t ppc_defs[] =
-{
-    /* Embedded PPC */
-#if defined (TODO)
-    /* PPC 401 */
-    {
-        .name        = "401",
-        .pvr         = CPU_PPC_401,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_401,
-        .flags       = PPC_FLAGS_401,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* IOP480 (401 microcontroler) */
-    {
-        .name        = "iop480",
-        .pvr         = CPU_PPC_IOP480,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_401,
-        .flags       = PPC_FLAGS_401,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 403 GA */
-    {
-        .name        = "403ga",
-        .pvr         = CPU_PPC_403GA,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_403,
-        .flags       = PPC_FLAGS_403,
-        .msr_mask    = 0x000000000007D23D,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 403 GB */
-    {
-        .name        = "403gb",
-        .pvr         = CPU_PPC_403GB,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_403,
-        .flags       = PPC_FLAGS_403,
-        .msr_mask    = 0x000000000007D23D,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 403 GC */
-    {
-        .name        = "403gc",
-        .pvr         = CPU_PPC_403GC,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_403,
-        .flags       = PPC_FLAGS_403,
-        .msr_mask    = 0x000000000007D23D,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 403 GCX */
-    {
-        .name        = "403gcx",
-        .pvr         = CPU_PPC_403GCX,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_403,
-        .flags       = PPC_FLAGS_403,
-        .msr_mask    = 0x000000000007D23D,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 405 CR */
-    {
-        .name        = "405cr",
-        .pvr         = CPU_PPC_405,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 405 GP */
-    {
-        .name        = "405gp",
-        .pvr         = CPU_PPC_405,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 405 EP */
-    {
-        .name        = "405ep",
-        .pvr         = CPU_PPC_405EP,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 405 GPR */
-    {
-        .name        = "405gpr",
-        .pvr         = CPU_PPC_405GPR,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 405 D2 */
-    {
-        .name        = "405d2",
-        .pvr         = CPU_PPC_405D2,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 405 D4 */
-    {
-        .name        = "405d4",
-        .pvr         = CPU_PPC_405D4,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* Npe405 H */
-    {
-        .name        = "Npe405H",
-        .pvr         = CPU_PPC_NPE405H,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* Npe405 L */
-    {
-        .name        = "Npe405L",
-        .pvr         = CPU_PPC_NPE405L,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* STB03xx */
-    {
-        .name        = "STB03",
-        .pvr         = CPU_PPC_STB03,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* STB04xx */
-    {
-        .name        = "STB04",
-        .pvr         = CPU_PPC_STB04,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* STB25xx */
-    {
-        .name        = "STB25",
-        .pvr         = CPU_PPC_STB25,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_405,
-        .msr_mask    = 0x00000000020EFF30,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 440 EP */
-    {
-        .name        = "440ep",
-        .pvr         = CPU_PPC_440EP,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_440,
-        .flags       = PPC_FLAGS_440,
-        .msr_mask    = 0x000000000006D630,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 440 GP */
-    {
-        .name        = "440gp",
-        .pvr         = CPU_PPC_440GP,
-        .pvr_mask    = 0xFFFFFF00,
-        .insns_flags = PPC_INSNS_440,
-        .flags       = PPC_FLAGS_440,
-        .msr_mask    = 0x000000000006D630,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 440 GX */
-    {
-        .name        = "440gx",
-        .pvr         = CPU_PPC_440GX,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_405,
-        .flags       = PPC_FLAGS_440,
-        .msr_mask    = 0x000000000006D630,
-    },
-#endif
-
-    /* 32 bits "classic" powerpc */
-#if defined (TODO)
-    /* PPC 601 */
-    {
-        .name        = "601",
-        .pvr         = CPU_PPC_601,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_601,
-        .flags       = PPC_FLAGS_601,
-        .msr_mask    = 0x000000000000FD70,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 602 */
-    {
-        .name        = "602",
-        .pvr         = CPU_PPC_602,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_602,
-        .flags       = PPC_FLAGS_602,
-        .msr_mask    = 0x0000000000C7FF73,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 603 */
-    {
-        .name        = "603",
-        .pvr         = CPU_PPC_603,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 603e */
-    {
-        .name        = "603e",
-        .pvr         = CPU_PPC_603E,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
-    {
-        .name        = "Stretch",
-        .pvr         = CPU_PPC_603E,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 603ev */
-    {
-        .name        = "603ev",
-        .pvr         = CPU_PPC_603EV,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 603r */
-    {
-        .name        = "603r",
-        .pvr         = CPU_PPC_603R,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
-    {
-        .name        = "Goldeneye",
-        .pvr         = CPU_PPC_603R,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_603,
-        .flags       = PPC_FLAGS_603,
-        .msr_mask    = 0x000000000007FF73,
-    },
-#endif
-#if defined (TODO)
-    /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */
-    {
-        .name        = "G2",
-        .pvr         = CPU_PPC_G2,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_G2,
-        .flags       = PPC_FLAGS_G2,
-        .msr_mask    = 0x000000000006FFF2,
-    },
-    { /* Same as G2, with LE mode support */
-        .name        = "G2le",
-        .pvr         = CPU_PPC_G2LE,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_G2,
-        .flags       = PPC_FLAGS_G2,
-        .msr_mask    = 0x000000000007FFF3,
-    },
-#endif
-    /* PPC 604 */
-    {
-        .name        = "604",
-        .pvr         = CPU_PPC_604,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_604,
-        .flags       = PPC_FLAGS_604,
-        .msr_mask    = 0x000000000005FF77,
-    },
-    /* PPC 604e */
-    {
-        .name        = "604e",
-        .pvr         = CPU_PPC_604E,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_604,
-        .flags       = PPC_FLAGS_604,
-        .msr_mask    = 0x000000000005FF77,
-    },
-    /* PPC 604r */
-    {
-        .name        = "604r",
-        .pvr         = CPU_PPC_604R,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_604,
-        .flags       = PPC_FLAGS_604,
-        .msr_mask    = 0x000000000005FF77,
-    },
-    /* generic G3 */
-    {
-        .name        = "G3",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#if defined (TODO)
-    /* MPC740 (G3) */
-    {
-        .name        = "740",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    {
-        .name        = "Arthur",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-#if defined (TODO)
-    /* MPC745 (G3) */
-    {
-        .name        = "745",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    {
-        .name        = "Goldfinger",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-    /* MPC750 (G3) */
-    {
-        .name        = "750",
-        .pvr         = CPU_PPC_74x,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#if defined (TODO)
-    /* MPC755 (G3) */
-    {
-        .name        = "755",
-        .pvr         = CPU_PPC_755,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-#if defined (TODO)
-    /* MPC740P (G3) */
-    {
-        .name        = "740p",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    {
-        .name        = "Conan/Doyle",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-#if defined (TODO)
-    /* MPC745P (G3) */
-    {
-        .name        = "745p",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-    /* MPC750P (G3) */
-    {
-        .name        = "750p",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#if defined (TODO)
-    /* MPC755P (G3) */
-    {
-        .name        = "755p",
-        .pvr         = CPU_PPC_74xP,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x5,
-        .flags       = PPC_FLAGS_7x5,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#endif
-    /* IBM 750CXe (G3 embedded) */
-    {
-        .name        = "750cxe",
-        .pvr         = CPU_PPC_750CXE,
-        .pvr_mask    = 0xFFFFF000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    /* IBM 750FX (G3 embedded) */
-    {
-        .name        = "750fx",
-        .pvr         = CPU_PPC_750FX,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-    /* IBM 750GX (G3 embedded) */
-    {
-        .name        = "750gx",
-        .pvr         = CPU_PPC_750GX,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_7x0,
-        .flags       = PPC_FLAGS_7x0,
-        .msr_mask    = 0x000000000007FF77,
-    },
-#if defined (TODO)
-    /* generic G4 */
-    {
-        .name        = "G4",
-        .pvr         = CPU_PPC_7400,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 7400 (G4) */
-    {
-        .name        = "7400",
-        .pvr         = CPU_PPC_7400,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Max",
-        .pvr         = CPU_PPC_7400,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 7410 (G4) */
-    {
-        .name        = "7410",
-        .pvr         = CPU_PPC_7410,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Nitro",
-        .pvr         = CPU_PPC_7410,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-#endif
-    /* XXX: 7441 */
-    /* XXX: 7445 */
-    /* XXX: 7447 */
-    /* XXX: 7447A */
-#if defined (TODO)
-    /* PPC 7450 (G4) */
-    {
-        .name        = "7450",
-        .pvr         = CPU_PPC_7450,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Vger",
-        .pvr         = CPU_PPC_7450,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-#endif
-    /* XXX: 7451 */
-#if defined (TODO)
-    /* PPC 7455 (G4) */
-    {
-        .name        = "7455",
-        .pvr         = CPU_PPC_7455,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Apollo 6",
-        .pvr         = CPU_PPC_7455,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 7457 (G4) */
-    {
-        .name        = "7457",
-        .pvr         = CPU_PPC_7457,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Apollo 7",
-        .pvr         = CPU_PPC_7457,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 7457A (G4) */
-    {
-        .name        = "7457A",
-        .pvr         = CPU_PPC_7457A,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-    {
-        .name        = "Apollo 7 PM",
-        .pvr         = CPU_PPC_7457A,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_74xx,
-        .flags       = PPC_FLAGS_74xx,
-        .msr_mask    = 0x000000000205FF77,
-    },
-#endif
-    /* 64 bits PPC */
-#if defined (TODO)
-    /* PPC 620 */
-    {
-        .name        = "620",
-        .pvr         = CPU_PPC_620,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_620,
-        .flags       = PPC_FLAGS_620,
-        .msr_mask    = 0x800000000005FF73,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 630 (POWER3) */
-    {
-        .name        = "630",
-        .pvr         = CPU_PPC_630,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_630,
-        .flags       = PPC_FLAGS_630,
-        .msr_mask    = xxx,
-    }
-    {
-        .name        = "POWER3",
-        .pvr         = CPU_PPC_630,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_630,
-        .flags       = PPC_FLAGS_630,
-        .msr_mask    = xxx,
-    }
-#endif
-#if defined (TODO)
-    /* PPC 631 (Power 3+)*/
-    {
-        .name        = "631",
-        .pvr         = CPU_PPC_631,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_631,
-        .flags       = PPC_FLAGS_631,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "POWER3+",
-        .pvr         = CPU_PPC_631,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_631,
-        .flags       = PPC_FLAGS_631,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* POWER4 */
-    {
-        .name        = "POWER4",
-        .pvr         = CPU_PPC_POWER4,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER4,
-        .flags       = PPC_FLAGS_POWER4,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* POWER4p */
-    {
-        .name        = "POWER4+",
-        .pvr         = CPU_PPC_POWER4P,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER4,
-        .flags       = PPC_FLAGS_POWER4,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* POWER5 */
-    {
-        .name        = "POWER5",
-        .pvr         = CPU_PPC_POWER5,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER5,
-        .flags       = PPC_FLAGS_POWER5,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* POWER5+ */
-    {
-        .name        = "POWER5+",
-        .pvr         = CPU_PPC_POWER5P,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER5,
-        .flags       = PPC_FLAGS_POWER5,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 970 */
-    {
-        .name        = "970",
-        .pvr         = CPU_PPC_970,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_970,
-        .flags       = PPC_FLAGS_970,
-        .msr_mask    = 0x900000000204FF36,
-    },
-#endif
-#if defined (TODO)
-    /* PPC 970FX (G5) */
-    {
-        .name        = "970fx",
-        .pvr         = CPU_PPC_970FX,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_970FX,
-        .flags       = PPC_FLAGS_970FX,
-        .msr_mask    = 0x800000000204FF36,
-    },
-#endif
-#if defined (TODO)
-    /* RS64 (Apache/A35) */
-    /* This one seems to support the whole POWER2 instruction set
-     * and the PowerPC 64 one.
-     */
-    {
-        .name        = "RS64",
-        .pvr         = CPU_PPC_RS64,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "Apache",
-        .pvr         = CPU_PPC_RS64,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "A35",
-        .pvr         = CPU_PPC_RS64,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* RS64-II (NorthStar/A50) */
-    {
-        .name        = "RS64-II",
-        .pvr         = CPU_PPC_RS64II,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "NortStar",
-        .pvr         = CPU_PPC_RS64II,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "A50",
-        .pvr         = CPU_PPC_RS64II,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* RS64-III (Pulsar) */
-    {
-        .name        = "RS64-III",
-        .pvr         = CPU_PPC_RS64III,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "Pulsar",
-        .pvr         = CPU_PPC_RS64III,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* RS64-IV (IceStar/IStar/SStar) */
-    {
-        .name        = "RS64-IV",
-        .pvr         = CPU_PPC_RS64IV,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "IceStar",
-        .pvr         = CPU_PPC_RS64IV,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "IStar",
-        .pvr         = CPU_PPC_RS64IV,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-    {
-        .name        = "SStar",
-        .pvr         = CPU_PPC_RS64IV,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_RS64,
-        .flags       = PPC_FLAGS_RS64,
-        .msr_mask    = xxx,
-    },
-#endif
-    /* POWER */
-#if defined (TODO)
-    /* Original POWER */
-    {
-        .name        = "POWER",
-        .pvr         = CPU_POWER,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER,
-        .flags       = PPC_FLAGS_POWER,
-        .msr_mask    = xxx,
-    },
-#endif
-#if defined (TODO)
-    /* POWER2 */
-    {
-        .name        = "POWER2",
-        .pvr         = CPU_POWER2,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_POWER,
-        .flags       = PPC_FLAGS_POWER,
-        .msr_mask    = xxx,
-    },
-#endif
-    /* Generic PowerPCs */
-#if defined (TODO)
-    {
-        .name        = "ppc64",
-        .pvr         = CPU_PPC_970,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_PPC64,
-        .flags       = PPC_FLAGS_PPC64,
-        .msr_mask    = 0xA00000000204FF36,
-    },
-#endif
-    {
-        .name        = "ppc32",
-        .pvr         = CPU_PPC_604,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_PPC32,
-        .flags       = PPC_FLAGS_PPC32,
-        .msr_mask    = 0x000000000005FF77,
-    },
-    /* Fallback */
-    {
-        .name        = "ppc",
-        .pvr         = CPU_PPC_604,
-        .pvr_mask    = 0xFFFF0000,
-        .insns_flags = PPC_INSNS_PPC32,
-        .flags       = PPC_FLAGS_PPC32,
-        .msr_mask    = 0x000000000005FF77,
-    },
-};
-
 int ppc_find_by_name (const unsigned char *name, ppc_def_t **def)
 {
-    int i, ret;
+    int i, max, ret;
 
     ret = -1;
     *def = NULL;
-    for (i = 0; strcmp(ppc_defs[i].name, "ppc") != 0; i++) {
+    max = sizeof(ppc_defs) / sizeof(ppc_def_t);
+    for (i = 0; i < max; i++) {
         if (strcasecmp(name, ppc_defs[i].name) == 0) {
             *def = &ppc_defs[i];
             ret = 0;
@@ -2037,11 +5971,12 @@
 
 int ppc_find_by_pvr (uint32_t pvr, ppc_def_t **def)
 {
-    int i, ret;
+    int i, max, ret;
 
     ret = -1;
     *def = NULL;
-    for (i = 0; ppc_defs[i].name != NULL; i++) {
+    max = sizeof(ppc_defs) / sizeof(ppc_def_t);
+    for (i = 0; i < max; i++) {
         if ((pvr & ppc_defs[i].pvr_mask) ==
             (ppc_defs[i].pvr & ppc_defs[i].pvr_mask)) {
             *def = &ppc_defs[i];
@@ -2055,13 +5990,11 @@
 
 void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
 {
-    int i;
+    int i, max;
 
-    for (i = 0; ; i++) {
-        (*cpu_fprintf)(f, "PowerPC '%s' PVR %08x mask %08x\n",
-                       ppc_defs[i].name,
-                       ppc_defs[i].pvr, ppc_defs[i].pvr_mask);
-        if (strcmp(ppc_defs[i].name, "ppc") == 0)
-            break;
+    max = sizeof(ppc_defs) / sizeof(ppc_def_t);
+    for (i = 0; i < max; i++) {
+        (*cpu_fprintf)(f, "PowerPC %-16s PVR %08x\n",
+                       ppc_defs[i].name, ppc_defs[i].pvr);
     }
 }
diff --git a/target-sh4/README.sh4 b/target-sh4/README.sh4
index 2edda9f..a92b6f3 100644
--- a/target-sh4/README.sh4
+++ b/target-sh4/README.sh4
@@ -141,7 +141,7 @@
     import sys
     denand (open (sys.argv[1], 'rb'),
             open (sys.argv[2], 'wb'))
-    
+
 Style isssues
 -------------
 
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index e844d69..add6a47 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -1,6 +1,6 @@
 /*
  *  SH4 emulation
- * 
+ *
  *  Copyright (c) 2005 Samuel Tardieu
  *
  * This library is free software; you can redistribute it and/or
@@ -80,7 +80,7 @@
 typedef struct CPUSH4State {
     uint32_t flags;		/* general execution flags */
     uint32_t gregs[24];		/* general registers */
-    uint32_t fregs[32];		/* floating point registers */
+    float32 fregs[32];		/* floating point registers */
     uint32_t sr;		/* status register */
     uint32_t ssr;		/* saved status register */
     uint32_t spc;		/* saved program counter */
@@ -99,6 +99,7 @@
     /* temporary float registers */
     float32 ft0, ft1;
     float64 dt0, dt1;
+    float_status fp_status;
 
     /* Those belong to the specific unit (SH7750) but are handled here */
     uint32_t mmucr;		/* MMU control register */
@@ -114,6 +115,7 @@
     jmp_buf jmp_env;
     int user_mode_only;
     int interrupt_request;
+    int halted;
     int exception_index;
      CPU_COMMON tlb_t utlb[UTLB_SIZE];	/* unified translation table */
     tlb_t itlb[ITLB_SIZE];	/* instruction translation table */
@@ -121,11 +123,17 @@
 
 CPUSH4State *cpu_sh4_init(void);
 int cpu_sh4_exec(CPUSH4State * s);
-int cpu_sh4_signal_handler(int host_signum, void *pinfo, 
+int cpu_sh4_signal_handler(int host_signum, void *pinfo,
                            void *puc);
 
 #include "softfloat.h"
 
+#define CPUState CPUSH4State
+#define cpu_init cpu_sh4_init
+#define cpu_exec cpu_sh4_exec
+#define cpu_gen_code cpu_sh4_gen_code
+#define cpu_signal_handler cpu_sh4_signal_handler
+
 #include "cpu-all.h"
 
 /* Memory access type */
diff --git a/target-sh4/exec.h b/target-sh4/exec.h
index 3563300..a606fd1 100644
--- a/target-sh4/exec.h
+++ b/target-sh4/exec.h
@@ -1,6 +1,6 @@
 /*
  *  SH4 emulation
- * 
+ *
  *  Copyright (c) 2005 Samuel Tardieu
  *
  * This library is free software; you can redistribute it and/or
@@ -36,6 +36,16 @@
 #include "cpu.h"
 #include "exec-all.h"
 
+static inline int cpu_halted(CPUState *env) {
+    if (!env->halted)
+        return 0;
+    if (env->interrupt_request & CPU_INTERRUPT_HARD) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
 #ifndef CONFIG_USER_ONLY
 #include "softmmu_exec.h"
 #endif
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
index 1839c96..a5af5ba 100644
--- a/target-sh4/helper.c
+++ b/target-sh4/helper.c
@@ -1,6 +1,6 @@
 /*
  *  SH4 emulation
- * 
+ *
  *  Copyright (c) 2005 Samuel Tardieu
  *
  * This library is free software; you can redistribute it and/or
@@ -53,7 +53,7 @@
     return 1;
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
 {
     return addr;
 }
@@ -429,7 +429,7 @@
     return tlb_set_page(env, address, physical, prot, is_user, is_softmmu);
 }
 
-target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
 {
     target_ulong physical;
     int prot;
diff --git a/target-sh4/op.c b/target-sh4/op.c
index d3b68bc..0902fca 100644
--- a/target-sh4/op.c
+++ b/target-sh4/op.c
@@ -1,6 +1,6 @@
 /*
  *  SH4 emulation
- * 
+ *
  *  Copyright (c) 2005 Samuel Tardieu
  *
  * This library is free software; you can redistribute it and/or
@@ -509,6 +509,9 @@
 void OPPROTO op_lds_T0_fpscr(void)
 {
     env->fpscr = T0 & 0x003fffff;
+    env->fp_status.float_rounding_mode = T0 & 0x01 ?
+      float_round_to_zero : float_round_nearest_even;
+
     RETURN();
 }
 
@@ -561,14 +564,14 @@
 void OPPROTO op_shar_Rn(void)
 {
     cond_t(env->gregs[PARAM1] & 1);
-    *(int32_t *) & env->gregs[PARAM1] >>= 1;
+    env->gregs[PARAM1] >>= 1;
     RETURN();
 }
 
 void OPPROTO op_shlr_Rn(void)
 {
     cond_t(env->gregs[PARAM1] & 1);
-    *(uint32_t *) & env->gregs[PARAM1] >>= 1;
+    env->gregs[PARAM1] >>= 1;
     RETURN();
 }
 
@@ -592,19 +595,19 @@
 
 void OPPROTO op_shlr2_Rn(void)
 {
-    *(uint32_t *) & env->gregs[PARAM1] >>= 2;
+    env->gregs[PARAM1] >>= 2;
     RETURN();
 }
 
 void OPPROTO op_shlr8_Rn(void)
 {
-    *(uint32_t *) & env->gregs[PARAM1] >>= 8;
+    env->gregs[PARAM1] >>= 8;
     RETURN();
 }
 
 void OPPROTO op_shlr16_Rn(void)
 {
-    *(uint32_t *) & env->gregs[PARAM1] >>= 16;
+    env->gregs[PARAM1] >>= 16;
     RETURN();
 }
 
@@ -695,25 +698,127 @@
 
 void OPPROTO op_fmov_frN_FT0(void)
 {
-    FT0 = *(float32 *)&env->fregs[PARAM1];
+    FT0 = env->fregs[PARAM1];
     RETURN();
 }
 
 void OPPROTO op_fmov_drN_DT0(void)
 {
-    DT0 = *(float64 *)&env->fregs[PARAM1];
+    CPU_DoubleU d;
+
+    d.l.upper = *(uint32_t *)&env->fregs[PARAM1];
+    d.l.lower = *(uint32_t *)&env->fregs[PARAM1 + 1];
+    DT0 = d.d;
+    RETURN();
+}
+
+void OPPROTO op_fmov_frN_FT1(void)
+{
+    FT1 = env->fregs[PARAM1];
+    RETURN();
+}
+
+void OPPROTO op_fmov_drN_DT1(void)
+{
+    CPU_DoubleU d;
+
+    d.l.upper = *(uint32_t *)&env->fregs[PARAM1];
+    d.l.lower = *(uint32_t *)&env->fregs[PARAM1 + 1];
+    DT1 = d.d;
     RETURN();
 }
 
 void OPPROTO op_fmov_FT0_frN(void)
 {
-    *(float32 *)&env->fregs[PARAM1] = FT0;
+    env->fregs[PARAM1] = FT0;
     RETURN();
 }
 
 void OPPROTO op_fmov_DT0_drN(void)
 {
-    *(float64 *)&env->fregs[PARAM1] = DT0;
+    CPU_DoubleU d;
+
+    d.d = DT0;
+    *(uint32_t *)&env->fregs[PARAM1] = d.l.upper;
+    *(uint32_t *)&env->fregs[PARAM1 + 1] = d.l.lower;
+    RETURN();
+}
+
+void OPPROTO op_fadd_FT(void)
+{
+    FT0 = float32_add(FT0, FT1, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_fadd_DT(void)
+{
+    DT0 = float64_add(DT0, DT1, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_fsub_FT(void)
+{
+    FT0 = float32_sub(FT0, FT1, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_fsub_DT(void)
+{
+    DT0 = float64_sub(DT0, DT1, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_fmul_FT(void)
+{
+    FT0 = float32_mul(FT0, FT1, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_fmul_DT(void)
+{
+    DT0 = float64_mul(DT0, DT1, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_fdiv_FT(void)
+{
+    FT0 = float32_div(FT0, FT1, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_fdiv_DT(void)
+{
+    DT0 = float64_div(DT0, DT1, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_float_FT(void)
+{
+    FT0 = int32_to_float32(env->fpul, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_float_DT(void)
+{
+    DT0 = int32_to_float64(env->fpul, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_ftrc_FT(void)
+{
+    env->fpul = float32_to_int32_round_to_zero(FT0, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_ftrc_DT(void)
+{
+    env->fpul = float64_to_int32_round_to_zero(DT0, &env->fp_status);
+    RETURN();
+}
+
+void OPPROTO op_fmov_T0_frN(void)
+{
+    *(unsigned int *)&env->fregs[PARAM1] = T0;
     RETURN();
 }
 
@@ -737,7 +842,7 @@
 
 void OPPROTO op_dec8_rN(void)
 {
-    env->gregs[PARAM1] -= 4;
+    env->gregs[PARAM1] -= 8;
     RETURN();
 }
 
@@ -761,7 +866,7 @@
 
 void OPPROTO op_inc8_rN(void)
 {
-    env->gregs[PARAM1] += 4;
+    env->gregs[PARAM1] += 8;
     RETURN();
 }
 
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
index f02fa58..292e9b3 100644
--- a/target-sh4/op_helper.c
+++ b/target-sh4/op_helper.c
@@ -1,6 +1,6 @@
 /*
  *  SH4 emulation
- * 
+ *
  *  Copyright (c) 2005 Samuel Tardieu
  *
  * This library is free software; you can redistribute it and/or
@@ -20,11 +20,6 @@
 #include <assert.h>
 #include "exec.h"
 
-void cpu_loop_exit(void)
-{
-    longjmp(env->jmp_env, 1);
-}
-
 void do_raise_exception(void)
 {
     cpu_loop_exit();
diff --git a/target-sh4/op_mem.c b/target-sh4/op_mem.c
index ca39abf..b59871c 100644
--- a/target-sh4/op_mem.c
+++ b/target-sh4/op_mem.c
@@ -1,6 +1,6 @@
 /*
  *  SH4 emulation
- * 
+ *
  *  Copyright (c) 2005 Samuel Tardieu
  *
  * This library is free software; you can redistribute it and/or
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 358f975..35b6f08 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -1,6 +1,6 @@
 /*
  *  SH4 translation
- * 
+ *
  *  Copyright (c) 2005 Samuel Tardieu
  *
  * This library is free software; you can redistribute it and/or
@@ -125,13 +125,19 @@
 void cpu_sh4_reset(CPUSH4State * env)
 {
 #if defined(CONFIG_USER_ONLY)
-    env->sr = 0x00000000;
+    env->sr = SR_FD;            /* FD - kernel does lazy fpu context switch */
 #else
     env->sr = 0x700000F0;	/* MD, RB, BL, I3-I0 */
 #endif
     env->vbr = 0;
     env->pc = 0xA0000000;
-    env->fpscr = 0x00040001;
+#if defined(CONFIG_USER_ONLY)
+    env->fpscr = FPSCR_PR; /* value for userspace according to the kernel */
+    env->fp_status.float_rounding_mode = float_round_nearest_even; /* ?! */
+#else
+    env->fpscr = 0x00040001; /* CPU reset value according to SH4 manual */
+    env->fp_status.float_rounding_mode = float_round_to_zero;
+#endif
     env->mmucr = 0;
 }
 
@@ -236,8 +242,9 @@
 		? (x) + 16 : (x))
 
 #define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x))
-#define XHACK(x) (((x) & 1 ) << 4 | ((x) & 0xe ) << 1)
+#define XHACK(x) ((((x) & 1 ) << 4) | ((x) & 0xe))
 #define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x))
+#define DREG(x) FREG(x) /* Assumes lsb of (x) is always 0 */
 
 #define CHECK_NOT_DELAY_SLOT \
   if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
@@ -270,7 +277,7 @@
     case 0x0038:		/* ldtlb */
 	assert(0);		/* XXXXX */
 	return;
-    case 0x004b:		/* rte */
+    case 0x002b:		/* rte */
 	CHECK_NOT_DELAY_SLOT gen_op_rte();
 	ctx->flags |= DELAY_SLOT;
 	ctx->delayed_pc = (uint32_t) - 1;
@@ -640,29 +647,22 @@
 	gen_op_movl_rN_T0(REG(B7_4));
 	gen_op_xor_T0_rN(REG(B11_8));
 	return;
-    case 0xf00c:		/* fmov {F,D,X}Rm,{F,D,X}Rn */
-	if (ctx->fpscr & FPSCR_PR) {
-	    gen_op_fmov_drN_DT0(XREG(B7_4));
-	    gen_op_fmov_DT0_drN(XREG(B11_8));
-	} else if (ctx->fpscr & FPSCR_SZ) {
+    case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn - FPSCR: Nothing */
+	if (ctx->fpscr & FPSCR_SZ) {
 	    if (ctx->opcode & 0x0110)
 		break; /* illegal instruction */
-	    gen_op_fmov_drN_DT0(XREG(B7_4));
-	    gen_op_fmov_DT0_drN(XREG(B11_8));
+	    gen_op_fmov_drN_DT0(DREG(B7_4));
+	    gen_op_fmov_DT0_drN(DREG(B11_8));
 	} else {
 	    gen_op_fmov_frN_FT0(FREG(B7_4));
 	    gen_op_fmov_FT0_frN(FREG(B11_8));
 	}
 	return;
-    case 0xf00a:		/* fmov {F,D,X}Rm,@Rn */
-	if (ctx->fpscr & FPSCR_PR) {
-	    gen_op_fmov_drN_DT0(XREG(B7_4));
-	    gen_op_movl_rN_T1(REG(B11_8));
-	    gen_op_stfq_DT0_T1(ctx);
-	} else if (ctx->fpscr & FPSCR_SZ) {
+    case 0xf00a: /* fmov {F,D,X}Rm,@Rn - FPSCR: Nothing */
+	if (ctx->fpscr & FPSCR_SZ) {
 	    if (ctx->opcode & 0x0010)
 		break; /* illegal instruction */
-	    gen_op_fmov_drN_DT0(XREG(B7_4));
+	    gen_op_fmov_drN_DT0(DREG(B7_4));
 	    gen_op_movl_rN_T1(REG(B11_8));
 	    gen_op_stfq_DT0_T1(ctx);
 	} else {
@@ -671,54 +671,40 @@
 	    gen_op_stfl_FT0_T1(ctx);
 	}
 	return;
-    case 0xf008:		/* fmov @Rm,{F,D,X}Rn */
-	if (ctx->fpscr & FPSCR_PR) {
-	    gen_op_movl_rN_T0(REG(B7_4));
-	    gen_op_ldfq_T0_DT0(ctx);
-	    gen_op_fmov_DT0_drN(XREG(B11_8));
-	} else if (ctx->fpscr & FPSCR_SZ) {
+    case 0xf008: /* fmov @Rm,{F,D,X}Rn - FPSCR: Nothing */
+	if (ctx->fpscr & FPSCR_SZ) {
 	    if (ctx->opcode & 0x0100)
 		break; /* illegal instruction */
 	    gen_op_movl_rN_T0(REG(B7_4));
 	    gen_op_ldfq_T0_DT0(ctx);
-	    gen_op_fmov_DT0_drN(XREG(B11_8));
+	    gen_op_fmov_DT0_drN(DREG(B11_8));
 	} else {
 	    gen_op_movl_rN_T0(REG(B7_4));
 	    gen_op_ldfl_T0_FT0(ctx);
-	    gen_op_fmov_FT0_frN(XREG(B11_8));
+	    gen_op_fmov_FT0_frN(FREG(B11_8));
 	}
 	return;
-    case 0xf009:		/* fmov @Rm+,{F,D,X}Rn */
-	if (ctx->fpscr & FPSCR_PR) {
-	    gen_op_movl_rN_T0(REG(B7_4));
-	    gen_op_ldfq_T0_DT0(ctx);
-	    gen_op_fmov_DT0_drN(XREG(B11_8));
-	    gen_op_inc8_rN(REG(B7_4));
-	} else if (ctx->fpscr & FPSCR_SZ) {
+    case 0xf009: /* fmov @Rm+,{F,D,X}Rn - FPSCR: Nothing */
+	if (ctx->fpscr & FPSCR_SZ) {
 	    if (ctx->opcode & 0x0100)
 		break; /* illegal instruction */
 	    gen_op_movl_rN_T0(REG(B7_4));
 	    gen_op_ldfq_T0_DT0(ctx);
-	    gen_op_fmov_DT0_drN(XREG(B11_8));
+	    gen_op_fmov_DT0_drN(DREG(B11_8));
 	    gen_op_inc8_rN(REG(B7_4));
 	} else {
 	    gen_op_movl_rN_T0(REG(B7_4));
 	    gen_op_ldfl_T0_FT0(ctx);
-	    gen_op_fmov_FT0_frN(XREG(B11_8));
+	    gen_op_fmov_FT0_frN(FREG(B11_8));
 	    gen_op_inc4_rN(REG(B7_4));
 	}
 	return;
-    case 0xf00b:		/* fmov {F,D,X}Rm,@-Rn */
-	if (ctx->fpscr & FPSCR_PR) {
-	    gen_op_dec8_rN(REG(B11_8));
-	    gen_op_fmov_drN_DT0(XREG(B7_4));
-	    gen_op_movl_rN_T1(REG(B11_8));
-	    gen_op_stfq_DT0_T1(ctx);
-	} else if (ctx->fpscr & FPSCR_SZ) {
+    case 0xf00b: /* fmov {F,D,X}Rm,@-Rn - FPSCR: Nothing */
+	if (ctx->fpscr & FPSCR_SZ) {
 	    if (ctx->opcode & 0x0100)
 		break; /* illegal instruction */
 	    gen_op_dec8_rN(REG(B11_8));
-	    gen_op_fmov_drN_DT0(XREG(B7_4));
+	    gen_op_fmov_drN_DT0(DREG(B7_4));
 	    gen_op_movl_rN_T1(REG(B11_8));
 	    gen_op_stfq_DT0_T1(ctx);
 	} else {
@@ -728,36 +714,26 @@
 	    gen_op_stfl_FT0_T1(ctx);
 	}
 	return;
-    case 0xf006:		/* fmov @(R0,Rm),{F,D,X}Rm */
-	if (ctx->fpscr & FPSCR_PR) {
-	    gen_op_movl_rN_T0(REG(B7_4));
-	    gen_op_add_rN_T0(REG(0));
-	    gen_op_ldfq_T0_DT0(ctx);
-	    gen_op_fmov_DT0_drN(XREG(B11_8));
-	} else if (ctx->fpscr & FPSCR_SZ) {
+    case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm - FPSCR: Nothing */
+	if (ctx->fpscr & FPSCR_SZ) {
 	    if (ctx->opcode & 0x0100)
 		break; /* illegal instruction */
 	    gen_op_movl_rN_T0(REG(B7_4));
 	    gen_op_add_rN_T0(REG(0));
 	    gen_op_ldfq_T0_DT0(ctx);
-	    gen_op_fmov_DT0_drN(XREG(B11_8));
+	    gen_op_fmov_DT0_drN(DREG(B11_8));
 	} else {
 	    gen_op_movl_rN_T0(REG(B7_4));
 	    gen_op_add_rN_T0(REG(0));
 	    gen_op_ldfl_T0_FT0(ctx);
-	    gen_op_fmov_FT0_frN(XREG(B11_8));
+	    gen_op_fmov_FT0_frN(FREG(B11_8));
 	}
 	return;
-    case 0xf007:		/* fmov {F,D,X}Rn,@(R0,Rn) */
-	if (ctx->fpscr & FPSCR_PR) {
-	    gen_op_fmov_drN_DT0(XREG(B7_4));
-	    gen_op_movl_rN_T1(REG(B11_8));
-	    gen_op_add_rN_T1(REG(0));
-	    gen_op_stfq_DT0_T1(ctx);
-	} else if (ctx->fpscr & FPSCR_SZ) {
+    case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) - FPSCR: Nothing */
+	if (ctx->fpscr & FPSCR_SZ) {
 	    if (ctx->opcode & 0x0010)
 		break; /* illegal instruction */
-	    gen_op_fmov_drN_DT0(XREG(B7_4));
+	    gen_op_fmov_drN_DT0(DREG(B7_4));
 	    gen_op_movl_rN_T1(REG(B11_8));
 	    gen_op_add_rN_T1(REG(0));
 	    gen_op_stfq_DT0_T1(ctx);
@@ -768,6 +744,49 @@
 	    gen_op_stfl_FT0_T1(ctx);
 	}
 	return;
+    case 0xf000: /* fadd Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf001: /* fsub Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf002: /* fmul Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf003: /* fdiv Rm,Rn - FPSCR: R[PR,Enable.O/U/I]/W[Cause,Flag] */
+    case 0xf004: /* fcmp/eq Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+    case 0xf005: /* fcmp/gt Rm,Rn - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+	if (ctx->fpscr & FPSCR_PR) {
+	    if (ctx->opcode & 0x0110)
+		break; /* illegal instruction */
+	    gen_op_fmov_drN_DT1(DREG(B7_4));
+	    gen_op_fmov_drN_DT0(DREG(B11_8));
+	}
+	else {
+	    gen_op_fmov_frN_FT1(FREG(B7_4));
+	    gen_op_fmov_frN_FT0(FREG(B11_8));
+	}
+
+	switch (ctx->opcode & 0xf00f) {
+	case 0xf000:		/* fadd Rm,Rn */
+	    ctx->fpscr & FPSCR_PR ? gen_op_fadd_DT() : gen_op_fadd_FT();
+	    break;
+	case 0xf001:		/* fsub Rm,Rn */
+	    ctx->fpscr & FPSCR_PR ? gen_op_fsub_DT() : gen_op_fsub_FT();
+	    break;
+	case 0xf002:		/* fmul Rm,Rn */
+	    ctx->fpscr & FPSCR_PR ? gen_op_fmul_DT() : gen_op_fmul_FT();
+	    break;
+	case 0xf003:		/* fdiv Rm,Rn */
+	    ctx->fpscr & FPSCR_PR ? gen_op_fdiv_DT() : gen_op_fdiv_FT();
+	    break;
+	case 0xf004:		/* fcmp/eq Rm,Rn */
+	    return;
+	case 0xf005:		/* fcmp/gt Rm,Rn */
+	    return;
+	}
+
+	if (ctx->fpscr & FPSCR_PR) {
+	    gen_op_fmov_DT0_drN(DREG(B11_8));
+	}
+	else {
+	    gen_op_fmov_FT0_frN(FREG(B11_8));
+	}
+	return;
     }
 
     switch (ctx->opcode & 0xff00) {
@@ -860,10 +879,10 @@
 	gen_op_stw_T0_T1(ctx);
 	return;
     case 0x8400:		/* mov.b @(disp,Rn),R0 */
-	gen_op_movl_rN_T0(REG(0));
-	gen_op_movl_rN_T1(REG(B7_4));
-	gen_op_addl_imm_T1(B3_0);
-	gen_op_stb_T0_T1(ctx);
+	gen_op_movl_rN_T0(REG(B7_4));
+	gen_op_addl_imm_T0(B3_0);
+	gen_op_ldb_T0_T0(ctx);
+	gen_op_movl_T0_rN(REG(0));
 	return;
     case 0x8500:		/* mov.w @(disp,Rn),R0 */
 	gen_op_movl_rN_T0(REG(B7_4));
@@ -1003,8 +1022,8 @@
 	LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,)
 	LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,)
 	LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,)
-	LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x0052, sts,)
-	LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x0062, sts, ctx->flags |=
+	LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,)
+	LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |=
 	     MODE_CHANGE;)
     case 0x00c3:		/* movca.l R0,@Rm */
 	gen_op_movl_rN_T0(REG(0));
@@ -1071,14 +1090,52 @@
     case 0x401b:		/* tas.b @Rn */
 	gen_op_tasb_rN(REG(B11_8));
 	return;
-    case 0xf00d:		/* fsts FPUL,FRn */
+    case 0xf00d: /* fsts FPUL,FRn - FPSCR: Nothing */
 	gen_op_movl_fpul_FT0();
 	gen_op_fmov_FT0_frN(FREG(B11_8));
 	return;
-    case 0xf01d:		/* flds FRm.FPUL */
+    case 0xf01d: /* flds FRm,FPUL - FPSCR: Nothing */
 	gen_op_fmov_frN_FT0(FREG(B11_8));
 	gen_op_movl_FT0_fpul();
 	return;
+    case 0xf02d: /* float FPUL,FRn/DRn - FPSCR: R[PR,Enable.I]/W[Cause,Flag] */
+	if (ctx->fpscr & FPSCR_PR) {
+	    if (ctx->opcode & 0x0100)
+		break; /* illegal instruction */
+	    gen_op_float_DT();
+	    gen_op_fmov_DT0_drN(DREG(B11_8));
+	}
+	else {
+	    gen_op_float_FT();
+	    gen_op_fmov_FT0_frN(FREG(B11_8));
+	}
+	return;
+    case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */
+	if (ctx->fpscr & FPSCR_PR) {
+	    if (ctx->opcode & 0x0100)
+		break; /* illegal instruction */
+	    gen_op_fmov_drN_DT0(DREG(B11_8));
+	    gen_op_ftrc_DT();
+	}
+	else {
+	    gen_op_fmov_frN_FT0(FREG(B11_8));
+	    gen_op_ftrc_FT();
+	}
+	return;
+    case 0xf08d: /* fldi0 FRn - FPSCR: R[PR] */
+	if (!(ctx->fpscr & FPSCR_PR)) {
+	    gen_op_movl_imm_T0(0);
+	    gen_op_fmov_T0_frN(FREG(B11_8));
+	    return;
+	}
+	break;
+    case 0xf09d: /* fldi1 FRn - FPSCR: R[PR] */
+	if (!(ctx->fpscr & FPSCR_PR)) {
+	    gen_op_movl_imm_T0(0x3f800000);
+	    gen_op_fmov_T0_frN(FREG(B11_8));
+	    return;
+	}
+	break;
     }
 
     fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
@@ -1087,8 +1144,9 @@
     ctx->flags |= BRANCH_EXCEPTION;
 }
 
-int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
-				   int search_pc)
+static inline int
+gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
+                               int search_pc)
 {
     DisasContext ctx;
     target_ulong pc_start;
@@ -1184,7 +1242,6 @@
         ii++;
         while (ii <= i)
             gen_opc_instr_start[ii++] = 0;
-        tb->size = 0;
     } else {
         tb->size = ctx.pc - pc_start;
     }
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 5c4593a..5c8c49a 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -10,9 +10,11 @@
 #else
 #define TARGET_LONG_BITS 64
 #define TARGET_FPREGS 64
-#define TARGET_PAGE_BITS 12 /* XXX */
+#define TARGET_PAGE_BITS 13 /* 8k */
 #endif
 
+#define TARGET_PHYS_ADDR_BITS 64
+
 #include "cpu-defs.h"
 
 #include "softfloat.h"
@@ -20,9 +22,9 @@
 #define TARGET_HAS_ICE 1
 
 #if !defined(TARGET_SPARC64)
-#define ELF_MACHINE	EM_SPARC
+#define ELF_MACHINE     EM_SPARC
 #else
-#define ELF_MACHINE	EM_SPARCV9
+#define ELF_MACHINE     EM_SPARCV9
 #endif
 
 /*#define EXCP_INTERRUPT 0x100*/
@@ -34,24 +36,33 @@
 #define TT_PRIV_INSN 0x03
 #define TT_NFPU_INSN 0x04
 #define TT_WIN_OVF  0x05
-#define TT_WIN_UNF  0x06 
+#define TT_WIN_UNF  0x06
+#define TT_UNALIGNED 0x07
 #define TT_FP_EXCP  0x08
 #define TT_DFAULT   0x09
+#define TT_TOVF     0x0a
 #define TT_EXTINT   0x10
+#define TT_CODE_ACCESS 0x21
+#define TT_DATA_ACCESS 0x29
 #define TT_DIV_ZERO 0x2a
+#define TT_NCP_INSN 0x24
 #define TT_TRAP     0x80
 #else
 #define TT_TFAULT   0x08
 #define TT_TMISS    0x09
+#define TT_CODE_ACCESS 0x0a
 #define TT_ILL_INSN 0x10
 #define TT_PRIV_INSN 0x11
 #define TT_NFPU_INSN 0x20
 #define TT_FP_EXCP  0x21
+#define TT_TOVF     0x23
 #define TT_CLRWIN   0x24
 #define TT_DIV_ZERO 0x28
 #define TT_DFAULT   0x30
 #define TT_DMISS    0x31
-#define TT_DPROT    0x32
+#define TT_DATA_ACCESS 0x32
+#define TT_DPROT    0x33
+#define TT_UNALIGNED 0x34
 #define TT_PRIV_ACT 0x37
 #define TT_EXTINT   0x40
 #define TT_SPILL    0x80
@@ -78,6 +89,7 @@
 #if defined(TARGET_SPARC64)
 #define PS_IG    (1<<11)
 #define PS_MG    (1<<10)
+#define PS_RMO   (1<<7)
 #define PS_RED   (1<<5)
 #define PS_PEF   (1<<4)
 #define PS_AM    (1<<3)
@@ -124,14 +136,16 @@
 #define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
 #define FSR_FTT_IEEE_EXCP (1 << 14)
 #define FSR_FTT_UNIMPFPOP (3 << 14)
+#define FSR_FTT_SEQ_ERROR (4 << 14)
 #define FSR_FTT_INVAL_FPR (6 << 14)
 
 #define FSR_FCC1  (1<<11)
 #define FSR_FCC0  (1<<10)
 
 /* MMU */
-#define MMU_E	  (1<<0)
-#define MMU_NF	  (1<<1)
+#define MMU_E     (1<<0)
+#define MMU_NF    (1<<1)
+#define MMU_BM    (1<<14)
 
 #define PTE_ENTRYTYPE_MASK 3
 #define PTE_ACCESS_MASK    0x1c
@@ -139,8 +153,8 @@
 #define PTE_PPN_SHIFT      7
 #define PTE_ADDR_MASK      0xffffff00
 
-#define PG_ACCESSED_BIT	5
-#define PG_MODIFIED_BIT	6
+#define PG_ACCESSED_BIT 5
+#define PG_MODIFIED_BIT 6
 #define PG_CACHE_BIT    7
 
 #define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
@@ -150,6 +164,8 @@
 /* 2 <= NWINDOWS <= 32. In QEMU it must also be a power of two. */
 #define NWINDOWS  8
 
+typedef struct sparc_def_t sparc_def_t;
+
 typedef struct CPUSPARCState {
     target_ulong gregs[8]; /* general registers */
     target_ulong *regwptr; /* pointer to current register window */
@@ -166,8 +182,10 @@
     int      psrs;     /* supervisor mode (extracted from PSR) */
     int      psrps;    /* previous supervisor mode */
     int      psret;    /* enable traps */
-    uint32_t psrpil;   /* interrupt level */
+    uint32_t psrpil;   /* interrupt blocking level */
+    uint32_t pil_in;   /* incoming interrupt level bitmap */
     int      psref;    /* enable fpu */
+    target_ulong version;
     jmp_buf  jmp_env;
     int user_mode_only;
     int exception_index;
@@ -204,7 +222,7 @@
     uint64_t tnpc[MAXTL];
     uint64_t tstate[MAXTL];
     uint32_t tt[MAXTL];
-    uint32_t xcc;		/* Extended integer condition codes */
+    uint32_t xcc;               /* Extended integer condition codes */
     uint32_t asi;
     uint32_t pstate;
     uint32_t tl;
@@ -213,10 +231,14 @@
     uint64_t bgregs[8]; /* backup for normal global registers */
     uint64_t igregs[8]; /* interrupt general registers */
     uint64_t mgregs[8]; /* mmu general registers */
-    uint64_t version;
     uint64_t fprs;
     uint64_t tick_cmpr, stick_cmpr;
+    void *tick, *stick;
     uint64_t gsr;
+    uint32_t gl; // UA2005
+    /* UA 2005 hyperprivileged registers */
+    uint64_t hpstate, htstate[MAXTL], hintp, htba, hver, hstick_cmpr, ssr;
+    void *hstick; // UA 2005
 #endif
 #if !defined(TARGET_SPARC64) && !defined(reg_T2)
     target_ulong t2;
@@ -224,58 +246,75 @@
 } CPUSPARCState;
 #if defined(TARGET_SPARC64)
 #define GET_FSR32(env) (env->fsr & 0xcfc1ffff)
-#define PUT_FSR32(env, val) do { uint32_t _tmp = val;			\
-	env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL);	\
+#define PUT_FSR32(env, val) do { uint32_t _tmp = val;                   \
+        env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL);  \
     } while (0)
 #define GET_FSR64(env) (env->fsr & 0x3fcfc1ffffULL)
-#define PUT_FSR64(env, val) do { uint64_t _tmp = val;	\
-	env->fsr = _tmp & 0x3fcfc1c3ffULL;		\
+#define PUT_FSR64(env, val) do { uint64_t _tmp = val;   \
+        env->fsr = _tmp & 0x3fcfc1c3ffULL;              \
     } while (0)
-// Manuf 0x17, version 0x11, mask 0 (UltraSparc-II)
-#define GET_VER(env) ((0x17ULL << 48) | (0x11ULL << 32) |		\
-		      (0 << 24) | (MAXTL << 8) | (NWINDOWS - 1))
 #else
 #define GET_FSR32(env) (env->fsr)
-#define PUT_FSR32(env, val) do { uint32_t _tmp = val;	\
-	env->fsr = _tmp & 0xcfc1ffff;			\
+#define PUT_FSR32(env, val) do { uint32_t _tmp = val;                   \
+        env->fsr = (_tmp & 0xcfc1dfff) | (env->fsr & 0x000e0000);       \
     } while (0)
 #endif
 
 CPUSPARCState *cpu_sparc_init(void);
 int cpu_sparc_exec(CPUSPARCState *s);
 int cpu_sparc_close(CPUSPARCState *s);
+int sparc_find_by_name (const unsigned char *name, const sparc_def_t **def);
+void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt,
+                                                 ...));
+int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def);
 
-/* Fake impl 0, version 4 */
-#define GET_PSR(env) ((0 << 28) | (4 << 24) | (env->psr & PSR_ICC) |	\
-		      (env->psref? PSR_EF : 0) |			\
-		      (env->psrpil << 8) |				\
-		      (env->psrs? PSR_S : 0) |				\
-		      (env->psrps? PSR_PS : 0) |			\
-		      (env->psret? PSR_ET : 0) | env->cwp)
+#define GET_PSR(env) (env->version | (env->psr & PSR_ICC) |             \
+                      (env->psref? PSR_EF : 0) |                        \
+                      (env->psrpil << 8) |                              \
+                      (env->psrs? PSR_S : 0) |                          \
+                      (env->psrps? PSR_PS : 0) |                        \
+                      (env->psret? PSR_ET : 0) | env->cwp)
 
 #ifndef NO_CPU_IO_DEFS
 void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
 #endif
 
-#define PUT_PSR(env, val) do { int _tmp = val;				\
-	env->psr = _tmp & PSR_ICC;					\
-	env->psref = (_tmp & PSR_EF)? 1 : 0;				\
-	env->psrpil = (_tmp & PSR_PIL) >> 8;				\
-	env->psrs = (_tmp & PSR_S)? 1 : 0;				\
-	env->psrps = (_tmp & PSR_PS)? 1 : 0;				\
-	env->psret = (_tmp & PSR_ET)? 1 : 0;				\
-	cpu_set_cwp(env, _tmp & PSR_CWP & (NWINDOWS - 1));		\
+#define PUT_PSR(env, val) do { int _tmp = val;                          \
+        env->psr = _tmp & PSR_ICC;                                      \
+        env->psref = (_tmp & PSR_EF)? 1 : 0;                            \
+        env->psrpil = (_tmp & PSR_PIL) >> 8;                            \
+        env->psrs = (_tmp & PSR_S)? 1 : 0;                              \
+        env->psrps = (_tmp & PSR_PS)? 1 : 0;                            \
+        env->psret = (_tmp & PSR_ET)? 1 : 0;                            \
+        cpu_set_cwp(env, _tmp & PSR_CWP);                               \
     } while (0)
 
 #ifdef TARGET_SPARC64
-#define GET_CCR(env) ((env->xcc << 4) | (env->psr & PSR_ICC))
-#define PUT_CCR(env, val) do { int _tmp = val;				\
-	env->xcc = _tmp >> 4;						\
-	env->psr = (_tmp & 0xf) << 20;					\
+#define GET_CCR(env) (((env->xcc >> 20) << 4) | ((env->psr & PSR_ICC) >> 20))
+#define PUT_CCR(env, val) do { int _tmp = val;                          \
+        env->xcc = (_tmp >> 4) << 20;                                           \
+        env->psr = (_tmp & 0xf) << 20;                                  \
     } while (0)
+#define GET_CWP64(env) (NWINDOWS - 1 - (env)->cwp)
+#define PUT_CWP64(env, val) \
+    cpu_set_cwp(env, NWINDOWS - 1 - ((val) & (NWINDOWS - 1)))
+
 #endif
 
 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);
+void do_tick_set_count(void *opaque, uint64_t count);
+uint64_t do_tick_get_count(void *opaque);
+void do_tick_set_limit(void *opaque, uint64_t limit);
+void cpu_check_irqs(CPUSPARCState *env);
+
+#define CPUState CPUSPARCState
+#define cpu_init cpu_sparc_init
+#define cpu_exec cpu_sparc_exec
+#define cpu_gen_code cpu_sparc_gen_code
+#define cpu_signal_handler cpu_sparc_signal_handler
 
 #include "cpu-all.h"
 
diff --git a/target-sparc/exec.h b/target-sparc/exec.h
index 6e0515f..063e2ee 100644
--- a/target-sparc/exec.h
+++ b/target-sparc/exec.h
@@ -1,13 +1,9 @@
 #ifndef EXEC_SPARC_H
 #define EXEC_SPARC_H 1
-#include "dyngen-exec.h"
 #include "config.h"
+#include "dyngen-exec.h"
 
-#if defined(__sparc__)
-struct CPUSPARCState *env;
-#else
 register struct CPUSPARCState *env asm(AREG0);
-#endif
 
 #ifdef TARGET_SPARC64
 #define T0 (env->t0)
@@ -15,13 +11,8 @@
 #define T2 (env->t2)
 #define REGWPTR env->regwptr
 #else
-#if defined(__sparc__)
-register uint32_t T0 asm(AREG3);
-register uint32_t T1 asm(AREG2);
-#else
 register uint32_t T0 asm(AREG1);
 register uint32_t T1 asm(AREG2);
-#endif
 
 #undef REG_REGWPTR // Broken
 #ifdef REG_REGWPTR
@@ -33,11 +24,7 @@
 #define reg_REGWPTR
 
 #ifdef AREG4
-#if defined(__sparc__)
-register uint32_t T2 asm(AREG0);
-#else
 register uint32_t T2 asm(AREG4);
-#endif
 #define reg_T2
 #else
 #define T2 (env->t2)
@@ -45,14 +32,10 @@
 
 #else
 #define REGWPTR env->regwptr
-#if defined(__sparc__)
-register uint32_t T2 asm(AREG0);
-#else
 register uint32_t T2 asm(AREG3);
 #endif
 #define reg_T2
 #endif
-#endif
 
 #define FT0 (env->ft0)
 #define FT1 (env->ft1)
@@ -67,7 +50,9 @@
 void cpu_loop_exit(void);
 void helper_flush(target_ulong addr);
 void helper_ld_asi(int asi, int size, int sign);
-void helper_st_asi(int asi, int size, int sign);
+void helper_st_asi(int asi, int size);
+void helper_ldf_asi(int asi, int size, int rd);
+void helper_stf_asi(int asi, int size, int rd);
 void helper_rett(void);
 void helper_ldfsr(void);
 void set_cwp(int new_cwp);
@@ -78,6 +63,8 @@
 void do_fsqrtd(void);
 void do_fcmps(void);
 void do_fcmpd(void);
+void do_fcmpes(void);
+void do_fcmped(void);
 #ifdef TARGET_SPARC64
 void do_fabsd(void);
 void do_fcmps_fcc1(void);
@@ -86,6 +73,12 @@
 void do_fcmpd_fcc2(void);
 void do_fcmps_fcc3(void);
 void do_fcmpd_fcc3(void);
+void do_fcmpes_fcc1(void);
+void do_fcmped_fcc1(void);
+void do_fcmpes_fcc2(void);
+void do_fcmped_fcc2(void);
+void do_fcmpes_fcc3(void);
+void do_fcmped_fcc3(void);
 void do_popc();
 void do_wrpstate();
 void do_done();
@@ -96,6 +89,7 @@
 void do_ldd_raw(target_ulong addr);
 void do_interrupt(int intno);
 void raise_exception(int tt);
+void check_ieee_exceptions();
 void memcpy32(target_ulong *dst, const target_ulong *src);
 target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev);
 void dump_mmu(CPUState *env);
@@ -123,4 +117,14 @@
 int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
                                int is_user, int is_softmmu);
 
+static inline int cpu_halted(CPUState *env) {
+    if (!env->halted)
+        return 0;
+    if ((env->interrupt_request & CPU_INTERRUPT_HARD) && (env->psret != 0)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
 #endif
diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h
index 74988f7..0598b30 100644
--- a/target-sparc/fop_template.h
+++ b/target-sparc/fop_template.h
@@ -1,7 +1,7 @@
 /*
  *  SPARC micro operations (templates for various register related
  *  operations)
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
index 8f12667..af8bc96 100644
--- a/target-sparc/helper.c
+++ b/target-sparc/helper.c
@@ -1,6 +1,6 @@
 /*
  *  sparc helpers
- * 
+ *
  *  Copyright (c) 2003-2005 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -46,7 +46,7 @@
     spin_unlock(&global_cpu_lock);
 }
 
-#if defined(CONFIG_USER_ONLY) 
+#if defined(CONFIG_USER_ONLY)
 
 int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
                                int is_user, int is_softmmu)
@@ -99,8 +99,8 @@
 };
 
 int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot,
-			  int *access_index, target_ulong address, int rw,
-			  int is_user)
+                          int *access_index, target_ulong address, int rw,
+                          int is_user)
 {
     int access_perms = 0;
     target_phys_addr_t pde_ptr;
@@ -110,14 +110,21 @@
     unsigned long page_offset;
 
     virt_addr = address & TARGET_PAGE_MASK;
+
     if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
-	*physical = address;
+        // Boot mode: instruction fetches are taken from PROM
+        if (rw == 2 && (env->mmuregs[0] & MMU_BM)) {
+            *physical = 0xff0000000ULL | (address & 0x3ffffULL);
+            *prot = PAGE_READ | PAGE_EXEC;
+            return 0;
+        }
+        *physical = address;
         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
         return 0;
     }
 
     *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 */
@@ -128,70 +135,70 @@
     switch (pde & PTE_ENTRYTYPE_MASK) {
     default:
     case 0: /* Invalid */
-	return 1 << 2;
+        return 1 << 2;
     case 2: /* L0 PTE, maybe should not happen? */
     case 3: /* Reserved */
         return 4 << 2;
     case 1: /* L0 PDE */
-	pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
         pde = ldl_phys(pde_ptr);
 
-	switch (pde & PTE_ENTRYTYPE_MASK) {
-	default:
-	case 0: /* Invalid */
-	    return (1 << 8) | (1 << 2);
-	case 3: /* Reserved */
-	    return (1 << 8) | (4 << 2);
-	case 1: /* L1 PDE */
-	    pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+            return (1 << 8) | (1 << 2);
+        case 3: /* Reserved */
+            return (1 << 8) | (4 << 2);
+        case 1: /* L1 PDE */
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
             pde = ldl_phys(pde_ptr);
 
-	    switch (pde & PTE_ENTRYTYPE_MASK) {
-	    default:
-	    case 0: /* Invalid */
-		return (2 << 8) | (1 << 2);
-	    case 3: /* Reserved */
-		return (2 << 8) | (4 << 2);
-	    case 1: /* L2 PDE */
-		pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+                return (2 << 8) | (1 << 2);
+            case 3: /* Reserved */
+                return (2 << 8) | (4 << 2);
+            case 1: /* L2 PDE */
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
                 pde = ldl_phys(pde_ptr);
 
-		switch (pde & PTE_ENTRYTYPE_MASK) {
-		default:
-		case 0: /* Invalid */
-		    return (3 << 8) | (1 << 2);
-		case 1: /* PDE, should not happen */
-		case 3: /* Reserved */
-		    return (3 << 8) | (4 << 2);
-		case 2: /* L3 PTE */
-		    virt_addr = address & TARGET_PAGE_MASK;
-		    page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
-		}
-		break;
-	    case 2: /* L2 PTE */
-		virt_addr = address & ~0x3ffff;
-		page_offset = address & 0x3ffff;
-	    }
-	    break;
-	case 2: /* L1 PTE */
-	    virt_addr = address & ~0xffffff;
-	    page_offset = address & 0xffffff;
-	}
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                    return (3 << 8) | (1 << 2);
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return (3 << 8) | (4 << 2);
+                case 2: /* L3 PTE */
+                    virt_addr = address & TARGET_PAGE_MASK;
+                    page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
+                }
+                break;
+            case 2: /* L2 PTE */
+                virt_addr = address & ~0x3ffff;
+                page_offset = address & 0x3ffff;
+            }
+            break;
+        case 2: /* L1 PTE */
+            virt_addr = address & ~0xffffff;
+            page_offset = address & 0xffffff;
+        }
     }
 
     /* update page modified and dirty bits */
     is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
     if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
-	pde |= PG_ACCESSED_MASK;
-	if (is_dirty)
-	    pde |= PG_MODIFIED_MASK;
+        pde |= PG_ACCESSED_MASK;
+        if (is_dirty)
+            pde |= PG_MODIFIED_MASK;
         stl_phys_notdirty(pde_ptr, pde);
     }
     /* check access */
     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
     error_code = access_table[*access_index][access_perms];
     if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
-	return error_code;
+        return error_code;
 
     /* the page can be put in the TLB */
     *prot = perm_table[is_user][access_perms];
@@ -203,7 +210,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,22 +219,23 @@
                               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);
     if (error_code == 0) {
-	vaddr = address & TARGET_PAGE_MASK;
-	paddr &= TARGET_PAGE_MASK;
+        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;
+        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
+        return ret;
     }
 
     if (env->mmuregs[3]) /* Fault status register */
-	env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+        env->mmuregs[3] = 1; /* overflow (not read before another fault) */
     env->mmuregs[3] |= (access_index << 5) | error_code | 2;
     env->mmuregs[4] = address; /* Fault address register */
 
@@ -236,10 +244,10 @@
         // permissions. If no mapping is available, redirect accesses to
         // neverland. Fake/overridden mappings will be flushed when
         // switching to normal mode.
-	vaddr = address & TARGET_PAGE_MASK;
+        vaddr = address & TARGET_PAGE_MASK;
         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
         ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
-	return ret;
+        return ret;
     } else {
         if (rw & 2)
             env->exception_index = TT_TFAULT;
@@ -255,7 +263,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) {
@@ -263,50 +272,50 @@
     case 0: /* Invalid */
     case 2: /* PTE, maybe should not happen? */
     case 3: /* Reserved */
-	return 0;
+        return 0;
     case 1: /* L1 PDE */
-	if (mmulev == 3)
-	    return pde;
-	pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
+        if (mmulev == 3)
+            return pde;
+        pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
         pde = ldl_phys(pde_ptr);
 
-	switch (pde & PTE_ENTRYTYPE_MASK) {
-	default:
-	case 0: /* Invalid */
-	case 3: /* Reserved */
-	    return 0;
-	case 2: /* L1 PTE */
-	    return pde;
-	case 1: /* L2 PDE */
-	    if (mmulev == 2)
-		return pde;
-	    pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
+        switch (pde & PTE_ENTRYTYPE_MASK) {
+        default:
+        case 0: /* Invalid */
+        case 3: /* Reserved */
+            return 0;
+        case 2: /* L1 PTE */
+            return pde;
+        case 1: /* L2 PDE */
+            if (mmulev == 2)
+                return pde;
+            pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
             pde = ldl_phys(pde_ptr);
 
-	    switch (pde & PTE_ENTRYTYPE_MASK) {
-	    default:
-	    case 0: /* Invalid */
-	    case 3: /* Reserved */
-		return 0;
-	    case 2: /* L2 PTE */
-		return pde;
-	    case 1: /* L3 PDE */
-		if (mmulev == 1)
-		    return pde;
-		pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
+            switch (pde & PTE_ENTRYTYPE_MASK) {
+            default:
+            case 0: /* Invalid */
+            case 3: /* Reserved */
+                return 0;
+            case 2: /* L2 PTE */
+                return pde;
+            case 1: /* L3 PDE */
+                if (mmulev == 1)
+                    return pde;
+                pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
                 pde = ldl_phys(pde_ptr);
 
-		switch (pde & PTE_ENTRYTYPE_MASK) {
-		default:
-		case 0: /* Invalid */
-		case 1: /* PDE, should not happen */
-		case 3: /* Reserved */
-		    return 0;
-		case 2: /* L3 PTE */
-		    return pde;
-		}
-	    }
-	}
+                switch (pde & PTE_ENTRYTYPE_MASK) {
+                default:
+                case 0: /* Invalid */
+                case 1: /* PDE, should not happen */
+                case 3: /* Reserved */
+                    return 0;
+                case 2: /* L3 PTE */
+                    return pde;
+                }
+            }
+        }
     }
     return 0;
 }
@@ -314,35 +323,40 @@
 #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) {
-	    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);
-	    for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
-		pde_ptr = mmu_probe(env, va1, 1);
-		if (pde_ptr) {
-		    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);
-		    for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
-			pde_ptr = mmu_probe(env, va2, 0);
-			if (pde_ptr) {
-			    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);
-			}
-		    }
-		}
-	    }
-	}
+        pde = mmu_probe(env, va, 2);
+        if (pde) {
+            pa = cpu_get_phys_page_debug(env, va);
+            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 = mmu_probe(env, va1, 1);
+                if (pde) {
+                    pa = cpu_get_phys_page_debug(env, va1);
+                    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 = mmu_probe(env, va2, 0);
+                        if (pde) {
+                            pa = cpu_get_phys_page_debug(env, va2);
+                            printf("  VA: " TARGET_FMT_lx ", PA: "
+                                   TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
+                                   va2, pa, pde);
+                        }
+                    }
+                }
+            }
+        }
     }
     printf("MMU dump ends\n");
 }
@@ -353,57 +367,57 @@
  * UltraSparc IIi I/DMMUs
  */
 static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
-			  int *access_index, target_ulong address, int rw,
-			  int is_user)
+                          int *access_index, target_ulong address, int rw,
+                          int is_user)
 {
     target_ulong mask;
     unsigned int i;
 
     if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
-	*physical = address;
-	*prot = PAGE_READ | PAGE_WRITE;
+        *physical = address;
+        *prot = PAGE_READ | PAGE_WRITE;
         return 0;
     }
 
     for (i = 0; i < 64; i++) {
-	switch ((env->dtlb_tte[i] >> 61) & 3) {
-	default:
-	case 0x0: // 8k
-	    mask = 0xffffffffffffe000ULL;
-	    break;
-	case 0x1: // 64k
-	    mask = 0xffffffffffff0000ULL;
-	    break;
-	case 0x2: // 512k
-	    mask = 0xfffffffffff80000ULL;
-	    break;
-	case 0x3: // 4M
-	    mask = 0xffffffffffc00000ULL;
-	    break;
-	}
-	// ctx match, vaddr match?
-	if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
-	    (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
-	    // valid, access ok?
-	    if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
-		((env->dtlb_tte[i] & 0x4) && is_user) ||
-		(!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
-		if (env->dmmuregs[3]) /* Fault status register */
-		    env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
-		env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
-		env->dmmuregs[4] = address; /* Fault address register */
-		env->exception_index = TT_DFAULT;
+        switch ((env->dtlb_tte[i] >> 61) & 3) {
+        default:
+        case 0x0: // 8k
+            mask = 0xffffffffffffe000ULL;
+            break;
+        case 0x1: // 64k
+            mask = 0xffffffffffff0000ULL;
+            break;
+        case 0x2: // 512k
+            mask = 0xfffffffffff80000ULL;
+            break;
+        case 0x3: // 4M
+            mask = 0xffffffffffc00000ULL;
+            break;
+        }
+        // ctx match, vaddr match?
+        if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
+            (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
+            // valid, access ok?
+            if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
+                ((env->dtlb_tte[i] & 0x4) && is_user) ||
+                (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
+                if (env->dmmuregs[3]) /* Fault status register */
+                    env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
+                env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
+                env->dmmuregs[4] = address; /* Fault address register */
+                env->exception_index = TT_DFAULT;
 #ifdef DEBUG_MMU
-		printf("DFAULT at 0x%" PRIx64 "\n", address);
+                printf("DFAULT at 0x%" PRIx64 "\n", address);
 #endif
-		return 1;
-	    }
-	    *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
-	    *prot = PAGE_READ;
-	    if (env->dtlb_tte[i] & 0x2)
-		*prot |= PAGE_WRITE;
-	    return 0;
-	}
+                return 1;
+            }
+            *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
+            *prot = PAGE_READ;
+            if (env->dtlb_tte[i] & 0x2)
+                *prot |= PAGE_WRITE;
+            return 0;
+        }
     }
 #ifdef DEBUG_MMU
     printf("DMISS at 0x%" PRIx64 "\n", address);
@@ -413,53 +427,53 @@
 }
 
 static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
-			  int *access_index, target_ulong address, int rw,
-			  int is_user)
+                          int *access_index, target_ulong address, int rw,
+                          int is_user)
 {
     target_ulong mask;
     unsigned int i;
 
     if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
-	*physical = address;
-	*prot = PAGE_EXEC;
+        *physical = address;
+        *prot = PAGE_EXEC;
         return 0;
     }
 
     for (i = 0; i < 64; i++) {
-	switch ((env->itlb_tte[i] >> 61) & 3) {
-	default:
-	case 0x0: // 8k
-	    mask = 0xffffffffffffe000ULL;
-	    break;
-	case 0x1: // 64k
-	    mask = 0xffffffffffff0000ULL;
-	    break;
-	case 0x2: // 512k
-	    mask = 0xfffffffffff80000ULL;
-	    break;
-	case 0x3: // 4M
-	    mask = 0xffffffffffc00000ULL;
-		break;
-	}
-	// ctx match, vaddr match?
-	if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
-	    (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
-	    // valid, access ok?
-	    if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
-		((env->itlb_tte[i] & 0x4) && is_user)) {
-		if (env->immuregs[3]) /* Fault status register */
-		    env->immuregs[3] = 2; /* overflow (not read before another fault) */
-		env->immuregs[3] |= (is_user << 3) | 1;
-		env->exception_index = TT_TFAULT;
+        switch ((env->itlb_tte[i] >> 61) & 3) {
+        default:
+        case 0x0: // 8k
+            mask = 0xffffffffffffe000ULL;
+            break;
+        case 0x1: // 64k
+            mask = 0xffffffffffff0000ULL;
+            break;
+        case 0x2: // 512k
+            mask = 0xfffffffffff80000ULL;
+            break;
+        case 0x3: // 4M
+            mask = 0xffffffffffc00000ULL;
+                break;
+        }
+        // ctx match, vaddr match?
+        if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
+            (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
+            // valid, access ok?
+            if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
+                ((env->itlb_tte[i] & 0x4) && is_user)) {
+                if (env->immuregs[3]) /* Fault status register */
+                    env->immuregs[3] = 2; /* overflow (not read before another fault) */
+                env->immuregs[3] |= (is_user << 3) | 1;
+                env->exception_index = TT_TFAULT;
 #ifdef DEBUG_MMU
-		printf("TFAULT at 0x%" PRIx64 "\n", address);
+                printf("TFAULT at 0x%" PRIx64 "\n", address);
 #endif
-		return 1;
-	    }
-	    *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
-	    *prot = PAGE_EXEC;
-	    return 0;
-	}
+                return 1;
+            }
+            *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
+            *prot = PAGE_EXEC;
+            return 0;
+        }
     }
 #ifdef DEBUG_MMU
     printf("TMISS at 0x%" PRIx64 "\n", address);
@@ -469,13 +483,13 @@
 }
 
 int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
-			  int *access_index, target_ulong address, int rw,
-			  int is_user)
+                          int *access_index, target_ulong address, int rw,
+                          int is_user)
 {
     if (rw == 2)
-	return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
+        return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
     else
-	return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
+        return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
 }
 
 /* Perform address translation */
@@ -488,13 +502,13 @@
 
     error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
     if (error_code == 0) {
-	virt_addr = address & TARGET_PAGE_MASK;
-	vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
+        virt_addr = address & TARGET_PAGE_MASK;
+        vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
 #ifdef DEBUG_MMU
-	printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr);
+        printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr);
 #endif
-	ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
-	return ret;
+        ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
+        return ret;
     }
     // XXX
     return 1;
@@ -508,67 +522,67 @@
 
     printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", env->dmmuregs[1], env->dmmuregs[2]);
     if ((env->lsu & DMMU_E) == 0) {
-	printf("DMMU disabled\n");
+        printf("DMMU disabled\n");
     } else {
-	printf("DMMU dump:\n");
-	for (i = 0; i < 64; i++) {
-	    switch ((env->dtlb_tte[i] >> 61) & 3) {
-	    default:
-	    case 0x0:
-		mask = "  8k";
-		break;
-	    case 0x1:
-		mask = " 64k";
-		break;
-	    case 0x2:
-		mask = "512k";
-		break;
-	    case 0x3:
-		mask = "  4M";
-		break;
-	    }
-	    if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
-		printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n",
-		       env->dtlb_tag[i] & ~0x1fffULL,
-		       env->dtlb_tte[i] & 0x1ffffffe000ULL,
-		       mask,
-		       env->dtlb_tte[i] & 0x4? "priv": "user",
-		       env->dtlb_tte[i] & 0x2? "RW": "RO",
-		       env->dtlb_tte[i] & 0x40? "locked": "unlocked",
-		       env->dtlb_tag[i] & 0x1fffULL);
-	    }
-	}
+        printf("DMMU dump:\n");
+        for (i = 0; i < 64; i++) {
+            switch ((env->dtlb_tte[i] >> 61) & 3) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
+                printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n",
+                       env->dtlb_tag[i] & ~0x1fffULL,
+                       env->dtlb_tte[i] & 0x1ffffffe000ULL,
+                       mask,
+                       env->dtlb_tte[i] & 0x4? "priv": "user",
+                       env->dtlb_tte[i] & 0x2? "RW": "RO",
+                       env->dtlb_tte[i] & 0x40? "locked": "unlocked",
+                       env->dtlb_tag[i] & 0x1fffULL);
+            }
+        }
     }
     if ((env->lsu & IMMU_E) == 0) {
-	printf("IMMU disabled\n");
+        printf("IMMU disabled\n");
     } else {
-	printf("IMMU dump:\n");
-	for (i = 0; i < 64; i++) {
-	    switch ((env->itlb_tte[i] >> 61) & 3) {
-	    default:
-	    case 0x0:
-		mask = "  8k";
-		break;
-	    case 0x1:
-		mask = " 64k";
-		break;
-	    case 0x2:
-		mask = "512k";
-		break;
-	    case 0x3:
-		mask = "  4M";
-		break;
-	    }
-	    if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
-		printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n",
-		       env->itlb_tag[i] & ~0x1fffULL,
-		       env->itlb_tte[i] & 0x1ffffffe000ULL,
-		       mask,
-		       env->itlb_tte[i] & 0x4? "priv": "user",
-		       env->itlb_tte[i] & 0x40? "locked": "unlocked",
-		       env->itlb_tag[i] & 0x1fffULL);
-	    }
-	}
+        printf("IMMU dump:\n");
+        for (i = 0; i < 64; i++) {
+            switch ((env->itlb_tte[i] >> 61) & 3) {
+            default:
+            case 0x0:
+                mask = "  8k";
+                break;
+            case 0x1:
+                mask = " 64k";
+                break;
+            case 0x2:
+                mask = "512k";
+                break;
+            case 0x3:
+                mask = "  4M";
+                break;
+            }
+            if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
+                printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n",
+                       env->itlb_tag[i] & ~0x1fffULL,
+                       env->itlb_tte[i] & 0x1ffffffe000ULL,
+                       mask,
+                       env->itlb_tte[i] & 0x4? "priv": "user",
+                       env->itlb_tte[i] & 0x40? "locked": "unlocked",
+                       env->itlb_tag[i] & 0x1fffULL);
+            }
+        }
     }
 }
 #endif /* DEBUG_MMU */
diff --git a/target-sparc/op.c b/target-sparc/op.c
index 1ec15d2..613bcb0 100644
--- a/target-sparc/op.c
+++ b/target-sparc/op.c
@@ -287,7 +287,7 @@
     __p.l.v1 = PARAM1;\
     __p.l.v0 = PARAM2;\
     __p.q;\
-}) 
+})
 
 void OPPROTO op_movq_T0_im64(void)
 {
@@ -376,33 +376,33 @@
     env->psr = 0;
 #ifdef TARGET_SPARC64
     if (!(T0 & 0xffffffff))
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
-	env->psr |= PSR_CARRY;
+        env->psr |= PSR_CARRY;
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
-	 ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
-	env->psr |= PSR_OVF;
+         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        env->psr |= PSR_OVF;
 
     env->xcc = 0;
     if (!T0)
-	env->xcc |= PSR_ZERO;
+        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
-	env->xcc |= PSR_NEG;
+        env->xcc |= PSR_NEG;
     if (T0 < src1)
-	env->xcc |= PSR_CARRY;
+        env->xcc |= PSR_CARRY;
     if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63))
-	env->xcc |= PSR_OVF;
+        env->xcc |= PSR_OVF;
 #else
     if (!T0)
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if (T0 < src1)
-	env->psr |= PSR_CARRY;
+        env->psr |= PSR_CARRY;
     if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
-	env->psr |= PSR_OVF;
+        env->psr |= PSR_OVF;
 #endif
     FORCE_RET();
 }
@@ -448,26 +448,119 @@
     }
 #ifdef TARGET_SPARC64
     if (!(T0 & 0xffffffff))
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
-	 ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
-	env->psr |= PSR_OVF;
+         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        env->psr |= PSR_OVF;
 
     if (!T0)
-	env->xcc |= PSR_ZERO;
+        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
-	env->xcc |= PSR_NEG;
+        env->xcc |= PSR_NEG;
     if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63))
-	env->xcc |= PSR_OVF;
+        env->xcc |= PSR_OVF;
 #else
     if (!T0)
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
-	env->psr |= PSR_OVF;
+        env->psr |= PSR_OVF;
+#endif
+    FORCE_RET();
+}
+
+void OPPROTO op_tadd_T1_T0_cc(void)
+{
+    target_ulong src1;
+
+    src1 = T0;
+    T0 += T1;
+    env->psr = 0;
+#ifdef TARGET_SPARC64
+    if (!(T0 & 0xffffffff))
+        env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+        env->psr |= PSR_NEG;
+    if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
+        env->psr |= PSR_CARRY;
+    if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
+         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        env->psr |= PSR_OVF;
+    if ((src1 & 0x03) || (T1 & 0x03))
+        env->psr |= PSR_OVF;
+
+    env->xcc = 0;
+    if (!T0)
+        env->xcc |= PSR_ZERO;
+    if ((int64_t) T0 < 0)
+        env->xcc |= PSR_NEG;
+    if (T0 < src1)
+        env->xcc |= PSR_CARRY;
+    if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63))
+        env->xcc |= PSR_OVF;
+#else
+    if (!T0)
+        env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+        env->psr |= PSR_NEG;
+    if (T0 < src1)
+        env->psr |= PSR_CARRY;
+    if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
+        env->psr |= PSR_OVF;
+    if ((src1 & 0x03) || (T1 & 0x03))
+        env->psr |= PSR_OVF;
+#endif
+    FORCE_RET();
+}
+
+void OPPROTO op_tadd_T1_T0_ccTV(void)
+{
+    target_ulong src1;
+
+    if ((T0 & 0x03) || (T1 & 0x03)) {
+        raise_exception(TT_TOVF);
+        FORCE_RET();
+        return;
+    }
+
+    src1 = T0;
+    T0 += T1;
+
+#ifdef TARGET_SPARC64
+    if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
+         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        raise_exception(TT_TOVF);
+#else
+    if ((src1 & 0x03) || (T1 & 0x03))
+        raise_exception(TT_TOVF);
+#endif
+
+    env->psr = 0;
+#ifdef TARGET_SPARC64
+    if (!(T0 & 0xffffffff))
+        env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+        env->psr |= PSR_NEG;
+    if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
+        env->psr |= PSR_CARRY;
+
+    env->xcc = 0;
+    if (!T0)
+        env->xcc |= PSR_ZERO;
+    if ((int64_t) T0 < 0)
+        env->xcc |= PSR_NEG;
+    if (T0 < src1)
+        env->xcc |= PSR_CARRY;
+#else
+    if (!T0)
+        env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+        env->psr |= PSR_NEG;
+    if (T0 < src1)
+        env->psr |= PSR_CARRY;
 #endif
     FORCE_RET();
 }
@@ -486,33 +579,33 @@
     env->psr = 0;
 #ifdef TARGET_SPARC64
     if (!(T0 & 0xffffffff))
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
-	env->psr |= PSR_CARRY;
+        env->psr |= PSR_CARRY;
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
-	 ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
-	env->psr |= PSR_OVF;
+         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        env->psr |= PSR_OVF;
 
     env->xcc = 0;
     if (!T0)
-	env->xcc |= PSR_ZERO;
+        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
-	env->xcc |= PSR_NEG;
+        env->xcc |= PSR_NEG;
     if (src1 < T1)
-	env->xcc |= PSR_CARRY;
+        env->xcc |= PSR_CARRY;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
-	env->xcc |= PSR_OVF;
+        env->xcc |= PSR_OVF;
 #else
     if (!T0)
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if (src1 < T1)
-	env->psr |= PSR_CARRY;
+        env->psr |= PSR_CARRY;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
-	env->psr |= PSR_OVF;
+        env->psr |= PSR_OVF;
 #endif
     FORCE_RET();
 }
@@ -558,26 +651,116 @@
     }
 #ifdef TARGET_SPARC64
     if (!(T0 & 0xffffffff))
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
-	 ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
-	env->psr |= PSR_OVF;
+         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        env->psr |= PSR_OVF;
 
     if (!T0)
-	env->xcc |= PSR_ZERO;
+        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
-	env->xcc |= PSR_NEG;
+        env->xcc |= PSR_NEG;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
-	env->xcc |= PSR_OVF;
+        env->xcc |= PSR_OVF;
 #else
     if (!T0)
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
-	env->psr |= PSR_OVF;
+        env->psr |= PSR_OVF;
+#endif
+    FORCE_RET();
+}
+
+void OPPROTO op_tsub_T1_T0_cc(void)
+{
+    target_ulong src1;
+
+    src1 = T0;
+    T0 -= T1;
+    env->psr = 0;
+#ifdef TARGET_SPARC64
+    if (!(T0 & 0xffffffff))
+        env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+        env->psr |= PSR_NEG;
+    if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
+        env->psr |= PSR_CARRY;
+    if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
+         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        env->psr |= PSR_OVF;
+    if ((src1 & 0x03) || (T1 & 0x03))
+        env->psr |= PSR_OVF;
+
+    env->xcc = 0;
+    if (!T0)
+        env->xcc |= PSR_ZERO;
+    if ((int64_t) T0 < 0)
+        env->xcc |= PSR_NEG;
+    if (src1 < T1)
+        env->xcc |= PSR_CARRY;
+    if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
+        env->xcc |= PSR_OVF;
+#else
+    if (!T0)
+        env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+        env->psr |= PSR_NEG;
+    if (src1 < T1)
+        env->psr |= PSR_CARRY;
+    if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
+        env->psr |= PSR_OVF;
+    if ((src1 & 0x03) || (T1 & 0x03))
+        env->psr |= PSR_OVF;
+#endif
+    FORCE_RET();
+}
+
+void OPPROTO op_tsub_T1_T0_ccTV(void)
+{
+    target_ulong src1;
+
+    if ((T0 & 0x03) || (T1 & 0x03))
+        raise_exception(TT_TOVF);
+
+    src1 = T0;
+    T0 -= T1;
+
+#ifdef TARGET_SPARC64
+    if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
+         ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+        raise_exception(TT_TOVF);
+#else
+    if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
+        raise_exception(TT_TOVF);
+#endif
+
+    env->psr = 0;
+#ifdef TARGET_SPARC64
+    if (!(T0 & 0xffffffff))
+        env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+        env->psr |= PSR_NEG;
+    if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
+        env->psr |= PSR_CARRY;
+
+    env->xcc = 0;
+    if (!T0)
+        env->xcc |= PSR_ZERO;
+    if ((int64_t) T0 < 0)
+        env->xcc |= PSR_NEG;
+    if (src1 < T1)
+        env->xcc |= PSR_CARRY;
+#else
+    if (!T0)
+        env->psr |= PSR_ZERO;
+    if ((int32_t) T0 < 0)
+        env->psr |= PSR_NEG;
+    if (src1 < T1)
+        env->psr |= PSR_CARRY;
 #endif
     FORCE_RET();
 }
@@ -653,13 +836,13 @@
     T0 += T1;
     env->psr = 0;
     if (!T0)
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if (T0 < src1)
-	env->psr |= PSR_CARRY;
+        env->psr |= PSR_CARRY;
     if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
-	env->psr |= PSR_OVF;
+        env->psr |= PSR_OVF;
     env->y = (b2 << 31) | (env->y >> 1);
     FORCE_RET();
 }
@@ -671,13 +854,18 @@
 
     x0 = T0 | ((uint64_t) (env->y) << 32);
     x1 = T1;
+
+    if (x1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
+
     x0 = x0 / x1;
     if (x0 > 0xffffffff) {
-	T0 = 0xffffffff;
-	T1 = 1;
+        T0 = 0xffffffff;
+        T1 = 1;
     } else {
-	T0 = x0;
-	T1 = 0;
+        T0 = x0;
+        T1 = 0;
     }
     FORCE_RET();
 }
@@ -689,13 +877,18 @@
 
     x0 = T0 | ((int64_t) (env->y) << 32);
     x1 = T1;
+
+    if (x1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
+
     x0 = x0 / x1;
     if ((int32_t) x0 != x0) {
-	T0 = x0 < 0? 0x80000000: 0x7fffffff;
-	T1 = 1;
+        T0 = x0 < 0? 0x80000000: 0x7fffffff;
+        T1 = 1;
     } else {
-	T0 = x0;
-	T1 = 0;
+        T0 = x0;
+        T1 = 0;
     }
     FORCE_RET();
 }
@@ -705,24 +898,24 @@
     env->psr = 0;
 #ifdef TARGET_SPARC64
     if (!T0)
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if (T1)
-	env->psr |= PSR_OVF;
+        env->psr |= PSR_OVF;
 
     env->xcc = 0;
     if (!T0)
-	env->xcc |= PSR_ZERO;
+        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
-	env->xcc |= PSR_NEG;
+        env->xcc |= PSR_NEG;
 #else
     if (!T0)
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
     if (T1)
-	env->psr |= PSR_OVF;
+        env->psr |= PSR_OVF;
 #endif
     FORCE_RET();
 }
@@ -736,16 +929,22 @@
 
 void OPPROTO op_udivx_T1_T0(void)
 {
+    if (T1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
     T0 /= T1;
     FORCE_RET();
 }
 
 void OPPROTO op_sdivx_T1_T0(void)
 {
+    if (T1 == 0) {
+        raise_exception(TT_DIV_ZERO);
+    }
     if (T0 == INT64_MIN && T1 == -1)
-	T0 = INT64_MIN;
+        T0 = INT64_MIN;
     else
-	T0 /= (target_long) T1;
+        T0 /= (target_long) T1;
     FORCE_RET();
 }
 #endif
@@ -755,58 +954,63 @@
     env->psr = 0;
 #ifdef TARGET_SPARC64
     if (!(T0 & 0xffffffff))
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
 
     env->xcc = 0;
     if (!T0)
-	env->xcc |= PSR_ZERO;
+        env->xcc |= PSR_ZERO;
     if ((int64_t) T0 < 0)
-	env->xcc |= PSR_NEG;
+        env->xcc |= PSR_NEG;
 #else
     if (!T0)
-	env->psr |= PSR_ZERO;
+        env->psr |= PSR_ZERO;
     if ((int32_t) T0 < 0)
-	env->psr |= PSR_NEG;
+        env->psr |= PSR_NEG;
 #endif
     FORCE_RET();
 }
 
 void OPPROTO op_sll(void)
 {
-    T0 <<= T1;
+    T0 <<= (T1 & 0x1f);
 }
 
 #ifdef TARGET_SPARC64
+void OPPROTO op_sllx(void)
+{
+    T0 <<= (T1 & 0x3f);
+}
+
 void OPPROTO op_srl(void)
 {
-    T0 = (T0 & 0xffffffff) >> T1;
+    T0 = (T0 & 0xffffffff) >> (T1 & 0x1f);
 }
 
 void OPPROTO op_srlx(void)
 {
-    T0 >>= T1;
+    T0 >>= (T1 & 0x3f);
 }
 
 void OPPROTO op_sra(void)
 {
-    T0 = ((int32_t) (T0 & 0xffffffff)) >> T1;
+    T0 = ((int32_t) (T0 & 0xffffffff)) >> (T1 & 0x1f);
 }
 
 void OPPROTO op_srax(void)
 {
-    T0 = ((int64_t) T0) >> T1;
+    T0 = ((int64_t) T0) >> (T1 & 0x3f);
 }
 #else
 void OPPROTO op_srl(void)
 {
-    T0 >>= T1;
+    T0 >>= (T1 & 0x1f);
 }
 
 void OPPROTO op_sra(void)
 {
-    T0 = ((int32_t) T0) >> T1;
+    T0 = ((int32_t) T0) >> (T1 & 0x1f);
 }
 #endif
 
@@ -864,7 +1068,7 @@
 void OPPROTO op_save(void)
 {
     uint32_t cwp;
-    cwp = (env->cwp - 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp - 1) & (NWINDOWS - 1);
     if (env->wim & (1 << cwp)) {
         raise_exception(TT_WIN_OVF);
     }
@@ -875,7 +1079,7 @@
 void OPPROTO op_restore(void)
 {
     uint32_t cwp;
-    cwp = (env->cwp + 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp + 1) & (NWINDOWS - 1);
     if (env->wim & (1 << cwp)) {
         raise_exception(TT_WIN_UNF);
     }
@@ -895,12 +1099,38 @@
 
 void OPPROTO op_rdtick(void)
 {
-    T0 = 0; // XXX read cycle counter and bit 31
+    T0 = do_tick_get_count(env->tick);
 }
 
 void OPPROTO op_wrtick(void)
 {
-    // XXX write cycle counter and bit 31
+    do_tick_set_count(env->tick, T0);
+}
+
+void OPPROTO op_wrtick_cmpr(void)
+{
+    do_tick_set_limit(env->tick, T0);
+}
+
+void OPPROTO op_rdstick(void)
+{
+    T0 = do_tick_get_count(env->stick);
+}
+
+void OPPROTO op_wrstick(void)
+{
+    do_tick_set_count(env->stick, T0);
+    do_tick_set_count(env->hstick, T0);
+}
+
+void OPPROTO op_wrstick_cmpr(void)
+{
+    do_tick_set_limit(env->stick, T0);
+}
+
+void OPPROTO op_wrhstick_cmpr(void)
+{
+    do_tick_set_limit(env->hstick, T0);
 }
 
 void OPPROTO op_rdtpc(void)
@@ -957,12 +1187,12 @@
 // order.
 void OPPROTO op_rdcwp(void)
 {
-    T0 = NWINDOWS - 1 - env->cwp;
+    T0 = GET_CWP64(env);
 }
 
 void OPPROTO op_wrcwp(void)
 {
-    env->cwp = NWINDOWS - 1 - T0;
+    PUT_CWP64(env, T0);
 }
 
 /* XXX: use another pointer for %iN registers to avoid slow wrapping
@@ -970,20 +1200,20 @@
 void OPPROTO op_save(void)
 {
     uint32_t cwp;
-    cwp = (env->cwp - 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp - 1) & (NWINDOWS - 1);
     if (env->cansave == 0) {
-        raise_exception(TT_SPILL | (env->otherwin != 0 ? 
-				    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-				    ((env->wstate & 0x7) << 2)));
+        raise_exception(TT_SPILL | (env->otherwin != 0 ?
+                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
+                                    ((env->wstate & 0x7) << 2)));
     } else {
-	if (env->cleanwin - env->canrestore == 0) {
-	    // XXX Clean windows without trap
-	    raise_exception(TT_CLRWIN);
-	} else {
-	    env->cansave--;
-	    env->canrestore++;
-	    set_cwp(cwp);
-	}
+        if (env->cleanwin - env->canrestore == 0) {
+            // XXX Clean windows without trap
+            raise_exception(TT_CLRWIN);
+        } else {
+            env->cansave--;
+            env->canrestore++;
+            set_cwp(cwp);
+        }
     }
     FORCE_RET();
 }
@@ -991,15 +1221,15 @@
 void OPPROTO op_restore(void)
 {
     uint32_t cwp;
-    cwp = (env->cwp + 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp + 1) & (NWINDOWS - 1);
     if (env->canrestore == 0) {
-        raise_exception(TT_FILL | (env->otherwin != 0 ? 
-				   (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-				   ((env->wstate & 0x7) << 2)));
+        raise_exception(TT_FILL | (env->otherwin != 0 ?
+                                   (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
+                                   ((env->wstate & 0x7) << 2)));
     } else {
-	env->cansave++;
-	env->canrestore--;
-	set_cwp(cwp);
+        env->cansave++;
+        env->canrestore--;
+        set_cwp(cwp);
     }
     FORCE_RET();
 }
@@ -1058,7 +1288,7 @@
 void OPPROTO op_eval_ble(void)
 {
     target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF);
-    
+
     T2 = Z | (N ^ V);
 }
 
@@ -1146,7 +1376,7 @@
 void OPPROTO op_eval_xble(void)
 {
     target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF);
-    
+
     T2 = Z | (N ^ V);
 }
 
@@ -1339,16 +1569,25 @@
     helper_flush(T0);
 }
 
+void OPPROTO op_clear_ieee_excp_and_FTT(void)
+{
+    env->fsr &= ~(FSR_FTT_MASK | FSR_CEXC_MASK);;
+}
+
 #define F_OP(name, p) void OPPROTO op_f##name##p(void)
 
 #define F_BINOP(name)                                           \
     F_OP(name, s)                                               \
     {                                                           \
+        set_float_exception_flags(0, &env->fp_status);          \
         FT0 = float32_ ## name (FT0, FT1, &env->fp_status);     \
+        check_ieee_exceptions();                                \
     }                                                           \
     F_OP(name, d)                                               \
     {                                                           \
+        set_float_exception_flags(0, &env->fp_status);          \
         DT0 = float64_ ## name (DT0, DT1, &env->fp_status);     \
+        check_ieee_exceptions();                                \
     }
 
 F_BINOP(add);
@@ -1359,9 +1598,11 @@
 
 void OPPROTO op_fsmuld(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status),
                       float32_to_float64(FT1, &env->fp_status),
                       &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #define F_HELPER(name)    \
@@ -1387,6 +1628,7 @@
 }
 
 F_HELPER(cmp);
+F_HELPER(cmpe);
 
 #ifdef TARGET_SPARC64
 F_OP(neg, d)
@@ -1428,6 +1670,37 @@
 {
     do_fcmpd_fcc3();
 }
+
+void OPPROTO op_fcmpes_fcc1(void)
+{
+    do_fcmpes_fcc1();
+}
+
+void OPPROTO op_fcmped_fcc1(void)
+{
+    do_fcmped_fcc1();
+}
+
+void OPPROTO op_fcmpes_fcc2(void)
+{
+    do_fcmpes_fcc2();
+}
+
+void OPPROTO op_fcmped_fcc2(void)
+{
+    do_fcmped_fcc2();
+}
+
+void OPPROTO op_fcmpes_fcc3(void)
+{
+    do_fcmpes_fcc3();
+}
+
+void OPPROTO op_fcmped_fcc3(void)
+{
+    do_fcmped_fcc3();
+}
+
 #endif
 
 /* Integer to float conversion.  */
@@ -1436,23 +1709,31 @@
 #else
 F_OP(ito, s)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 F_OP(ito, d)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #ifdef TARGET_SPARC64
 F_OP(xto, s)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 F_OP(xto, d)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 #endif
 #endif
@@ -1461,60 +1742,72 @@
 /* floating point conversion */
 void OPPROTO op_fdtos(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = float64_to_float32(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fstod(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float32_to_float64(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 /* Float to integer conversion.  */
 void OPPROTO op_fstoi(void)
 {
-    *((int32_t *)&FT0) = float32_to_int32(FT1, &env->fp_status);
+    set_float_exception_flags(0, &env->fp_status);
+    *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fdtoi(void)
 {
-    *((int32_t *)&FT0) = float64_to_int32(DT1, &env->fp_status);
+    set_float_exception_flags(0, &env->fp_status);
+    *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 #ifdef TARGET_SPARC64
 void OPPROTO op_fstox(void)
 {
-    *((int64_t *)&DT0) = float32_to_int64(FT1, &env->fp_status);
+    set_float_exception_flags(0, &env->fp_status);
+    *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fdtox(void)
 {
-    *((int64_t *)&DT0) = float64_to_int64(DT1, &env->fp_status);
+    set_float_exception_flags(0, &env->fp_status);
+    *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void OPPROTO op_fmovs_cc(void)
 {
     if (T2)
-	FT0 = FT1;
+        FT0 = FT1;
 }
 
 void OPPROTO op_fmovd_cc(void)
 {
     if (T2)
-	DT0 = DT1;
+        DT0 = DT1;
 }
 
 void OPPROTO op_mov_cc(void)
 {
     if (T2)
-	T0 = T1;
+        T0 = T1;
 }
 
 void OPPROTO op_flushw(void)
 {
     if (env->cansave != NWINDOWS - 2) {
-        raise_exception(TT_SPILL | (env->otherwin != 0 ? 
-				    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
-				    ((env->wstate & 0x7) << 2)));
+        raise_exception(TT_SPILL | (env->otherwin != 0 ?
+                                    (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
+                                    ((env->wstate & 0x7) << 2)));
     }
 }
 
@@ -1522,9 +1815,9 @@
 {
     env->cansave++;
     if (env->otherwin == 0)
-	env->canrestore--;
+        env->canrestore--;
     else
-	env->otherwin--;
+        env->otherwin--;
     FORCE_RET();
 }
 
@@ -1532,11 +1825,11 @@
 {
     env->canrestore++;
     if (env->cleanwin < NWINDOWS - 1)
-	env->cleanwin++;
+        env->cleanwin++;
     if (env->otherwin == 0)
-	env->cansave--;
+        env->cansave--;
     else
-	env->otherwin--;
+        env->otherwin--;
     FORCE_RET();
 }
 
@@ -1557,8 +1850,7 @@
 
 void OPPROTO op_sir(void)
 {
-    // XXX
-
+    T0 = 0;  // XXX
 }
 
 void OPPROTO op_ld_asi_reg()
@@ -1570,10 +1862,148 @@
 void OPPROTO op_st_asi_reg()
 {
     T0 += PARAM1;
-    helper_st_asi(env->asi, PARAM2, PARAM3);
+    helper_st_asi(env->asi, PARAM2);
+}
+
+void OPPROTO op_ldf_asi_reg()
+{
+    T0 += PARAM1;
+    helper_ldf_asi(env->asi, PARAM2, PARAM3);
+}
+
+void OPPROTO op_stf_asi_reg()
+{
+    T0 += PARAM1;
+    helper_stf_asi(env->asi, PARAM2, PARAM3);
+}
+
+void OPPROTO op_ldf_asi()
+{
+    helper_ldf_asi(PARAM1, PARAM2, PARAM3);
+}
+
+void OPPROTO op_stf_asi()
+{
+    helper_stf_asi(PARAM1, PARAM2, PARAM3);
+}
+
+void OPPROTO op_ldstub_asi_reg()             /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    T0 += PARAM1;
+    helper_ld_asi(env->asi, 1, 0);
+    tmp = T1;
+    T1 = 0xff;
+    helper_st_asi(env->asi, 1);
+    T1 = tmp;
+}
+
+void OPPROTO op_swap_asi_reg()               /* XXX: should be atomically */
+{
+    target_ulong tmp1, tmp2;
+
+    T0 += PARAM1;
+    tmp1 = T1;
+    helper_ld_asi(env->asi, 4, 0);
+    tmp2 = T1;
+    T1 = tmp1;
+    helper_st_asi(env->asi, 4);
+    T1 = tmp2;
+}
+
+void OPPROTO op_ldda_asi()
+{
+    helper_ld_asi(PARAM1, 8, 0);
+    T0 = T1 & 0xffffffffUL;
+    T1 >>= 32;
+}
+
+void OPPROTO op_ldda_asi_reg()
+{
+    T0 += PARAM1;
+    helper_ld_asi(env->asi, 8, 0);
+    T0 = T1 & 0xffffffffUL;
+    T1 >>= 32;
+}
+
+void OPPROTO op_stda_asi()
+{
+    T1 <<= 32;
+    T1 += T2 & 0xffffffffUL;
+    helper_st_asi(PARAM1, 8);
+}
+
+void OPPROTO op_stda_asi_reg()
+{
+    T0 += PARAM1;
+    T1 <<= 32;
+    T1 += T2 & 0xffffffffUL;
+    helper_st_asi(env->asi, 8);
+}
+
+void OPPROTO op_cas_asi()                    /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    tmp = T1 & 0xffffffffUL;
+    helper_ld_asi(PARAM1, 4, 0);
+    if (tmp == T1) {
+        tmp = T1;
+        T1 = T2 & 0xffffffffUL;
+        helper_st_asi(PARAM1, 4);
+        T1 = tmp;
+    }
+    T1 &= 0xffffffffUL;
+}
+
+void OPPROTO op_cas_asi_reg()                /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    T0 += PARAM1;
+    tmp = T1 & 0xffffffffUL;
+    helper_ld_asi(env->asi, 4, 0);
+    if (tmp == T1) {
+        tmp = T1;
+        T1 = T2 & 0xffffffffUL;
+        helper_st_asi(env->asi, 4);
+        T1 = tmp;
+    }
+    T1 &= 0xffffffffUL;
+}
+
+void OPPROTO op_casx_asi()                   /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    tmp = T1;
+    helper_ld_asi(PARAM1, 8, 0);
+    if (tmp == T1) {
+        tmp = T1;
+        T1 = T2;
+        helper_st_asi(PARAM1, 8);
+        T1 = tmp;
+    }
+}
+
+void OPPROTO op_casx_asi_reg()               /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    T0 += PARAM1;
+    tmp = T1;
+    helper_ld_asi(env->asi, 8, 0);
+    if (tmp == T1) {
+        tmp = T1;
+        T1 = T2;
+        helper_st_asi(env->asi, 8);
+        T1 = tmp;
+    }
 }
 #endif
 
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
 void OPPROTO op_ld_asi()
 {
     helper_ld_asi(PARAM1, PARAM2, PARAM3);
@@ -1581,10 +2011,72 @@
 
 void OPPROTO op_st_asi()
 {
-    helper_st_asi(PARAM1, PARAM2, PARAM3);
+    helper_st_asi(PARAM1, PARAM2);
 }
 
+void OPPROTO op_ldstub_asi()                 /* XXX: should be atomically */
+{
+    target_ulong tmp;
+
+    helper_ld_asi(PARAM1, 1, 0);
+    tmp = T1;
+    T1 = 0xff;
+    helper_st_asi(PARAM1, 1);
+    T1 = tmp;
+}
+
+void OPPROTO op_swap_asi()                   /* XXX: should be atomically */
+{
+    target_ulong tmp1, tmp2;
+
+    tmp1 = T1;
+    helper_ld_asi(PARAM1, 4, 0);
+    tmp2 = T1;
+    T1 = tmp1;
+    helper_st_asi(PARAM1, 4);
+    T1 = tmp2;
+}
+#endif
+
 #ifdef TARGET_SPARC64
+// This function uses non-native bit order
+#define GET_FIELD(X, FROM, TO)                                  \
+    ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
+
+// This function uses the order in the manuals, i.e. bit 0 is 2^0
+#define GET_FIELD_SP(X, FROM, TO)               \
+    GET_FIELD(X, 63 - (TO), 63 - (FROM))
+
+void OPPROTO op_array8()
+{
+    T0 = (GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+        (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+        (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+        (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+        (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+        (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12);
+}
+
+void OPPROTO op_array16()
+{
+    T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+          (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+          (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+          (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+          (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+          (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 1;
+}
+
+void OPPROTO op_array32()
+{
+    T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+          (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+          (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+          (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+          (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+          (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 2;
+}
+
 void OPPROTO op_alignaddr()
 {
     uint64_t tmp;
@@ -1601,6 +2093,452 @@
 
     tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
     tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
-    (*((uint64_t *)&DT0)) = tmp;
+    *((uint64_t *)&DT0) = tmp;
 }
+
+void OPPROTO op_movl_FT0_0(void)
+{
+    *((uint32_t *)&FT0) = 0;
+}
+
+void OPPROTO op_movl_DT0_0(void)
+{
+    *((uint64_t *)&DT0) = 0;
+}
+
+void OPPROTO op_movl_FT0_1(void)
+{
+    *((uint32_t *)&FT0) = 0xffffffff;
+}
+
+void OPPROTO op_movl_DT0_1(void)
+{
+    *((uint64_t *)&DT0) = 0xffffffffffffffffULL;
+}
+
+void OPPROTO op_fnot(void)
+{
+    *(uint64_t *)&DT0 = ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fnots(void)
+{
+    *(uint32_t *)&FT0 = ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fnor(void)
+{
+    *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 | *(uint64_t *)&DT1);
+}
+
+void OPPROTO op_fnors(void)
+{
+    *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 | *(uint32_t *)&FT1);
+}
+
+void OPPROTO op_for(void)
+{
+    *(uint64_t *)&DT0 |= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fors(void)
+{
+    *(uint32_t *)&FT0 |= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fxor(void)
+{
+    *(uint64_t *)&DT0 ^= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fxors(void)
+{
+    *(uint32_t *)&FT0 ^= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fand(void)
+{
+    *(uint64_t *)&DT0 &= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fands(void)
+{
+    *(uint32_t *)&FT0 &= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fornot(void)
+{
+    *(uint64_t *)&DT0 = *(uint64_t *)&DT0 | ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fornots(void)
+{
+    *(uint32_t *)&FT0 = *(uint32_t *)&FT0 | ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fandnot(void)
+{
+    *(uint64_t *)&DT0 = *(uint64_t *)&DT0 & ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fandnots(void)
+{
+    *(uint32_t *)&FT0 = *(uint32_t *)&FT0 & ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fnand(void)
+{
+    *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 & *(uint64_t *)&DT1);
+}
+
+void OPPROTO op_fnands(void)
+{
+    *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 & *(uint32_t *)&FT1);
+}
+
+void OPPROTO op_fxnor(void)
+{
+    *(uint64_t *)&DT0 ^= ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fxnors(void)
+{
+    *(uint32_t *)&FT0 ^= ~*(uint32_t *)&FT1;
+}
+
+#ifdef WORDS_BIGENDIAN
+#define VIS_B64(n) b[7 - (n)]
+#define VIS_W64(n) w[3 - (n)]
+#define VIS_SW64(n) sw[3 - (n)]
+#define VIS_L64(n) l[1 - (n)]
+#define VIS_B32(n) b[3 - (n)]
+#define VIS_W32(n) w[1 - (n)]
+#else
+#define VIS_B64(n) b[n]
+#define VIS_W64(n) w[n]
+#define VIS_SW64(n) sw[n]
+#define VIS_L64(n) l[n]
+#define VIS_B32(n) b[n]
+#define VIS_W32(n) w[n]
 #endif
+
+typedef union {
+    uint8_t b[8];
+    uint16_t w[4];
+    int16_t sw[4];
+    uint32_t l[2];
+    float64 d;
+} vis64;
+
+typedef union {
+    uint8_t b[4];
+    uint16_t w[2];
+    uint32_t l;
+    float32 f;
+} vis32;
+
+void OPPROTO op_fpmerge(void)
+{
+    vis64 s, d;
+
+    s.d = DT0;
+    d.d = DT1;
+
+    // Reverse calculation order to handle overlap
+    d.VIS_B64(7) = s.VIS_B64(3);
+    d.VIS_B64(6) = d.VIS_B64(3);
+    d.VIS_B64(5) = s.VIS_B64(2);
+    d.VIS_B64(4) = d.VIS_B64(2);
+    d.VIS_B64(3) = s.VIS_B64(1);
+    d.VIS_B64(2) = d.VIS_B64(1);
+    d.VIS_B64(1) = s.VIS_B64(0);
+    //d.VIS_B64(0) = d.VIS_B64(0);
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16al(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16au(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                 \
+    tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r);       \
+    if ((tmp & 0xff) > 0x7f)                                    \
+        tmp += 0x100;                                           \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8sux16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmul8ulx16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_W64(r) = tmp >> 8;
+
+    PMUL(0);
+    PMUL(1);
+    PMUL(2);
+    PMUL(3);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmuld8sux16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8);       \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_L64(r) = tmp;
+
+    // Reverse calculation order to handle overlap
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fmuld8ulx16(void)
+{
+    vis64 s, d;
+    uint32_t tmp;
+
+    s.d = DT0;
+    d.d = DT1;
+
+#define PMUL(r)                                                         \
+    tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2));        \
+    if ((tmp & 0xff) > 0x7f)                                            \
+        tmp += 0x100;                                                   \
+    d.VIS_L64(r) = tmp;
+
+    // Reverse calculation order to handle overlap
+    PMUL(1);
+    PMUL(0);
+#undef PMUL
+
+    DT0 = d.d;
+}
+
+void OPPROTO op_fexpand(void)
+{
+    vis32 s;
+    vis64 d;
+
+    s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
+    d.d = DT1;
+    d.VIS_L64(0) = s.VIS_W32(0) << 4;
+    d.VIS_L64(1) = s.VIS_W32(1) << 4;
+    d.VIS_L64(2) = s.VIS_W32(2) << 4;
+    d.VIS_L64(3) = s.VIS_W32(3) << 4;
+
+    DT0 = d.d;
+}
+
+#define VIS_OP(name, F)                                 \
+    void OPPROTO name##16(void)                         \
+    {                                                   \
+        vis64 s, d;                                     \
+                                                        \
+        s.d = DT0;                                      \
+        d.d = DT1;                                      \
+                                                        \
+        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0));   \
+        d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1));   \
+        d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2));   \
+        d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3));   \
+                                                        \
+        DT0 = d.d;                                      \
+    }                                                   \
+                                                        \
+    void OPPROTO name##16s(void)                        \
+    {                                                   \
+        vis32 s, d;                                     \
+                                                        \
+        s.f = FT0;                                      \
+        d.f = FT1;                                      \
+                                                        \
+        d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0));   \
+        d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1));   \
+                                                        \
+        FT0 = d.f;                                      \
+    }                                                   \
+                                                        \
+    void OPPROTO name##32(void)                         \
+    {                                                   \
+        vis64 s, d;                                     \
+                                                        \
+        s.d = DT0;                                      \
+        d.d = DT1;                                      \
+                                                        \
+        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0));   \
+        d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1));   \
+                                                        \
+        DT0 = d.d;                                      \
+    }                                                   \
+                                                        \
+    void OPPROTO name##32s(void)                        \
+    {                                                   \
+        vis32 s, d;                                     \
+                                                        \
+        s.f = FT0;                                      \
+        d.f = FT1;                                      \
+                                                        \
+        d.l = F(d.l, s.l);                              \
+                                                        \
+        FT0 = d.f;                                      \
+    }
+
+#define FADD(a, b) ((a) + (b))
+#define FSUB(a, b) ((a) - (b))
+VIS_OP(op_fpadd, FADD)
+VIS_OP(op_fpsub, FSUB)
+
+#define VIS_CMPOP(name, F)                                        \
+    void OPPROTO name##16(void)                                   \
+    {                                                             \
+        vis64 s, d;                                               \
+                                                                  \
+        s.d = DT0;                                                \
+        d.d = DT1;                                                \
+                                                                  \
+        d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0;       \
+        d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0;      \
+        d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0;      \
+        d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0;      \
+                                                                  \
+        DT0 = d.d;                                                \
+    }                                                             \
+                                                                  \
+    void OPPROTO name##32(void)                                   \
+    {                                                             \
+        vis64 s, d;                                               \
+                                                                  \
+        s.d = DT0;                                                \
+        d.d = DT1;                                                \
+                                                                  \
+        d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0;       \
+        d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0;      \
+                                                                  \
+        DT0 = d.d;                                                \
+    }
+
+#define FCMPGT(a, b) ((a) > (b))
+#define FCMPEQ(a, b) ((a) == (b))
+#define FCMPLE(a, b) ((a) <= (b))
+#define FCMPNE(a, b) ((a) != (b))
+
+VIS_CMPOP(op_fcmpgt, FCMPGT)
+VIS_CMPOP(op_fcmpeq, FCMPEQ)
+VIS_CMPOP(op_fcmple, FCMPLE)
+VIS_CMPOP(op_fcmpne, FCMPNE)
+
+#endif
+
+#define CHECK_ALIGN_OP(align)                           \
+    void OPPROTO op_check_align_T0_ ## align (void)     \
+    {                                                   \
+        if (T0 & align)                                 \
+            raise_exception(TT_UNALIGNED);              \
+        FORCE_RET();                                    \
+    }
+
+CHECK_ALIGN_OP(1)
+CHECK_ALIGN_OP(3)
+CHECK_ALIGN_OP(7)
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 0b1d566..fa51cde 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -2,17 +2,52 @@
 
 //#define DEBUG_PCALL
 //#define DEBUG_MMU
+//#define DEBUG_UNALIGNED
+//#define DEBUG_UNASSIGNED
 
 void raise_exception(int tt)
 {
     env->exception_index = tt;
     cpu_loop_exit();
-}   
+}
+
+void check_ieee_exceptions()
+{
+     T0 = get_float_exception_flags(&env->fp_status);
+     if (T0)
+     {
+        /* Copy IEEE 754 flags into FSR */
+        if (T0 & float_flag_invalid)
+            env->fsr |= FSR_NVC;
+        if (T0 & float_flag_overflow)
+            env->fsr |= FSR_OFC;
+        if (T0 & float_flag_underflow)
+            env->fsr |= FSR_UFC;
+        if (T0 & float_flag_divbyzero)
+            env->fsr |= FSR_DZC;
+        if (T0 & float_flag_inexact)
+            env->fsr |= FSR_NXC;
+
+        if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23))
+        {
+            /* Unmasked exception, generate a trap */
+            env->fsr |= FSR_FTT_IEEE_EXCP;
+            raise_exception(TT_FP_EXCP);
+        }
+        else
+        {
+            /* Accumulate exceptions */
+            env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+        }
+     }
+}
 
 #ifdef USE_INT_TO_FLOAT_HELPERS
 void do_fitos(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void do_fitod(void)
@@ -35,23 +70,29 @@
 
 void do_fsqrts(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     FT0 = float32_sqrt(FT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
 void do_fsqrtd(void)
 {
+    set_float_exception_flags(0, &env->fp_status);
     DT0 = float64_sqrt(DT1, &env->fp_status);
+    check_ieee_exceptions();
 }
 
-#define GEN_FCMP(name, size, reg1, reg2, FS)                            \
+#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP)                      \
     void glue(do_, name) (void)                                         \
     {                                                                   \
         env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS);                     \
         switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) {   \
         case float_relation_unordered:                                  \
             T0 = (FSR_FCC1 | FSR_FCC0) << FS;                           \
-            if (env->fsr & FSR_NVM) {                                   \
+            if ((env->fsr & FSR_NVM) || TRAP) {                         \
                 env->fsr |= T0;                                         \
+                env->fsr |= FSR_NVC;                                    \
+                env->fsr |= FSR_FTT_IEEE_EXCP;                          \
                 raise_exception(TT_FP_EXCP);                            \
             } else {                                                    \
                 env->fsr |= FSR_NVA;                                    \
@@ -70,64 +111,129 @@
         env->fsr |= T0;                                                 \
     }
 
-GEN_FCMP(fcmps, float32, FT0, FT1, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0);
+GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+
+GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
 
 #ifdef TARGET_SPARC64
-GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22);
+GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
 
-GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24);
+GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
 
-GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26);
+GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+
+GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+
+GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+
+GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
 #endif
 
-#if defined(CONFIG_USER_ONLY) 
-void helper_ld_asi(int asi, int size, int sign)
-{
-}
-
-void helper_st_asi(int asi, int size, int sign)
-{
-}
-#else
 #ifndef TARGET_SPARC64
+#ifndef CONFIG_USER_ONLY
 void helper_ld_asi(int asi, int size, int sign)
 {
     uint32_t ret = 0;
 
     switch (asi) {
+    case 2: /* SuperSparc MXCC registers */
+        break;
     case 3: /* MMU probe */
-	{
-	    int mmulev;
+        {
+            int mmulev;
 
-	    mmulev = (T0 >> 8) & 15;
-	    if (mmulev > 4)
-		ret = 0;
-	    else {
-		ret = mmu_probe(env, T0, mmulev);
-		//bswap32s(&ret);
-	    }
+            mmulev = (T0 >> 8) & 15;
+            if (mmulev > 4)
+                ret = 0;
+            else {
+                ret = mmu_probe(env, T0, mmulev);
+                //bswap32s(&ret);
+            }
 #ifdef DEBUG_MMU
-	    printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
+            printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
 #endif
-	}
-	break;
+        }
+        break;
     case 4: /* read MMU regs */
-	{
-	    int reg = (T0 >> 8) & 0xf;
-	    
-	    ret = env->mmuregs[reg];
-	    if (reg == 3) /* Fault status cleared on read */
-		env->mmuregs[reg] = 0;
+        {
+            int reg = (T0 >> 8) & 0xf;
+
+            ret = env->mmuregs[reg];
+            if (reg == 3) /* Fault status cleared on read */
+                env->mmuregs[reg] = 0;
 #ifdef DEBUG_MMU
-	    printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
+            printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
 #endif
-	}
-	break;
-    case 0x20 ... 0x2f: /* MMU passthrough */
+        }
+        break;
+    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 0xa: /* User data access */
+        switch(size) {
+        case 1:
+            ret = ldub_user(T0);
+            break;
+        case 2:
+            ret = lduw_user(T0 & ~1);
+            break;
+        default:
+        case 4:
+            ret = ldl_user(T0 & ~3);
+            break;
+        case 8:
+            ret = ldl_user(T0 & ~3);
+            T0 = ldl_user((T0 + 4) & ~3);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch(size) {
+        case 1:
+            ret = ldub_kernel(T0);
+            break;
+        case 2:
+            ret = lduw_kernel(T0 & ~1);
+            break;
+        default:
+        case 4:
+            ret = ldl_kernel(T0 & ~3);
+            break;
+        case 8:
+            ret = ldl_kernel(T0 & ~3);
+            T0 = ldl_kernel((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);
@@ -140,64 +246,106 @@
             ret = ldl_phys(T0 & ~3);
             break;
         case 8:
-	    ret = ldl_phys(T0 & ~3);
-	    T0 = ldl_phys((T0 + 4) & ~3);
-	    break;
+            ret = ldl_phys(T0 & ~3);
+            T0 = ldl_phys((T0 + 4) & ~3);
+            break;
         }
-	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:
-	ret = 0;
-	break;
+        do_unassigned_access(T0, 0, 0, 1);
+        ret = 0;
+        break;
     }
-    T1 = ret;
+    if (sign) {
+        switch(size) {
+        case 1:
+            T1 = (int8_t) ret;
+            break;
+        case 2:
+            T1 = (int16_t) ret;
+            break;
+        default:
+            T1 = ret;
+            break;
+        }
+    }
+    else
+        T1 = ret;
 }
 
-void helper_st_asi(int asi, int size, int sign)
+void helper_st_asi(int asi, int size)
 {
     switch(asi) {
+    case 2: /* SuperSparc MXCC registers */
+        break;
     case 3: /* MMU flush */
-	{
-	    int mmulev;
+        {
+            int mmulev;
 
-	    mmulev = (T0 >> 8) & 15;
+            mmulev = (T0 >> 8) & 15;
 #ifdef DEBUG_MMU
-	    printf("mmu flush level %d\n", mmulev);
+            printf("mmu flush level %d\n", mmulev);
 #endif
-	    switch (mmulev) {
-	    case 0: // flush page
-		tlb_flush_page(env, T0 & 0xfffff000);
-		break;
-	    case 1: // flush segment (256k)
-	    case 2: // flush region (16M)
-	    case 3: // flush context (4G)
-	    case 4: // flush entire
-		tlb_flush(env, 1);
-		break;
-	    default:
-		break;
-	    }
+            switch (mmulev) {
+            case 0: // flush page
+                tlb_flush_page(env, T0 & 0xfffff000);
+                break;
+            case 1: // flush segment (256k)
+            case 2: // flush region (16M)
+            case 3: // flush context (4G)
+            case 4: // flush entire
+                tlb_flush(env, 1);
+                break;
+            default:
+                break;
+            }
 #ifdef DEBUG_MMU
-	    dump_mmu(env);
+            dump_mmu(env);
 #endif
-	    return;
-	}
+            return;
+        }
     case 4: /* write MMU regs */
-	{
-	    int reg = (T0 >> 8) & 0xf;
-	    uint32_t oldreg;
-	    
-	    oldreg = env->mmuregs[reg];
+        {
+            int reg = (T0 >> 8) & 0xf;
+            uint32_t oldreg;
+
+            oldreg = env->mmuregs[reg];
             switch(reg) {
             case 0:
-		env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
-		env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
-		// Mappings generated during no-fault mode or MMU
-		// disabled mode are invalid in normal mode
+                env->mmuregs[reg] &= ~(MMU_E | MMU_NF | MMU_BM);
+                env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF | MMU_BM);
+                // Mappings generated during no-fault mode or MMU
+                // disabled mode are invalid in normal mode
                 if (oldreg != env->mmuregs[reg])
                     tlb_flush(env, 1);
                 break;
             case 2:
-		env->mmuregs[reg] = T1;
+                env->mmuregs[reg] = T1;
                 if (oldreg != env->mmuregs[reg]) {
                     /* we flush when the MMU context changes because
                        QEMU has no MMU context support */
@@ -208,50 +356,94 @@
             case 4:
                 break;
             default:
-		env->mmuregs[reg] = T1;
+                env->mmuregs[reg] = T1;
                 break;
             }
 #ifdef DEBUG_MMU
             if (oldreg != env->mmuregs[reg]) {
                 printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]);
             }
-	    dump_mmu(env);
+            dump_mmu(env);
 #endif
-	    return;
-	}
+            return;
+        }
+    case 0xa: /* User data access */
+        switch(size) {
+        case 1:
+            stb_user(T0, T1);
+            break;
+        case 2:
+            stw_user(T0 & ~1, T1);
+            break;
+        default:
+        case 4:
+            stl_user(T0 & ~3, T1);
+            break;
+        case 8:
+            stl_user(T0 & ~3, T1);
+            stl_user((T0 + 4) & ~3, T2);
+            break;
+        }
+        break;
+    case 0xb: /* Supervisor data access */
+        switch(size) {
+        case 1:
+            stb_kernel(T0, T1);
+            break;
+        case 2:
+            stw_kernel(T0 & ~1, T1);
+            break;
+        default:
+        case 4:
+            stl_kernel(T0 & ~3, T1);
+            break;
+        case 8:
+            stl_kernel(T0 & ~3, T1);
+            stl_kernel((T0 + 4) & ~3, T2);
+            break;
+        }
+        break;
+    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];
-	    
-	    tswap32s(&src);
+        {
+            // value (T1) = src
+            // address (T0) = dst
+            // copy 32 bytes
+            unsigned int i;
+            uint32_t src = T1 & ~3, dst = T0 & ~3, temp;
 
-	    cpu_physical_memory_read(src, (void *) &temp, 32);
-	    cpu_physical_memory_write(dst, (void *) &temp, 32);
-	}
-	return;
+            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 */
-	{
-	    // 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);
+        {
+            // value (T1, T2)
+            // address (T0) = dst
+            // fill 32 bytes
+            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);
-	    }
-	}
-	return;
-    case 0x20 ... 0x2f: /* MMU passthrough */
-	{
+            val = (((uint64_t)T1) << 32) | T2;
+
+            for (i = 0; i < 32; i += 8, dst += 8)
+                stq_kernel(dst, val);
+        }
+        return;
+    case 0x20: /* MMU passthrough */
+        {
             switch(size) {
             case 1:
                 stb_phys(T0, T1);
@@ -268,26 +460,249 @@
                 stl_phys((T0 + 4) & ~3, T2);
                 break;
             }
-	}
-	return;
+        }
+        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:
-	return;
+        do_unassigned_access(T0, 1, 0, 1);
+        return;
     }
 }
 
-#else
+#endif /* CONFIG_USER_ONLY */
+#else /* TARGET_SPARC64 */
+
+#ifdef CONFIG_USER_ONLY
+void helper_ld_asi(int asi, int size, int sign)
+{
+    uint64_t ret = 0;
+
+    if (asi < 0x80)
+        raise_exception(TT_PRIV_ACT);
+
+    switch (asi) {
+    case 0x80: // Primary
+    case 0x82: // Primary no-fault
+    case 0x88: // Primary LE
+    case 0x8a: // Primary no-fault LE
+        {
+            switch(size) {
+            case 1:
+                ret = ldub_raw(T0);
+                break;
+            case 2:
+                ret = lduw_raw(T0 & ~1);
+                break;
+            case 4:
+                ret = ldl_raw(T0 & ~3);
+                break;
+            default:
+            case 8:
+                ret = ldq_raw(T0 & ~7);
+                break;
+            }
+        }
+        break;
+    case 0x81: // Secondary
+    case 0x83: // Secondary no-fault
+    case 0x89: // Secondary LE
+    case 0x8b: // Secondary no-fault LE
+        // XXX
+        break;
+    default:
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+    case 0x8a: // Primary no-fault LE
+    case 0x8b: // Secondary no-fault LE
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch(size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
+    }
+    T1 = ret;
+}
+
+void helper_st_asi(int asi, int size)
+{
+    if (asi < 0x80)
+        raise_exception(TT_PRIV_ACT);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+        switch(size) {
+        case 2:
+            T0 = bswap16(T0);
+            break;
+        case 4:
+            T0 = bswap32(T0);
+            break;
+        case 8:
+            T0 = bswap64(T0);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    switch(asi) {
+    case 0x80: // Primary
+    case 0x88: // Primary LE
+        {
+            switch(size) {
+            case 1:
+                stb_raw(T0, T1);
+                break;
+            case 2:
+                stw_raw(T0 & ~1, T1);
+                break;
+            case 4:
+                stl_raw(T0 & ~3, T1);
+                break;
+            case 8:
+            default:
+                stq_raw(T0 & ~7, T1);
+                break;
+            }
+        }
+        break;
+    case 0x81: // Secondary
+    case 0x89: // Secondary LE
+        // XXX
+        return;
+
+    case 0x82: // Primary no-fault, RO
+    case 0x83: // Secondary no-fault, RO
+    case 0x8a: // Primary no-fault LE, RO
+    case 0x8b: // Secondary no-fault LE, RO
+    default:
+        do_unassigned_access(T0, 1, 0, 1);
+        return;
+    }
+}
+
+#else /* CONFIG_USER_ONLY */
 
 void helper_ld_asi(int asi, int size, int sign)
 {
     uint64_t ret = 0;
 
     if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-	raise_exception(TT_PRIV_ACT);
+        raise_exception(TT_PRIV_ACT);
 
     switch (asi) {
+    case 0x10: // As if user primary
+    case 0x18: // As if user primary LE
+    case 0x80: // Primary
+    case 0x82: // Primary no-fault
+    case 0x88: // Primary LE
+    case 0x8a: // Primary no-fault LE
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            switch(size) {
+            case 1:
+                ret = ldub_kernel(T0);
+                break;
+            case 2:
+                ret = lduw_kernel(T0 & ~1);
+                break;
+            case 4:
+                ret = ldl_kernel(T0 & ~3);
+                break;
+            default:
+            case 8:
+                ret = ldq_kernel(T0 & ~7);
+                break;
+            }
+        } else {
+            switch(size) {
+            case 1:
+                ret = ldub_user(T0);
+                break;
+            case 2:
+                ret = lduw_user(T0 & ~1);
+                break;
+            case 4:
+                ret = ldl_user(T0 & ~3);
+                break;
+            default:
+            case 8:
+                ret = ldq_user(T0 & ~7);
+                break;
+            }
+        }
+        break;
     case 0x14: // Bypass
     case 0x15: // Bypass, non-cacheable
-	{
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+        {
             switch(size) {
             case 1:
                 ret = ldub_phys(T0);
@@ -303,77 +718,71 @@
                 ret = ldq_phys(T0 & ~7);
                 break;
             }
-	    break;
-	}
+            break;
+        }
     case 0x04: // Nucleus
     case 0x0c: // Nucleus Little Endian (LE)
-    case 0x10: // As if user primary
     case 0x11: // As if user secondary
-    case 0x18: // As if user primary LE
     case 0x19: // As if user secondary LE
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
     case 0x24: // Nucleus quad LDD 128 bit atomic
     case 0x2c: // Nucleus quad LDD 128 bit atomic
     case 0x4a: // UPA config
-    case 0x82: // Primary no-fault
+    case 0x81: // Secondary
     case 0x83: // Secondary no-fault
-    case 0x88: // Primary LE
     case 0x89: // Secondary LE
-    case 0x8a: // Primary no-fault LE
     case 0x8b: // Secondary no-fault LE
-	// XXX
-	break;
+        // XXX
+        break;
     case 0x45: // LSU
-	ret = env->lsu;
-	break;
+        ret = env->lsu;
+        break;
     case 0x50: // I-MMU regs
-	{
-	    int reg = (T0 >> 3) & 0xf;
+        {
+            int reg = (T0 >> 3) & 0xf;
 
-	    ret = env->immuregs[reg];
-	    break;
-	}
+            ret = env->immuregs[reg];
+            break;
+        }
     case 0x51: // I-MMU 8k TSB pointer
     case 0x52: // I-MMU 64k TSB pointer
     case 0x55: // I-MMU data access
-	// XXX
-	break;
+        // XXX
+        break;
     case 0x56: // I-MMU tag read
-	{
-	    unsigned int i;
-	    
-	    for (i = 0; i < 64; i++) {
-		// Valid, ctx match, vaddr match
-		if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 &&
-		    env->itlb_tag[i] == T0) {
-		    ret = env->itlb_tag[i];
-		    break;
-		}
-	    }
-	    break;
-	}
-    case 0x58: // D-MMU regs
-	{
-	    int reg = (T0 >> 3) & 0xf;
+        {
+            unsigned int i;
 
-	    ret = env->dmmuregs[reg];
-	    break;
-	}
+            for (i = 0; i < 64; i++) {
+                // Valid, ctx match, vaddr match
+                if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 &&
+                    env->itlb_tag[i] == T0) {
+                    ret = env->itlb_tag[i];
+                    break;
+                }
+            }
+            break;
+        }
+    case 0x58: // D-MMU regs
+        {
+            int reg = (T0 >> 3) & 0xf;
+
+            ret = env->dmmuregs[reg];
+            break;
+        }
     case 0x5e: // D-MMU tag read
-	{
-	    unsigned int i;
-	    
-	    for (i = 0; i < 64; i++) {
-		// Valid, ctx match, vaddr match
-		if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 &&
-		    env->dtlb_tag[i] == T0) {
-		    ret = env->dtlb_tag[i];
-		    break;
-		}
-	    }
-	    break;
-	}
+        {
+            unsigned int i;
+
+            for (i = 0; i < 64; i++) {
+                // Valid, ctx match, vaddr match
+                if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 &&
+                    env->dtlb_tag[i] == T0) {
+                    ret = env->dtlb_tag[i];
+                    break;
+                }
+            }
+            break;
+        }
     case 0x59: // D-MMU 8k TSB pointer
     case 0x5a: // D-MMU 64k TSB pointer
     case 0x5b: // D-MMU data pointer
@@ -381,29 +790,142 @@
     case 0x48: // Interrupt dispatch, RO
     case 0x49: // Interrupt data receive
     case 0x7f: // Incoming interrupt vector, RO
-	// XXX
-	break;
+        // XXX
+        break;
     case 0x54: // I-MMU data in, WO
     case 0x57: // I-MMU demap, WO
     case 0x5c: // D-MMU data in, WO
     case 0x5f: // D-MMU demap, WO
     case 0x77: // Interrupt vector, WO
     default:
-	ret = 0;
-	break;
+        do_unassigned_access(T0, 0, 0, 1);
+        ret = 0;
+        break;
+    }
+
+    /* Convert from little endian */
+    switch (asi) {
+    case 0x0c: // Nucleus Little Endian (LE)
+    case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+    case 0x8a: // Primary no-fault LE
+    case 0x8b: // Secondary no-fault LE
+        switch(size) {
+        case 2:
+            ret = bswap16(ret);
+            break;
+        case 4:
+            ret = bswap32(ret);
+            break;
+        case 8:
+            ret = bswap64(ret);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
+
+    /* Convert to signed number */
+    if (sign) {
+        switch(size) {
+        case 1:
+            ret = (int8_t) ret;
+            break;
+        case 2:
+            ret = (int16_t) ret;
+            break;
+        case 4:
+            ret = (int32_t) ret;
+            break;
+        default:
+            break;
+        }
     }
     T1 = ret;
 }
 
-void helper_st_asi(int asi, int size, int sign)
+void helper_st_asi(int asi, int size)
 {
     if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
-	raise_exception(TT_PRIV_ACT);
+        raise_exception(TT_PRIV_ACT);
+
+    /* Convert to little endian */
+    switch (asi) {
+    case 0x0c: // Nucleus Little Endian (LE)
+    case 0x18: // As if user primary LE
+    case 0x19: // As if user secondary LE
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+    case 0x81: // Secondary
+    case 0x88: // Primary LE
+    case 0x89: // Secondary LE
+        switch(size) {
+        case 2:
+            T0 = bswap16(T0);
+            break;
+        case 4:
+            T0 = bswap32(T0);
+            break;
+        case 8:
+            T0 = bswap64(T0);
+            break;
+        default:
+            break;
+        }
+    default:
+        break;
+    }
 
     switch(asi) {
+    case 0x10: // As if user primary
+    case 0x18: // As if user primary LE
+    case 0x80: // Primary
+    case 0x88: // Primary LE
+        if ((asi & 0x80) && (env->pstate & PS_PRIV)) {
+            switch(size) {
+            case 1:
+                stb_kernel(T0, T1);
+                break;
+            case 2:
+                stw_kernel(T0 & ~1, T1);
+                break;
+            case 4:
+                stl_kernel(T0 & ~3, T1);
+                break;
+            case 8:
+            default:
+                stq_kernel(T0 & ~7, T1);
+                break;
+            }
+        } else {
+            switch(size) {
+            case 1:
+                stb_user(T0, T1);
+                break;
+            case 2:
+                stw_user(T0 & ~1, T1);
+                break;
+            case 4:
+                stl_user(T0 & ~3, T1);
+                break;
+            case 8:
+            default:
+                stq_user(T0 & ~7, T1);
+                break;
+            }
+        }
+        break;
     case 0x14: // Bypass
     case 0x15: // Bypass, non-cacheable
-	{
+    case 0x1c: // Bypass LE
+    case 0x1d: // Bypass, non-cacheable LE
+        {
             switch(size) {
             case 1:
                 stb_phys(T0, T1);
@@ -419,46 +941,41 @@
                 stq_phys(T0 & ~7, T1);
                 break;
             }
-	}
-	return;
+        }
+        return;
     case 0x04: // Nucleus
     case 0x0c: // Nucleus Little Endian (LE)
-    case 0x10: // As if user primary
     case 0x11: // As if user secondary
-    case 0x18: // As if user primary LE
     case 0x19: // As if user secondary LE
-    case 0x1c: // Bypass LE
-    case 0x1d: // Bypass, non-cacheable LE
     case 0x24: // Nucleus quad LDD 128 bit atomic
     case 0x2c: // Nucleus quad LDD 128 bit atomic
     case 0x4a: // UPA config
-    case 0x88: // Primary LE
     case 0x89: // Secondary LE
-	// XXX
-	return;
+        // XXX
+        return;
     case 0x45: // LSU
-	{
-	    uint64_t oldreg;
+        {
+            uint64_t oldreg;
 
-	    oldreg = env->lsu;
-	    env->lsu = T1 & (DMMU_E | IMMU_E);
-	    // Mappings generated during D/I MMU disabled mode are
-	    // invalid in normal mode
-	    if (oldreg != env->lsu) {
+            oldreg = env->lsu;
+            env->lsu = T1 & (DMMU_E | IMMU_E);
+            // Mappings generated during D/I MMU disabled mode are
+            // invalid in normal mode
+            if (oldreg != env->lsu) {
 #ifdef DEBUG_MMU
                 printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu);
-		dump_mmu(env);
+                dump_mmu(env);
 #endif
-		tlb_flush(env, 1);
-	    }
-	    return;
-	}
+                tlb_flush(env, 1);
+            }
+            return;
+        }
     case 0x50: // I-MMU regs
-	{
-	    int reg = (T0 >> 3) & 0xf;
-	    uint64_t oldreg;
-	    
-	    oldreg = env->immuregs[reg];
+        {
+            int reg = (T0 >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->immuregs[reg];
             switch(reg) {
             case 0: // RO
             case 4:
@@ -469,73 +986,73 @@
             case 8:
                 return;
             case 3: // SFSR
-		if ((T1 & 1) == 0)
-		    T1 = 0; // Clear SFSR
+                if ((T1 & 1) == 0)
+                    T1 = 0; // Clear SFSR
                 break;
             case 5: // TSB access
             case 6: // Tag access
             default:
                 break;
             }
-	    env->immuregs[reg] = T1;
+            env->immuregs[reg] = T1;
 #ifdef DEBUG_MMU
             if (oldreg != env->immuregs[reg]) {
                 printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
             }
-	    dump_mmu(env);
+            dump_mmu(env);
 #endif
-	    return;
-	}
+            return;
+        }
     case 0x54: // I-MMU data in
-	{
-	    unsigned int i;
+        {
+            unsigned int i;
 
-	    // Try finding an invalid entry
-	    for (i = 0; i < 64; i++) {
-		if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
-		    env->itlb_tag[i] = env->immuregs[6];
-		    env->itlb_tte[i] = T1;
-		    return;
-		}
-	    }
-	    // Try finding an unlocked entry
-	    for (i = 0; i < 64; i++) {
-		if ((env->itlb_tte[i] & 0x40) == 0) {
-		    env->itlb_tag[i] = env->immuregs[6];
-		    env->itlb_tte[i] = T1;
-		    return;
-		}
-	    }
-	    // error state?
-	    return;
-	}
+            // Try finding an invalid entry
+            for (i = 0; i < 64; i++) {
+                if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
+                    env->itlb_tag[i] = env->immuregs[6];
+                    env->itlb_tte[i] = T1;
+                    return;
+                }
+            }
+            // Try finding an unlocked entry
+            for (i = 0; i < 64; i++) {
+                if ((env->itlb_tte[i] & 0x40) == 0) {
+                    env->itlb_tag[i] = env->immuregs[6];
+                    env->itlb_tte[i] = T1;
+                    return;
+                }
+            }
+            // error state?
+            return;
+        }
     case 0x55: // I-MMU data access
-	{
-	    unsigned int i = (T0 >> 3) & 0x3f;
+        {
+            unsigned int i = (T0 >> 3) & 0x3f;
 
-	    env->itlb_tag[i] = env->immuregs[6];
-	    env->itlb_tte[i] = T1;
-	    return;
-	}
+            env->itlb_tag[i] = env->immuregs[6];
+            env->itlb_tte[i] = T1;
+            return;
+        }
     case 0x57: // I-MMU demap
-	// XXX
-	return;
+        // XXX
+        return;
     case 0x58: // D-MMU regs
-	{
-	    int reg = (T0 >> 3) & 0xf;
-	    uint64_t oldreg;
-	    
-	    oldreg = env->dmmuregs[reg];
+        {
+            int reg = (T0 >> 3) & 0xf;
+            uint64_t oldreg;
+
+            oldreg = env->dmmuregs[reg];
             switch(reg) {
             case 0: // RO
             case 4:
                 return;
             case 3: // SFSR
-		if ((T1 & 1) == 0) {
-		    T1 = 0; // Clear SFSR, Fault address
-		    env->dmmuregs[4] = 0;
-		}
-		env->dmmuregs[reg] = T1;
+                if ((T1 & 1) == 0) {
+                    T1 = 0; // Clear SFSR, Fault address
+                    env->dmmuregs[4] = 0;
+                }
+                env->dmmuregs[reg] = T1;
                 break;
             case 1: // Primary context
             case 2: // Secondary context
@@ -546,50 +1063,50 @@
             default:
                 break;
             }
-	    env->dmmuregs[reg] = T1;
+            env->dmmuregs[reg] = T1;
 #ifdef DEBUG_MMU
             if (oldreg != env->dmmuregs[reg]) {
                 printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
             }
-	    dump_mmu(env);
+            dump_mmu(env);
 #endif
-	    return;
-	}
+            return;
+        }
     case 0x5c: // D-MMU data in
-	{
-	    unsigned int i;
+        {
+            unsigned int i;
 
-	    // Try finding an invalid entry
-	    for (i = 0; i < 64; i++) {
-		if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
-		    env->dtlb_tag[i] = env->dmmuregs[6];
-		    env->dtlb_tte[i] = T1;
-		    return;
-		}
-	    }
-	    // Try finding an unlocked entry
-	    for (i = 0; i < 64; i++) {
-		if ((env->dtlb_tte[i] & 0x40) == 0) {
-		    env->dtlb_tag[i] = env->dmmuregs[6];
-		    env->dtlb_tte[i] = T1;
-		    return;
-		}
-	    }
-	    // error state?
-	    return;
-	}
+            // Try finding an invalid entry
+            for (i = 0; i < 64; i++) {
+                if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
+                    env->dtlb_tag[i] = env->dmmuregs[6];
+                    env->dtlb_tte[i] = T1;
+                    return;
+                }
+            }
+            // Try finding an unlocked entry
+            for (i = 0; i < 64; i++) {
+                if ((env->dtlb_tte[i] & 0x40) == 0) {
+                    env->dtlb_tag[i] = env->dmmuregs[6];
+                    env->dtlb_tte[i] = T1;
+                    return;
+                }
+            }
+            // error state?
+            return;
+        }
     case 0x5d: // D-MMU data access
-	{
-	    unsigned int i = (T0 >> 3) & 0x3f;
+        {
+            unsigned int i = (T0 >> 3) & 0x3f;
 
-	    env->dtlb_tag[i] = env->dmmuregs[6];
-	    env->dtlb_tte[i] = T1;
-	    return;
-	}
+            env->dtlb_tag[i] = env->dmmuregs[6];
+            env->dtlb_tte[i] = T1;
+            return;
+        }
     case 0x5f: // D-MMU demap
     case 0x49: // Interrupt data receive
-	// XXX
-	return;
+        // XXX
+        return;
     case 0x51: // I-MMU 8k TSB pointer, RO
     case 0x52: // I-MMU 64k TSB pointer, RO
     case 0x56: // I-MMU tag read, RO
@@ -604,19 +1121,96 @@
     case 0x8a: // Primary no-fault LE, RO
     case 0x8b: // Secondary no-fault LE, RO
     default:
-	return;
+        do_unassigned_access(T0, 1, 0, 1);
+        return;
     }
 }
-#endif
-#endif /* !CONFIG_USER_ONLY */
+#endif /* CONFIG_USER_ONLY */
+
+void helper_ldf_asi(int asi, int size, int rd)
+{
+    target_ulong tmp_T0 = T0, tmp_T1 = T1;
+    unsigned int i;
+
+    switch (asi) {
+    case 0xf0: // Block load primary
+    case 0xf1: // Block load secondary
+    case 0xf8: // Block load primary LE
+    case 0xf9: // Block load secondary LE
+        for (i = 0; i < 8; i++) {
+            helper_ld_asi(asi & 0x8f, 8, 0);
+            *((int64_t *)&DT0) = T1;
+            T0 += 8;
+        }
+        T0 = tmp_T0;
+        T1 = tmp_T1;
+
+        return;
+    default:
+        break;
+    }
+
+    helper_ld_asi(asi, size, 0);
+    switch(size) {
+    default:
+    case 4:
+        *((uint32_t *)&FT0) = T1;
+        break;
+    case 8:
+        *((int64_t *)&DT0) = T1;
+        break;
+    }
+    T1 = tmp_T1;
+}
+
+void helper_stf_asi(int asi, int size, int rd)
+{
+    target_ulong tmp_T0 = T0, tmp_T1 = T1;
+    unsigned int i;
+
+    switch (asi) {
+    case 0xf0: // Block store primary
+    case 0xf1: // Block store secondary
+    case 0xf8: // Block store primary LE
+    case 0xf9: // Block store secondary LE
+        for (i = 0; i < 8; i++) {
+            T1 = *((int64_t *)&DT0);
+            helper_st_asi(asi & 0x8f, 8);
+            T0 += 8;
+        }
+        T0 = tmp_T0;
+        T1 = tmp_T1;
+
+        return;
+    default:
+        break;
+    }
+
+    switch(size) {
+    default:
+    case 4:
+        T1 = *((uint32_t *)&FT0);
+        break;
+    case 8:
+        T1 = *((int64_t *)&DT0);
+        break;
+    }
+    helper_st_asi(asi, size);
+    T1 = tmp_T1;
+}
+
+#endif /* TARGET_SPARC64 */
 
 #ifndef TARGET_SPARC64
 void helper_rett()
 {
     unsigned int cwp;
 
+    if (env->psret == 1)
+        raise_exception(TT_ILL_INSN);
+
     env->psret = 1;
-    cwp = (env->cwp + 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp + 1) & (NWINDOWS - 1);
     if (env->wim & (1 << cwp)) {
         raise_exception(TT_WIN_UNF);
     }
@@ -631,17 +1225,17 @@
     switch (env->fsr & FSR_RD_MASK) {
     case FSR_RD_NEAREST:
         rnd_mode = float_round_nearest_even;
-	break;
+        break;
     default:
     case FSR_RD_ZERO:
         rnd_mode = float_round_to_zero;
-	break;
+        break;
     case FSR_RD_POS:
         rnd_mode = float_round_up;
-	break;
+        break;
     case FSR_RD_NEG:
         rnd_mode = float_round_down;
-	break;
+        break;
     }
     set_float_rounding_mode(rnd_mode, &env->fp_status);
 }
@@ -655,7 +1249,10 @@
 #ifndef TARGET_SPARC64
 void do_wrpsr()
 {
-    PUT_PSR(env, T0);
+    if ((T0 & PSR_CWP) >= NWINDOWS)
+        raise_exception(TT_ILL_INSN);
+    else
+        PUT_PSR(env, T0);
 }
 
 void do_rdpsr()
@@ -680,34 +1277,38 @@
     switch (pstate) {
     default:
     case 0:
-	return env->bgregs;
+        return env->bgregs;
     case PS_AG:
-	return env->agregs;
+        return env->agregs;
     case PS_MG:
-	return env->mgregs;
+        return env->mgregs;
     case PS_IG:
-	return env->igregs;
+        return env->igregs;
     }
 }
 
-void do_wrpstate()
+static inline void change_pstate(uint64_t new_pstate)
 {
-    uint64_t new_pstate, pstate_regs, new_pstate_regs;
+    uint64_t pstate_regs, new_pstate_regs;
     uint64_t *src, *dst;
 
-    new_pstate = T0 & 0xf3f;
     pstate_regs = env->pstate & 0xc01;
     new_pstate_regs = new_pstate & 0xc01;
     if (new_pstate_regs != pstate_regs) {
-	// Switch global register bank
-	src = get_gregset(new_pstate_regs);
-	dst = get_gregset(pstate_regs);
-	memcpy32(dst, env->gregs);
-	memcpy32(env->gregs, src);
+        // Switch global register bank
+        src = get_gregset(new_pstate_regs);
+        dst = get_gregset(pstate_regs);
+        memcpy32(dst, env->gregs);
+        memcpy32(env->gregs, src);
     }
     env->pstate = new_pstate;
 }
 
+void do_wrpstate(void)
+{
+    change_pstate(T0 & 0xf3f);
+}
+
 void do_done(void)
 {
     env->tl--;
@@ -715,8 +1316,8 @@
     env->npc = env->tnpc[env->tl] + 4;
     PUT_CCR(env, env->tstate[env->tl] >> 32);
     env->asi = (env->tstate[env->tl] >> 24) & 0xff;
-    env->pstate = (env->tstate[env->tl] >> 8) & 0xfff;
-    set_cwp(env->tstate[env->tl] & 0xff);
+    change_pstate((env->tstate[env->tl] >> 8) & 0xf3f);
+    PUT_CWP64(env, env->tstate[env->tl] & 0xff);
 }
 
 void do_retry(void)
@@ -726,8 +1327,8 @@
     env->npc = env->tnpc[env->tl];
     PUT_CCR(env, env->tstate[env->tl] >> 32);
     env->asi = (env->tstate[env->tl] >> 24) & 0xff;
-    env->pstate = (env->tstate[env->tl] >> 8) & 0xfff;
-    set_cwp(env->tstate[env->tl] & 0xff);
+    change_pstate((env->tstate[env->tl] >> 8) & 0xf3f);
+    PUT_CWP64(env, env->tstate[env->tl] & 0xff);
 }
 #endif
 
@@ -768,48 +1369,55 @@
 {
 #ifdef DEBUG_PCALL
     if (loglevel & CPU_LOG_INT) {
-	static int count;
-	fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n",
+        static int count;
+        fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n",
                 count, intno,
                 env->pc,
                 env->npc, env->regwptr[6]);
-	cpu_dump_state(env, logfile, fprintf, 0);
+        cpu_dump_state(env, logfile, fprintf, 0);
 #if 0
-	{
-	    int i;
-	    uint8_t *ptr;
+        {
+            int i;
+            uint8_t *ptr;
 
-	    fprintf(logfile, "       code=");
-	    ptr = (uint8_t *)env->pc;
-	    for(i = 0; i < 16; i++) {
-		fprintf(logfile, " %02x", ldub(ptr + i));
-	    }
-	    fprintf(logfile, "\n");
-	}
+            fprintf(logfile, "       code=");
+            ptr = (uint8_t *)env->pc;
+            for(i = 0; i < 16; i++) {
+                fprintf(logfile, " %02x", ldub(ptr + i));
+            }
+            fprintf(logfile, "\n");
+        }
 #endif
-	count++;
+        count++;
     }
 #endif
-#if !defined(CONFIG_USER_ONLY) 
+#if !defined(CONFIG_USER_ONLY)
     if (env->tl == MAXTL) {
         cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index);
-	return;
+        return;
     }
 #endif
     env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) |
-	((env->pstate & 0xfff) << 8) | (env->cwp & 0xff);
+        ((env->pstate & 0xf3f) << 8) | GET_CWP64(env);
     env->tpc[env->tl] = env->pc;
     env->tnpc[env->tl] = env->npc;
     env->tt[env->tl] = intno;
-    env->pstate = PS_PEF | PS_PRIV | PS_AG;
+    change_pstate(PS_PEF | PS_PRIV | PS_AG);
+
+    if (intno == TT_CLRWIN)
+        set_cwp((env->cwp - 1) & (NWINDOWS - 1));
+    else if ((intno & 0x1c0) == TT_SPILL)
+        set_cwp((env->cwp - env->cansave - 2) & (NWINDOWS - 1));
+    else if ((intno & 0x1c0) == TT_FILL)
+        set_cwp((env->cwp + 1) & (NWINDOWS - 1));
     env->tbr &= ~0x7fffULL;
     env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
     if (env->tl < MAXTL - 1) {
-	env->tl++;
+        env->tl++;
     } else {
-	env->pstate |= PS_RED;
-	if (env->tl != MAXTL)
-	    env->tl++;
+        env->pstate |= PS_RED;
+        if (env->tl != MAXTL)
+            env->tl++;
     }
     env->pc = env->tbr;
     env->npc = env->pc + 4;
@@ -822,36 +1430,36 @@
 
 #ifdef DEBUG_PCALL
     if (loglevel & CPU_LOG_INT) {
-	static int count;
-	fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
+        static int count;
+        fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
                 count, intno,
                 env->pc,
                 env->npc, env->regwptr[6]);
-	cpu_dump_state(env, logfile, fprintf, 0);
+        cpu_dump_state(env, logfile, fprintf, 0);
 #if 0
-	{
-	    int i;
-	    uint8_t *ptr;
+        {
+            int i;
+            uint8_t *ptr;
 
-	    fprintf(logfile, "       code=");
-	    ptr = (uint8_t *)env->pc;
-	    for(i = 0; i < 16; i++) {
-		fprintf(logfile, " %02x", ldub(ptr + i));
-	    }
-	    fprintf(logfile, "\n");
-	}
+            fprintf(logfile, "       code=");
+            ptr = (uint8_t *)env->pc;
+            for(i = 0; i < 16; i++) {
+                fprintf(logfile, " %02x", ldub(ptr + i));
+            }
+            fprintf(logfile, "\n");
+        }
 #endif
-	count++;
+        count++;
     }
 #endif
-#if !defined(CONFIG_USER_ONLY) 
+#if !defined(CONFIG_USER_ONLY)
     if (env->psret == 0) {
         cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
-	return;
+        return;
     }
 #endif
     env->psret = 0;
-    cwp = (env->cwp - 1) & (NWINDOWS - 1); 
+    cwp = (env->cwp - 1) & (NWINDOWS - 1);
     set_cwp(cwp);
     env->regwptr[9] = env->pc;
     env->regwptr[10] = env->npc;
@@ -864,9 +1472,13 @@
 }
 #endif
 
-#if !defined(CONFIG_USER_ONLY) 
+#if !defined(CONFIG_USER_ONLY)
+
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+                                void *retaddr);
 
 #define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
 #define GETPC() (__builtin_return_address(0))
 
 #define SHIFT 0
@@ -881,6 +1493,14 @@
 #define SHIFT 3
 #include "softmmu_template.h"
 
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+                                void *retaddr)
+{
+#ifdef DEBUG_UNALIGNED
+    printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc);
+#endif
+    raise_exception(TT_UNALIGNED);
+}
 
 /* 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
@@ -916,3 +1536,84 @@
 }
 
 #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
+        if (is_exec)
+            raise_exception(TT_CODE_ACCESS);
+        else
+            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
+    if (is_exec)
+        raise_exception(TT_CODE_ACCESS);
+    else
+        raise_exception(TT_DATA_ACCESS);
+}
+#endif
+
+#ifdef TARGET_SPARC64
+void do_tick_set_count(void *opaque, uint64_t count)
+{
+#if !defined(CONFIG_USER_ONLY)
+    ptimer_set_count(opaque, -count);
+#endif
+}
+
+uint64_t do_tick_get_count(void *opaque)
+{
+#if !defined(CONFIG_USER_ONLY)
+    return -ptimer_get_count(opaque);
+#else
+    return 0;
+#endif
+}
+
+void do_tick_set_limit(void *opaque, uint64_t limit)
+{
+#if !defined(CONFIG_USER_ONLY)
+    ptimer_set_limit(opaque, -limit, 0);
+#endif
+}
+#endif
diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h
index f5dbd26..c0cf043 100644
--- a/target-sparc/op_mem.h
+++ b/target-sparc/op_mem.h
@@ -2,13 +2,13 @@
 #define SPARC_LD_OP(name, qp)                                                 \
 void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void)                           \
 {                                                                             \
-    T1 = (target_ulong)glue(qp, MEMSUFFIX)(T0);				\
+    T1 = (target_ulong)glue(qp, MEMSUFFIX)(T0);                         \
 }
 
-#define SPARC_LD_OP_S(name, qp)						\
-    void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void)			\
-    {									\
-	T1 = (target_long)glue(qp, MEMSUFFIX)(T0);			\
+#define SPARC_LD_OP_S(name, qp)                                         \
+    void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void)                 \
+    {                                                                   \
+        T1 = (target_long)glue(qp, MEMSUFFIX)(T0);                      \
     }
 
 #define SPARC_ST_OP(name, op)                                                 \
@@ -76,31 +76,9 @@
 }
 
 #ifdef TARGET_SPARC64
-/* XXX: Should be Atomically */
-/* XXX: There are no cas[x] instructions, only cas[x]a */
-void OPPROTO glue(op_cas, MEMSUFFIX)(void)
+void OPPROTO glue(op_lduw, MEMSUFFIX)(void)
 {
-    uint32_t tmp;
-
-    tmp = glue(ldl, MEMSUFFIX)(T0);
-    T2 &=  0xffffffffULL;
-    if (tmp == (T1 & 0xffffffffULL)) {
-	glue(stl, MEMSUFFIX)(T0, T2);
-    }
-    T2 = tmp;
-}
-
-void OPPROTO glue(op_casx, MEMSUFFIX)(void)
-{
-    uint64_t tmp;
-
-    // XXX
-    tmp = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32;
-    tmp |= glue(ldl, MEMSUFFIX)(T0);
-    if (tmp == T1) {
-	glue(stq, MEMSUFFIX)(T0, T2);
-    }
-    T2 = tmp;
+    T1 = (uint64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff);
 }
 
 void OPPROTO glue(op_ldsw, MEMSUFFIX)(void)
diff --git a/target-sparc/op_template.h b/target-sparc/op_template.h
index ecf65fd..f920615 100644
--- a/target-sparc/op_template.h
+++ b/target-sparc/op_template.h
@@ -1,7 +1,7 @@
 /*
  *  SPARC micro operations (templates for various register related
  *  operations)
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 455dd17..94503be 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -25,9 +25,7 @@
    Rest of V9 instructions, VIS instructions
    NPC/PC static optimisations (use JUMP_TB when possible)
    Optimize synthetic instructions
-   Optional alignment check
    128-bit float
-   Tagged add/sub
 */
 
 #include <stdarg.h>
@@ -47,8 +45,8 @@
                          according to jump_pc[T2] */
 
 typedef struct DisasContext {
-    target_ulong pc;	/* current Program Counter: integer or DYNAMIC_PC */
-    target_ulong npc;	/* next PC: integer or DYNAMIC_PC or JUMP_PC */
+    target_ulong pc;    /* current Program Counter: integer or DYNAMIC_PC */
+    target_ulong npc;   /* next PC: integer or DYNAMIC_PC or JUMP_PC */
     target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
     int is_br;
     int mem_idx;
@@ -56,6 +54,13 @@
     struct TranslationBlock *tb;
 } DisasContext;
 
+struct sparc_def_t {
+    const unsigned char *name;
+    target_ulong iu_version;
+    uint32_t fpu_version;
+    uint32_t mmu_version;
+};
+
 static uint16_t *gen_opc_ptr;
 static uint32_t *gen_opparam_ptr;
 extern FILE *logfile;
@@ -79,12 +84,12 @@
     GET_FIELD(X, 31 - (TO), 31 - (FROM))
 
 #define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
-#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), 32 - ((b) - (a) + 1))
+#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), ((b) - (a) + 1))
 
 #ifdef TARGET_SPARC64
 #define DFPREG(r) (((r & 1) << 6) | (r & 0x1e))
 #else
-#define DFPREG(r) (r)
+#define DFPREG(r) (r & 0x1e)
 #endif
 
 #ifdef USE_DIRECT_JUMP
@@ -103,7 +108,7 @@
 
 static void disas_sparc_insn(DisasContext * dc);
 
-static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
+static GenOpFunc * const gen_op_movl_TN_reg[2][32] = {
     {
      gen_op_movl_g0_T0,
      gen_op_movl_g1_T0,
@@ -174,7 +179,7 @@
      }
 };
 
-static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
+static GenOpFunc * const gen_op_movl_reg_TN[3][32] = {
     {
      gen_op_movl_T0_g0,
      gen_op_movl_T0_g1,
@@ -279,7 +284,7 @@
      }
 };
 
-static GenOpFunc1 *gen_op_movl_TN_im[3] = {
+static GenOpFunc1 * const gen_op_movl_TN_im[3] = {
     gen_op_movl_T0_im,
     gen_op_movl_T1_im,
     gen_op_movl_T2_im
@@ -294,7 +299,7 @@
 
 #ifdef TARGET_SPARC64
 #define GEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [64] = {                                     \
+static GenOpFunc * const NAME ## _table [64] = {                              \
 NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,                                   \
 NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,                                   \
 NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11,                                 \
@@ -314,7 +319,7 @@
 }
 #else
 #define GEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [32] = {                                     \
+static GenOpFunc *const NAME ## _table [32] = {                               \
 NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3,                                   \
 NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7,                                   \
 NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11,                                 \
@@ -341,110 +346,34 @@
 GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf);
 GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf);
 
+#ifdef ALIGN_7_BUGS_FIXED
+#else
+#ifndef CONFIG_USER_ONLY
+#define gen_op_check_align_T0_7()
+#endif
+#endif
+
+/* moves */
+#ifdef CONFIG_USER_ONLY
+#define supervisor(dc) 0
 #ifdef TARGET_SPARC64
-// 'a' versions allowed to user depending on asi
-#if defined(CONFIG_USER_ONLY)
-#define supervisor(dc) 0
+#define hypervisor(dc) 0
+#endif
 #define gen_op_ldst(name)        gen_op_##name##_raw()
-#define OP_LD_TABLE(width)						\
-    static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
-    {									\
-	int asi, offset;						\
-									\
-	if (IS_IMM) {							\
-	    offset = GET_FIELD(insn, 25, 31);				\
-	    if (is_ld)							\
-		gen_op_ld_asi_reg(offset, size, sign);			\
-	    else							\
-		gen_op_st_asi_reg(offset, size, sign);			\
-	    return;							\
-	}								\
-	asi = GET_FIELD(insn, 19, 26);					\
-	switch (asi) {							\
-	case 0x80: /* Primary address space */				\
-	    gen_op_##width##_raw();					\
-	    break;							\
-	case 0x82: /* Primary address space, non-faulting load */       \
-	    gen_op_##width##_raw();					\
-	    break;							\
-	default:							\
-            break;							\
-	}								\
-    }
-
 #else
-#define gen_op_ldst(name)        (*gen_op_##name[dc->mem_idx])()
-#define OP_LD_TABLE(width)						\
-    static GenOpFunc *gen_op_##width[] = {				\
-	&gen_op_##width##_user,						\
-	&gen_op_##width##_kernel,					\
-    };									\
-									\
-    static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
-    {									\
-	int asi, offset;						\
-									\
-	if (IS_IMM) {							\
-	    offset = GET_FIELD(insn, 25, 31);				\
-	    if (is_ld)							\
-		gen_op_ld_asi_reg(offset, size, sign);			\
-	    else							\
-		gen_op_st_asi_reg(offset, size, sign);			\
-	    return;							\
-	}								\
-	asi = GET_FIELD(insn, 19, 26);					\
-	if (is_ld)							\
-	    gen_op_ld_asi(asi, size, sign);				\
-	else								\
-	    gen_op_st_asi(asi, size, sign);				\
-    }
-
 #define supervisor(dc) (dc->mem_idx == 1)
+#ifdef TARGET_SPARC64
+#define hypervisor(dc) (dc->mem_idx == 2)
 #endif
-#else
-#if defined(CONFIG_USER_ONLY)
-#define gen_op_ldst(name)        gen_op_##name##_raw()
-#define OP_LD_TABLE(width)
-#define supervisor(dc) 0
-#else
 #define gen_op_ldst(name)        (*gen_op_##name[dc->mem_idx])()
-#define OP_LD_TABLE(width)						      \
-static GenOpFunc *gen_op_##width[] = {                                        \
-    &gen_op_##width##_user,                                                   \
-    &gen_op_##width##_kernel,                                                 \
-};                                                                            \
-                                                                              \
-static void gen_op_##width##a(int insn, int is_ld, int size, int sign)        \
-{                                                                             \
-    int asi;                                                                  \
-                                                                              \
-    asi = GET_FIELD(insn, 19, 26);                                            \
-    switch (asi) {                                                            \
-	case 10: /* User data access */                                       \
-	    gen_op_##width##_user();                                          \
-	    break;                                                            \
-	case 11: /* Supervisor data access */                                 \
-	    gen_op_##width##_kernel();                                        \
-	    break;                                                            \
-        case 0x20 ... 0x2f: /* MMU passthrough */			      \
-	    if (is_ld)                                                        \
-		gen_op_ld_asi(asi, size, sign);				      \
-	    else                                                              \
-		gen_op_st_asi(asi, size, sign);				      \
-	    break;                                                            \
-	default:                                                              \
-	    if (is_ld)                                                        \
-		gen_op_ld_asi(asi, size, sign);			              \
-	    else                                                              \
-		gen_op_st_asi(asi, size, sign);				      \
-            break;                                                            \
-    }                                                                         \
-}
-
-#define supervisor(dc) (dc->mem_idx == 1)
-#endif
+#define OP_LD_TABLE(width)                                              \
+    static GenOpFunc * const gen_op_##width[] = {                       \
+        &gen_op_##width##_user,                                         \
+        &gen_op_##width##_kernel,                                       \
+    };
 #endif
 
+#ifndef CONFIG_USER_ONLY
 OP_LD_TABLE(ld);
 OP_LD_TABLE(st);
 OP_LD_TABLE(ldub);
@@ -463,11 +392,196 @@
 OP_LD_TABLE(lddf);
 
 #ifdef TARGET_SPARC64
+OP_LD_TABLE(lduw);
 OP_LD_TABLE(ldsw);
 OP_LD_TABLE(ldx);
 OP_LD_TABLE(stx);
-OP_LD_TABLE(cas);
-OP_LD_TABLE(casx);
+#endif
+#endif
+
+/* asi moves */
+#ifdef TARGET_SPARC64
+static inline void gen_ld_asi(int insn, int size, int sign)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ld_asi_reg(offset, size, sign);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ld_asi(asi, size, sign);
+    }
+}
+
+static inline void gen_st_asi(int insn, int size)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_st_asi_reg(offset, size);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_st_asi(asi, size);
+    }
+}
+
+static inline void gen_ldf_asi(int insn, int size)
+{
+    int asi, offset, rd;
+
+    rd = GET_FIELD(insn, 2, 6);
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ldf_asi_reg(offset, size, rd);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ldf_asi(asi, size, rd);
+    }
+}
+
+static inline void gen_stf_asi(int insn, int size)
+{
+    int asi, offset, rd;
+
+    rd = GET_FIELD(insn, 2, 6);
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_stf_asi_reg(offset, size, rd);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_stf_asi(asi, size, rd);
+    }
+}
+
+static inline void gen_swap_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_swap_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_swap_asi(asi);
+    }
+}
+
+static inline void gen_ldstub_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ldstub_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ldstub_asi(asi);
+    }
+}
+
+static inline void gen_ldda_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_ldda_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_ldda_asi(asi);
+    }
+}
+
+static inline void gen_stda_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_stda_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_stda_asi(asi);
+    }
+}
+
+static inline void gen_cas_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_cas_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_cas_asi(asi);
+    }
+}
+
+static inline void gen_casx_asi(int insn)
+{
+    int asi, offset;
+
+    if (IS_IMM) {
+        offset = GET_FIELD(insn, 25, 31);
+        gen_op_casx_asi_reg(offset);
+    } else {
+        asi = GET_FIELD(insn, 19, 26);
+        gen_op_casx_asi(asi);
+    }
+}
+
+#elif !defined(CONFIG_USER_ONLY)
+
+static inline void gen_ld_asi(int insn, int size, int sign)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ld_asi(asi, size, sign);
+}
+
+static inline void gen_st_asi(int insn, int size)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_st_asi(asi, size);
+}
+
+static inline void gen_ldstub_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ldstub_asi(asi);
+}
+
+static inline void gen_swap_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_swap_asi(asi);
+}
+
+static inline void gen_ldda_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_ld_asi(asi, 8, 0);
+}
+
+static inline void gen_stda_asi(int insn)
+{
+    int asi;
+
+    asi = GET_FIELD(insn, 19, 26);
+    gen_op_st_asi(asi, 8);
+}
 #endif
 
 static inline void gen_movl_imm_TN(int reg, uint32_t imm)
@@ -503,9 +617,9 @@
 static inline void gen_movl_reg_TN(int reg, int t)
 {
     if (reg)
-	gen_op_movl_reg_TN[t][reg] ();
+        gen_op_movl_reg_TN[t][reg] ();
     else
-	gen_movl_imm_TN(t, 0);
+        gen_movl_imm_TN(t, 0);
 }
 
 static inline void gen_movl_reg_T0(int reg)
@@ -526,7 +640,7 @@
 static inline void gen_movl_TN_reg(int reg, int t)
 {
     if (reg)
-	gen_op_movl_TN_reg[t][reg] ();
+        gen_op_movl_TN_reg[t][reg] ();
 }
 
 static inline void gen_movl_T0_reg(int reg)
@@ -565,7 +679,7 @@
 #endif
 }
 
-static inline void gen_goto_tb(DisasContext *s, int tb_num, 
+static inline void gen_goto_tb(DisasContext *s, int tb_num,
                                target_ulong pc, target_ulong npc)
 {
     TranslationBlock *tb;
@@ -591,7 +705,8 @@
     }
 }
 
-static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
+static inline void gen_branch2(DisasContext *dc, target_ulong pc1,
+                               target_ulong pc2)
 {
     int l1;
 
@@ -605,7 +720,8 @@
     gen_goto_tb(dc, 1, pc2, pc2 + 4);
 }
 
-static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
+static inline void gen_branch_a(DisasContext *dc, target_ulong pc1,
+                                target_ulong pc2)
 {
     int l1;
 
@@ -619,12 +735,13 @@
     gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8);
 }
 
-static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc)
+static inline void gen_branch(DisasContext *dc, target_ulong pc,
+                              target_ulong npc)
 {
     gen_goto_tb(dc, 0, pc, npc);
 }
 
-static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2)
+static inline void gen_generic_branch(target_ulong npc1, target_ulong npc2)
 {
     int l1, l2;
 
@@ -644,7 +761,7 @@
 static inline void flush_T2(DisasContext * dc)
 {
     if (dc->npc == JUMP_PC) {
-        gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
+        gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
         dc->npc = DYNAMIC_PC;
     }
 }
@@ -652,7 +769,7 @@
 static inline void save_npc(DisasContext * dc)
 {
     if (dc->npc == JUMP_PC) {
-        gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
+        gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
         dc->npc = DYNAMIC_PC;
     } else if (dc->npc != DYNAMIC_PC) {
         gen_movl_npc_im(dc->npc);
@@ -668,7 +785,7 @@
 static inline void gen_mov_pc_npc(DisasContext * dc)
 {
     if (dc->npc == JUMP_PC) {
-        gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
+        gen_generic_branch(dc->jump_pc[0], dc->jump_pc[1]);
         gen_op_mov_pc_npc();
         dc->pc = DYNAMIC_PC;
     } else if (dc->npc == DYNAMIC_PC) {
@@ -681,118 +798,118 @@
 
 static GenOpFunc * const gen_cond[2][16] = {
     {
-	gen_op_eval_ba,
-	gen_op_eval_be,
-	gen_op_eval_ble,
-	gen_op_eval_bl,
-	gen_op_eval_bleu,
-	gen_op_eval_bcs,
-	gen_op_eval_bneg,
-	gen_op_eval_bvs,
-	gen_op_eval_bn,
-	gen_op_eval_bne,
-	gen_op_eval_bg,
-	gen_op_eval_bge,
-	gen_op_eval_bgu,
-	gen_op_eval_bcc,
-	gen_op_eval_bpos,
-	gen_op_eval_bvc,
+        gen_op_eval_bn,
+        gen_op_eval_be,
+        gen_op_eval_ble,
+        gen_op_eval_bl,
+        gen_op_eval_bleu,
+        gen_op_eval_bcs,
+        gen_op_eval_bneg,
+        gen_op_eval_bvs,
+        gen_op_eval_ba,
+        gen_op_eval_bne,
+        gen_op_eval_bg,
+        gen_op_eval_bge,
+        gen_op_eval_bgu,
+        gen_op_eval_bcc,
+        gen_op_eval_bpos,
+        gen_op_eval_bvc,
     },
     {
 #ifdef TARGET_SPARC64
-	gen_op_eval_ba,
-	gen_op_eval_xbe,
-	gen_op_eval_xble,
-	gen_op_eval_xbl,
-	gen_op_eval_xbleu,
-	gen_op_eval_xbcs,
-	gen_op_eval_xbneg,
-	gen_op_eval_xbvs,
-	gen_op_eval_bn,
-	gen_op_eval_xbne,
-	gen_op_eval_xbg,
-	gen_op_eval_xbge,
-	gen_op_eval_xbgu,
-	gen_op_eval_xbcc,
-	gen_op_eval_xbpos,
-	gen_op_eval_xbvc,
+        gen_op_eval_bn,
+        gen_op_eval_xbe,
+        gen_op_eval_xble,
+        gen_op_eval_xbl,
+        gen_op_eval_xbleu,
+        gen_op_eval_xbcs,
+        gen_op_eval_xbneg,
+        gen_op_eval_xbvs,
+        gen_op_eval_ba,
+        gen_op_eval_xbne,
+        gen_op_eval_xbg,
+        gen_op_eval_xbge,
+        gen_op_eval_xbgu,
+        gen_op_eval_xbcc,
+        gen_op_eval_xbpos,
+        gen_op_eval_xbvc,
 #endif
     },
 };
 
 static GenOpFunc * const gen_fcond[4][16] = {
     {
-	gen_op_eval_ba,
-	gen_op_eval_fbne,
-	gen_op_eval_fblg,
-	gen_op_eval_fbul,
-	gen_op_eval_fbl,
-	gen_op_eval_fbug,
-	gen_op_eval_fbg,
-	gen_op_eval_fbu,
-	gen_op_eval_bn,
-	gen_op_eval_fbe,
-	gen_op_eval_fbue,
-	gen_op_eval_fbge,
-	gen_op_eval_fbuge,
-	gen_op_eval_fble,
-	gen_op_eval_fbule,
-	gen_op_eval_fbo,
+        gen_op_eval_bn,
+        gen_op_eval_fbne,
+        gen_op_eval_fblg,
+        gen_op_eval_fbul,
+        gen_op_eval_fbl,
+        gen_op_eval_fbug,
+        gen_op_eval_fbg,
+        gen_op_eval_fbu,
+        gen_op_eval_ba,
+        gen_op_eval_fbe,
+        gen_op_eval_fbue,
+        gen_op_eval_fbge,
+        gen_op_eval_fbuge,
+        gen_op_eval_fble,
+        gen_op_eval_fbule,
+        gen_op_eval_fbo,
     },
 #ifdef TARGET_SPARC64
     {
-	gen_op_eval_ba,
-	gen_op_eval_fbne_fcc1,
-	gen_op_eval_fblg_fcc1,
-	gen_op_eval_fbul_fcc1,
-	gen_op_eval_fbl_fcc1,
-	gen_op_eval_fbug_fcc1,
-	gen_op_eval_fbg_fcc1,
-	gen_op_eval_fbu_fcc1,
-	gen_op_eval_bn,
-	gen_op_eval_fbe_fcc1,
-	gen_op_eval_fbue_fcc1,
-	gen_op_eval_fbge_fcc1,
-	gen_op_eval_fbuge_fcc1,
-	gen_op_eval_fble_fcc1,
-	gen_op_eval_fbule_fcc1,
-	gen_op_eval_fbo_fcc1,
+        gen_op_eval_bn,
+        gen_op_eval_fbne_fcc1,
+        gen_op_eval_fblg_fcc1,
+        gen_op_eval_fbul_fcc1,
+        gen_op_eval_fbl_fcc1,
+        gen_op_eval_fbug_fcc1,
+        gen_op_eval_fbg_fcc1,
+        gen_op_eval_fbu_fcc1,
+        gen_op_eval_ba,
+        gen_op_eval_fbe_fcc1,
+        gen_op_eval_fbue_fcc1,
+        gen_op_eval_fbge_fcc1,
+        gen_op_eval_fbuge_fcc1,
+        gen_op_eval_fble_fcc1,
+        gen_op_eval_fbule_fcc1,
+        gen_op_eval_fbo_fcc1,
     },
     {
-	gen_op_eval_ba,
-	gen_op_eval_fbne_fcc2,
-	gen_op_eval_fblg_fcc2,
-	gen_op_eval_fbul_fcc2,
-	gen_op_eval_fbl_fcc2,
-	gen_op_eval_fbug_fcc2,
-	gen_op_eval_fbg_fcc2,
-	gen_op_eval_fbu_fcc2,
-	gen_op_eval_bn,
-	gen_op_eval_fbe_fcc2,
-	gen_op_eval_fbue_fcc2,
-	gen_op_eval_fbge_fcc2,
-	gen_op_eval_fbuge_fcc2,
-	gen_op_eval_fble_fcc2,
-	gen_op_eval_fbule_fcc2,
-	gen_op_eval_fbo_fcc2,
+        gen_op_eval_bn,
+        gen_op_eval_fbne_fcc2,
+        gen_op_eval_fblg_fcc2,
+        gen_op_eval_fbul_fcc2,
+        gen_op_eval_fbl_fcc2,
+        gen_op_eval_fbug_fcc2,
+        gen_op_eval_fbg_fcc2,
+        gen_op_eval_fbu_fcc2,
+        gen_op_eval_ba,
+        gen_op_eval_fbe_fcc2,
+        gen_op_eval_fbue_fcc2,
+        gen_op_eval_fbge_fcc2,
+        gen_op_eval_fbuge_fcc2,
+        gen_op_eval_fble_fcc2,
+        gen_op_eval_fbule_fcc2,
+        gen_op_eval_fbo_fcc2,
     },
     {
-	gen_op_eval_ba,
-	gen_op_eval_fbne_fcc3,
-	gen_op_eval_fblg_fcc3,
-	gen_op_eval_fbul_fcc3,
-	gen_op_eval_fbl_fcc3,
-	gen_op_eval_fbug_fcc3,
-	gen_op_eval_fbg_fcc3,
-	gen_op_eval_fbu_fcc3,
-	gen_op_eval_bn,
-	gen_op_eval_fbe_fcc3,
-	gen_op_eval_fbue_fcc3,
-	gen_op_eval_fbge_fcc3,
-	gen_op_eval_fbuge_fcc3,
-	gen_op_eval_fble_fcc3,
-	gen_op_eval_fbule_fcc3,
-	gen_op_eval_fbo_fcc3,
+        gen_op_eval_bn,
+        gen_op_eval_fbne_fcc3,
+        gen_op_eval_fblg_fcc3,
+        gen_op_eval_fbul_fcc3,
+        gen_op_eval_fbl_fcc3,
+        gen_op_eval_fbug_fcc3,
+        gen_op_eval_fbg_fcc3,
+        gen_op_eval_fbu_fcc3,
+        gen_op_eval_ba,
+        gen_op_eval_fbe_fcc3,
+        gen_op_eval_fbue_fcc3,
+        gen_op_eval_fbge_fcc3,
+        gen_op_eval_fbuge_fcc3,
+        gen_op_eval_fble_fcc3,
+        gen_op_eval_fbule_fcc3,
+        gen_op_eval_fbo_fcc3,
     },
 #else
     {}, {}, {},
@@ -802,27 +919,27 @@
 #ifdef TARGET_SPARC64
 static void gen_cond_reg(int cond)
 {
-	switch (cond) {
-	case 0x1:
-	    gen_op_eval_brz();
-	    break;
-	case 0x2:
-	    gen_op_eval_brlez();
-	    break;
-	case 0x3:
-	    gen_op_eval_brlz();
-	    break;
-	case 0x5:
-	    gen_op_eval_brnz();
-	    break;
-	case 0x6:
-	    gen_op_eval_brgz();
-	    break;
+        switch (cond) {
+        case 0x1:
+            gen_op_eval_brz();
+            break;
+        case 0x2:
+            gen_op_eval_brlez();
+            break;
+        case 0x3:
+            gen_op_eval_brlz();
+            break;
+        case 0x5:
+            gen_op_eval_brnz();
+            break;
+        case 0x6:
+            gen_op_eval_brgz();
+            break;
         default:
-	case 0x7:
-	    gen_op_eval_brgez();
-	    break;
-	}
+        case 0x7:
+            gen_op_eval_brgez();
+            break;
+        }
 }
 #endif
 
@@ -831,37 +948,37 @@
 {
     unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
     target_ulong target = dc->pc + offset;
-	
+
     if (cond == 0x0) {
-	/* unconditional not taken */
-	if (a) {
-	    dc->pc = dc->npc + 4; 
-	    dc->npc = dc->pc + 4;
-	} else {
-	    dc->pc = dc->npc;
-	    dc->npc = dc->pc + 4;
-	}
+        /* unconditional not taken */
+        if (a) {
+            dc->pc = dc->npc + 4;
+            dc->npc = dc->pc + 4;
+        } else {
+            dc->pc = dc->npc;
+            dc->npc = dc->pc + 4;
+        }
     } else if (cond == 0x8) {
-	/* unconditional taken */
-	if (a) {
-	    dc->pc = target;
-	    dc->npc = dc->pc + 4;
-	} else {
-	    dc->pc = dc->npc;
-	    dc->npc = target;
-	}
+        /* unconditional taken */
+        if (a) {
+            dc->pc = target;
+            dc->npc = dc->pc + 4;
+        } else {
+            dc->pc = dc->npc;
+            dc->npc = target;
+        }
     } else {
         flush_T2(dc);
         gen_cond[cc][cond]();
-	if (a) {
-	    gen_branch_a(dc, (long)dc->tb, target, dc->npc);
+        if (a) {
+            gen_branch_a(dc, target, dc->npc);
             dc->is_br = 1;
-	} else {
+        } else {
             dc->pc = dc->npc;
             dc->jump_pc[0] = target;
             dc->jump_pc[1] = dc->npc + 4;
             dc->npc = JUMP_PC;
-	}
+        }
     }
 }
 
@@ -872,35 +989,35 @@
     target_ulong target = dc->pc + offset;
 
     if (cond == 0x0) {
-	/* unconditional not taken */
-	if (a) {
-	    dc->pc = dc->npc + 4;
-	    dc->npc = dc->pc + 4;
-	} else {
-	    dc->pc = dc->npc;
-	    dc->npc = dc->pc + 4;
-	}
+        /* unconditional not taken */
+        if (a) {
+            dc->pc = dc->npc + 4;
+            dc->npc = dc->pc + 4;
+        } else {
+            dc->pc = dc->npc;
+            dc->npc = dc->pc + 4;
+        }
     } else if (cond == 0x8) {
-	/* unconditional taken */
-	if (a) {
-	    dc->pc = target;
-	    dc->npc = dc->pc + 4;
-	} else {
-	    dc->pc = dc->npc;
-	    dc->npc = target;
-	}
+        /* unconditional taken */
+        if (a) {
+            dc->pc = target;
+            dc->npc = dc->pc + 4;
+        } else {
+            dc->pc = dc->npc;
+            dc->npc = target;
+        }
     } else {
         flush_T2(dc);
         gen_fcond[cc][cond]();
-	if (a) {
-	    gen_branch_a(dc, (long)dc->tb, target, dc->npc);
+        if (a) {
+            gen_branch_a(dc, target, dc->npc);
             dc->is_br = 1;
-	} else {
+        } else {
             dc->pc = dc->npc;
             dc->jump_pc[0] = target;
             dc->jump_pc[1] = dc->npc + 4;
             dc->npc = JUMP_PC;
-	}
+        }
     }
 }
 
@@ -914,13 +1031,13 @@
     flush_T2(dc);
     gen_cond_reg(cond);
     if (a) {
-	gen_branch_a(dc, (long)dc->tb, target, dc->npc);
-	dc->is_br = 1;
+        gen_branch_a(dc, target, dc->npc);
+        dc->is_br = 1;
     } else {
-	dc->pc = dc->npc;
-	dc->jump_pc[0] = target;
-	dc->jump_pc[1] = dc->npc + 4;
-	dc->npc = JUMP_PC;
+        dc->pc = dc->npc;
+        dc->jump_pc[0] = target;
+        dc->jump_pc[1] = dc->npc + 4;
+        dc->npc = JUMP_PC;
     }
 }
 
@@ -937,6 +1054,21 @@
     gen_op_fcmpd_fcc2,
     gen_op_fcmpd_fcc3,
 };
+
+static GenOpFunc * const gen_fcmpes[4] = {
+    gen_op_fcmpes,
+    gen_op_fcmpes_fcc1,
+    gen_op_fcmpes_fcc2,
+    gen_op_fcmpes_fcc3,
+};
+
+static GenOpFunc * const gen_fcmped[4] = {
+    gen_op_fcmped,
+    gen_op_fcmped_fcc1,
+    gen_op_fcmped_fcc2,
+    gen_op_fcmped_fcc3,
+};
+
 #endif
 
 static int gen_trap_ifnofpu(DisasContext * dc)
@@ -962,134 +1094,139 @@
 
     rd = GET_FIELD(insn, 2, 6);
     switch (opc) {
-    case 0:			/* branches/sethi */
-	{
-	    unsigned int xop = GET_FIELD(insn, 7, 9);
-	    int32_t target;
-	    switch (xop) {
+    case 0:                     /* branches/sethi */
+        {
+            unsigned int xop = GET_FIELD(insn, 7, 9);
+            int32_t target;
+            switch (xop) {
 #ifdef TARGET_SPARC64
-	    case 0x1:		/* V9 BPcc */
-		{
-		    int cc;
+            case 0x1:           /* V9 BPcc */
+                {
+                    int cc;
 
-		    target = GET_FIELD_SP(insn, 0, 18);
-		    target = sign_extend(target, 18);
-		    target <<= 2;
-		    cc = GET_FIELD_SP(insn, 20, 21);
-		    if (cc == 0)
-			do_branch(dc, target, insn, 0);
-		    else if (cc == 2)
-			do_branch(dc, target, insn, 1);
-		    else
-			goto illegal_insn;
-		    goto jmp_insn;
-		}
-	    case 0x3:		/* V9 BPr */
-		{
-		    target = GET_FIELD_SP(insn, 0, 13) | 
+                    target = GET_FIELD_SP(insn, 0, 18);
+                    target = sign_extend(target, 18);
+                    target <<= 2;
+                    cc = GET_FIELD_SP(insn, 20, 21);
+                    if (cc == 0)
+                        do_branch(dc, target, insn, 0);
+                    else if (cc == 2)
+                        do_branch(dc, target, insn, 1);
+                    else
+                        goto illegal_insn;
+                    goto jmp_insn;
+                }
+            case 0x3:           /* V9 BPr */
+                {
+                    target = GET_FIELD_SP(insn, 0, 13) |
                         (GET_FIELD_SP(insn, 20, 21) << 14);
-		    target = sign_extend(target, 16);
-		    target <<= 2;
-		    rs1 = GET_FIELD(insn, 13, 17);
-		    gen_movl_reg_T0(rs1);
-		    do_branch_reg(dc, target, insn);
-		    goto jmp_insn;
-		}
-	    case 0x5:		/* V9 FBPcc */
-		{
-		    int cc = GET_FIELD_SP(insn, 20, 21);
+                    target = sign_extend(target, 16);
+                    target <<= 2;
+                    rs1 = GET_FIELD(insn, 13, 17);
+                    gen_movl_reg_T0(rs1);
+                    do_branch_reg(dc, target, insn);
+                    goto jmp_insn;
+                }
+            case 0x5:           /* V9 FBPcc */
+                {
+                    int cc = GET_FIELD_SP(insn, 20, 21);
                     if (gen_trap_ifnofpu(dc))
                         goto jmp_insn;
-		    target = GET_FIELD_SP(insn, 0, 18);
-		    target = sign_extend(target, 19);
-		    target <<= 2;
-		    do_fbranch(dc, target, insn, cc);
-		    goto jmp_insn;
-		}
+                    target = GET_FIELD_SP(insn, 0, 18);
+                    target = sign_extend(target, 19);
+                    target <<= 2;
+                    do_fbranch(dc, target, insn, cc);
+                    goto jmp_insn;
+                }
+#else
+            case 0x7:           /* CBN+x */
+                {
+                    goto ncp_insn;
+                }
 #endif
-	    case 0x2:		/* BN+x */
-		{
-		    target = GET_FIELD(insn, 10, 31);
-		    target = sign_extend(target, 22);
-		    target <<= 2;
-		    do_branch(dc, target, insn, 0);
-		    goto jmp_insn;
-		}
-	    case 0x6:		/* FBN+x */
-		{
+            case 0x2:           /* BN+x */
+                {
+                    target = GET_FIELD(insn, 10, 31);
+                    target = sign_extend(target, 22);
+                    target <<= 2;
+                    do_branch(dc, target, insn, 0);
+                    goto jmp_insn;
+                }
+            case 0x6:           /* FBN+x */
+                {
                     if (gen_trap_ifnofpu(dc))
                         goto jmp_insn;
-		    target = GET_FIELD(insn, 10, 31);
-		    target = sign_extend(target, 22);
-		    target <<= 2;
-		    do_fbranch(dc, target, insn, 0);
-		    goto jmp_insn;
-		}
-	    case 0x4:		/* SETHI */
+                    target = GET_FIELD(insn, 10, 31);
+                    target = sign_extend(target, 22);
+                    target <<= 2;
+                    do_fbranch(dc, target, insn, 0);
+                    goto jmp_insn;
+                }
+            case 0x4:           /* SETHI */
 #define OPTIM
 #if defined(OPTIM)
-		if (rd) { // nop
+                if (rd) { // nop
 #endif
-		    uint32_t value = GET_FIELD(insn, 10, 31);
-		    gen_movl_imm_T0(value << 10);
-		    gen_movl_T0_reg(rd);
+                    uint32_t value = GET_FIELD(insn, 10, 31);
+                    gen_movl_imm_T0(value << 10);
+                    gen_movl_T0_reg(rd);
 #if defined(OPTIM)
-		}
+                }
 #endif
-		break;
-	    case 0x0:		/* UNIMPL */
-	    default:
+                break;
+            case 0x0:           /* UNIMPL */
+            default:
                 goto illegal_insn;
-	    }
-	    break;
-	}
-	break;
+            }
+            break;
+        }
+        break;
     case 1:
-	/*CALL*/ {
-	    target_long target = GET_FIELDs(insn, 2, 31) << 2;
+        /*CALL*/ {
+            target_long target = GET_FIELDs(insn, 2, 31) << 2;
 
 #ifdef TARGET_SPARC64
-	    if (dc->pc == (uint32_t)dc->pc) {
-		gen_op_movl_T0_im(dc->pc);
-	    } else {
-		gen_op_movq_T0_im64(dc->pc >> 32, dc->pc);
-	    }
+            if (dc->pc == (uint32_t)dc->pc) {
+                gen_op_movl_T0_im(dc->pc);
+            } else {
+                gen_op_movq_T0_im64(dc->pc >> 32, dc->pc);
+            }
 #else
-	    gen_op_movl_T0_im(dc->pc);
+            gen_op_movl_T0_im(dc->pc);
 #endif
-	    gen_movl_T0_reg(15);
-	    target += dc->pc;
+            gen_movl_T0_reg(15);
+            target += dc->pc;
             gen_mov_pc_npc(dc);
-	    dc->npc = target;
-	}
-	goto jmp_insn;
-    case 2:			/* FPU & Logical Operations */
-	{
-	    unsigned int xop = GET_FIELD(insn, 7, 12);
-	    if (xop == 0x3a) {	/* generate trap */
+            dc->npc = target;
+        }
+        goto jmp_insn;
+    case 2:                     /* FPU & Logical Operations */
+        {
+            unsigned int xop = GET_FIELD(insn, 7, 12);
+            if (xop == 0x3a) {  /* generate trap */
                 int cond;
 
                 rs1 = GET_FIELD(insn, 13, 17);
                 gen_movl_reg_T0(rs1);
-		if (IS_IMM) {
-		    rs2 = GET_FIELD(insn, 25, 31);
+                if (IS_IMM) {
+                    rs2 = GET_FIELD(insn, 25, 31);
 #if defined(OPTIM)
-		    if (rs2 != 0) {
+                    if (rs2 != 0) {
 #endif
-			gen_movl_simm_T1(rs2);
-			gen_op_add_T1_T0();
+                        gen_movl_simm_T1(rs2);
+                        gen_op_add_T1_T0();
 #if defined(OPTIM)
-		    }
+                    }
 #endif
                 } else {
                     rs2 = GET_FIELD(insn, 27, 31);
 #if defined(OPTIM)
-		    if (rs2 != 0) {
+                    if (rs2 != 0) {
 #endif
-			gen_movl_reg_T1(rs2);
-			gen_op_add_T1_T0();
+                        gen_movl_reg_T1(rs2);
+                        gen_op_add_T1_T0();
 #if defined(OPTIM)
-		    }
+                    }
 #endif
                 }
                 cond = GET_FIELD(insn, 3, 6);
@@ -1098,20 +1235,20 @@
                     gen_op_trap_T0();
                 } else if (cond != 0) {
 #ifdef TARGET_SPARC64
-		    /* V9 icc/xcc */
-		    int cc = GET_FIELD_SP(insn, 11, 12);
-		    flush_T2(dc);
+                    /* V9 icc/xcc */
+                    int cc = GET_FIELD_SP(insn, 11, 12);
+                    flush_T2(dc);
                     save_state(dc);
-		    if (cc == 0)
-			gen_cond[0][cond]();
-		    else if (cc == 2)
-			gen_cond[1][cond]();
-		    else
-			goto illegal_insn;
+                    if (cc == 0)
+                        gen_cond[0][cond]();
+                    else if (cc == 2)
+                        gen_cond[1][cond]();
+                    else
+                        goto illegal_insn;
 #else
-		    flush_T2(dc);
+                    flush_T2(dc);
                     save_state(dc);
-		    gen_cond[0][cond]();
+                    gen_cond[0][cond]();
 #endif
                     gen_op_trapcc_T0();
                 }
@@ -1124,619 +1261,668 @@
                 rs1 = GET_FIELD(insn, 13, 17);
                 switch(rs1) {
                 case 0: /* rdy */
-		    gen_op_movtl_T0_env(offsetof(CPUSPARCState, y));
+#ifndef TARGET_SPARC64
+                case 0x01 ... 0x0e: /* undefined in the SPARCv8
+                                       manual, rdy on the microSPARC
+                                       II */
+                case 0x0f:          /* stbar in the SPARCv8 manual,
+                                       rdy on the microSPARC II */
+                case 0x10 ... 0x1f: /* implementation-dependent in the
+                                       SPARCv8 manual, rdy on the
+                                       microSPARC II */
+#endif
+                    gen_op_movtl_T0_env(offsetof(CPUSPARCState, y));
                     gen_movl_T0_reg(rd);
                     break;
-                case 15: /* stbar / V9 membar */
-		    break; /* no effect? */
 #ifdef TARGET_SPARC64
-		case 0x2: /* V9 rdccr */
+                case 0x2: /* V9 rdccr */
                     gen_op_rdccr();
                     gen_movl_T0_reg(rd);
                     break;
-		case 0x3: /* V9 rdasi */
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, asi));
+                case 0x3: /* V9 rdasi */
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, asi));
                     gen_movl_T0_reg(rd);
                     break;
-		case 0x4: /* V9 rdtick */
+                case 0x4: /* V9 rdtick */
                     gen_op_rdtick();
                     gen_movl_T0_reg(rd);
                     break;
-		case 0x5: /* V9 rdpc */
-		    if (dc->pc == (uint32_t)dc->pc) {
-			gen_op_movl_T0_im(dc->pc);
-		    } else {
-			gen_op_movq_T0_im64(dc->pc >> 32, dc->pc);
-		    }
-		    gen_movl_T0_reg(rd);
-		    break;
-		case 0x6: /* V9 rdfprs */
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs));
+                case 0x5: /* V9 rdpc */
+                    if (dc->pc == (uint32_t)dc->pc) {
+                        gen_op_movl_T0_im(dc->pc);
+                    } else {
+                        gen_op_movq_T0_im64(dc->pc >> 32, dc->pc);
+                    }
                     gen_movl_T0_reg(rd);
                     break;
-		case 0x13: /* Graphics Status */
+                case 0x6: /* V9 rdfprs */
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs));
+                    gen_movl_T0_reg(rd);
+                    break;
+                case 0xf: /* V9 membar */
+                    break; /* no effect */
+                case 0x13: /* Graphics Status */
                     if (gen_trap_ifnofpu(dc))
                         goto jmp_insn;
-		    gen_op_movtl_T0_env(offsetof(CPUSPARCState, gsr));
+                    gen_op_movtl_T0_env(offsetof(CPUSPARCState, gsr));
                     gen_movl_T0_reg(rd);
                     break;
-		case 0x17: /* Tick compare */
-		    gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr));
+                case 0x17: /* Tick compare */
+                    gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr));
                     gen_movl_T0_reg(rd);
                     break;
-		case 0x18: /* System tick */
-                    gen_op_rdtick(); // XXX
+                case 0x18: /* System tick */
+                    gen_op_rdstick();
                     gen_movl_T0_reg(rd);
                     break;
-		case 0x19: /* System tick compare */
-		    gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr));
+                case 0x19: /* System tick compare */
+                    gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr));
                     gen_movl_T0_reg(rd);
                     break;
-		case 0x10: /* Performance Control */
-		case 0x11: /* Performance Instrumentation Counter */
-		case 0x12: /* Dispatch Control */
-		case 0x14: /* Softint set, WO */
-		case 0x15: /* Softint clear, WO */
-		case 0x16: /* Softint write */
+                case 0x10: /* Performance Control */
+                case 0x11: /* Performance Instrumentation Counter */
+                case 0x12: /* Dispatch Control */
+                case 0x14: /* Softint set, WO */
+                case 0x15: /* Softint clear, WO */
+                case 0x16: /* Softint write */
 #endif
                 default:
                     goto illegal_insn;
                 }
 #if !defined(CONFIG_USER_ONLY)
+            } else if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */
 #ifndef TARGET_SPARC64
-            } else if (xop == 0x29) { /* rdpsr / V9 unimp */
-		if (!supervisor(dc))
-		    goto priv_insn;
+                if (!supervisor(dc))
+                    goto priv_insn;
                 gen_op_rdpsr();
+#else
+                if (!hypervisor(dc))
+                    goto priv_insn;
+                rs1 = GET_FIELD(insn, 13, 17);
+                switch (rs1) {
+                case 0: // hpstate
+                    // gen_op_rdhpstate();
+                    break;
+                case 1: // htstate
+                    // gen_op_rdhtstate();
+                    break;
+                case 3: // hintp
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, hintp));
+                    break;
+                case 5: // htba
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, htba));
+                    break;
+                case 6: // hver
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, hver));
+                    break;
+                case 31: // hstick_cmpr
+                    gen_op_movl_env_T0(offsetof(CPUSPARCState, hstick_cmpr));
+                    break;
+                default:
+                    goto illegal_insn;
+                }
+#endif
                 gen_movl_T0_reg(rd);
                 break;
-#endif
             } else if (xop == 0x2a) { /* rdwim / V9 rdpr */
-		if (!supervisor(dc))
-		    goto priv_insn;
+                if (!supervisor(dc))
+                    goto priv_insn;
 #ifdef TARGET_SPARC64
                 rs1 = GET_FIELD(insn, 13, 17);
-		switch (rs1) {
-		case 0: // tpc
-		    gen_op_rdtpc();
-		    break;
-		case 1: // tnpc
-		    gen_op_rdtnpc();
-		    break;
-		case 2: // tstate
-		    gen_op_rdtstate();
-		    break;
-		case 3: // tt
-		    gen_op_rdtt();
-		    break;
-		case 4: // tick
-		    gen_op_rdtick();
-		    break;
-		case 5: // tba
-		    gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr));
-		    break;
-		case 6: // pstate
-		    gen_op_rdpstate();
-		    break;
-		case 7: // tl
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, tl));
-		    break;
-		case 8: // pil
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, psrpil));
-		    break;
-		case 9: // cwp
-		    gen_op_rdcwp();
-		    break;
-		case 10: // cansave
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, cansave));
-		    break;
-		case 11: // canrestore
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, canrestore));
-		    break;
-		case 12: // cleanwin
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, cleanwin));
-		    break;
-		case 13: // otherwin
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, otherwin));
-		    break;
-		case 14: // wstate
-		    gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate));
-		    break;
-		case 31: // ver
-		    gen_op_movtl_T0_env(offsetof(CPUSPARCState, version));
-		    break;
-		case 15: // fq
-		default:
-		    goto illegal_insn;
-		}
+                switch (rs1) {
+                case 0: // tpc
+                    gen_op_rdtpc();
+                    break;
+                case 1: // tnpc
+                    gen_op_rdtnpc();
+                    break;
+                case 2: // tstate
+                    gen_op_rdtstate();
+                    break;
+                case 3: // tt
+                    gen_op_rdtt();
+                    break;
+                case 4: // tick
+                    gen_op_rdtick();
+                    break;
+                case 5: // tba
+                    gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr));
+                    break;
+                case 6: // pstate
+                    gen_op_rdpstate();
+                    break;
+                case 7: // tl
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, tl));
+                    break;
+                case 8: // pil
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, psrpil));
+                    break;
+                case 9: // cwp
+                    gen_op_rdcwp();
+                    break;
+                case 10: // cansave
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, cansave));
+                    break;
+                case 11: // canrestore
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, canrestore));
+                    break;
+                case 12: // cleanwin
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, cleanwin));
+                    break;
+                case 13: // otherwin
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, otherwin));
+                    break;
+                case 14: // wstate
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate));
+                    break;
+                case 16: // UA2005 gl
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, gl));
+                    break;
+                case 26: // UA2005 strand status
+                    if (!hypervisor(dc))
+                        goto priv_insn;
+                    gen_op_movl_T0_env(offsetof(CPUSPARCState, ssr));
+                    break;
+                case 31: // ver
+                    gen_op_movtl_T0_env(offsetof(CPUSPARCState, version));
+                    break;
+                case 15: // fq
+                default:
+                    goto illegal_insn;
+                }
 #else
-		gen_op_movl_T0_env(offsetof(CPUSPARCState, wim));
+                gen_op_movl_T0_env(offsetof(CPUSPARCState, wim));
 #endif
                 gen_movl_T0_reg(rd);
                 break;
             } else if (xop == 0x2b) { /* rdtbr / V9 flushw */
 #ifdef TARGET_SPARC64
-		gen_op_flushw();
+                gen_op_flushw();
 #else
-		if (!supervisor(dc))
-		    goto priv_insn;
-		gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr));
+                if (!supervisor(dc))
+                    goto priv_insn;
+                gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr));
                 gen_movl_T0_reg(rd);
 #endif
                 break;
 #endif
-	    } else if (xop == 0x34) {	/* FPU Operations */
+            } else if (xop == 0x34) {   /* FPU Operations */
                 if (gen_trap_ifnofpu(dc))
                     goto jmp_insn;
+                gen_op_clear_ieee_excp_and_FTT();
                 rs1 = GET_FIELD(insn, 13, 17);
-	        rs2 = GET_FIELD(insn, 27, 31);
-	        xop = GET_FIELD(insn, 18, 26);
-		switch (xop) {
-		    case 0x1: /* fmovs */
-                	gen_op_load_fpr_FT0(rs2);
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x5: /* fnegs */
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fnegs();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x9: /* fabss */
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fabss();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x29: /* fsqrts */
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fsqrts();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x2a: /* fsqrtd */
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fsqrtd();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x2b: /* fsqrtq */
-		        goto nfpu_insn;
-		    case 0x41:
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fadds();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x42:
-                	gen_op_load_fpr_DT0(DFPREG(rs1));
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_faddd();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x43: /* faddq */
-		        goto nfpu_insn;
-		    case 0x45:
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fsubs();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x46:
-                	gen_op_load_fpr_DT0(DFPREG(rs1));
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fsubd();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x47: /* fsubq */
-		        goto nfpu_insn;
-		    case 0x49:
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fmuls();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x4a:
-                	gen_op_load_fpr_DT0(DFPREG(rs1));
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fmuld();
-			gen_op_store_DT0_fpr(rd);
-			break;
-		    case 0x4b: /* fmulq */
-		        goto nfpu_insn;
-		    case 0x4d:
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fdivs();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x4e:
-                	gen_op_load_fpr_DT0(DFPREG(rs1));
-			gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fdivd();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x4f: /* fdivq */
-		        goto nfpu_insn;
-		    case 0x69:
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fsmuld();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x6e: /* fdmulq */
-		        goto nfpu_insn;
-		    case 0xc4:
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fitos();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0xc6:
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fdtos();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0xc7: /* fqtos */
-		        goto nfpu_insn;
-		    case 0xc8:
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fitod();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0xc9:
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fstod();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0xcb: /* fqtod */
-		        goto nfpu_insn;
-		    case 0xcc: /* fitoq */
-		        goto nfpu_insn;
-		    case 0xcd: /* fstoq */
-		        goto nfpu_insn;
-		    case 0xce: /* fdtoq */
-		        goto nfpu_insn;
-		    case 0xd1:
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fstoi();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0xd2:
-                	gen_op_load_fpr_DT1(rs2);
-			gen_op_fdtoi();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0xd3: /* fqtoi */
-		        goto nfpu_insn;
+                rs2 = GET_FIELD(insn, 27, 31);
+                xop = GET_FIELD(insn, 18, 26);
+                switch (xop) {
+                    case 0x1: /* fmovs */
+                        gen_op_load_fpr_FT0(rs2);
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x5: /* fnegs */
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fnegs();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x9: /* fabss */
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fabss();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x29: /* fsqrts */
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fsqrts();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x2a: /* fsqrtd */
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fsqrtd();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x2b: /* fsqrtq */
+                        goto nfpu_insn;
+                    case 0x41:
+                        gen_op_load_fpr_FT0(rs1);
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fadds();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x42:
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_faddd();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x43: /* faddq */
+                        goto nfpu_insn;
+                    case 0x45:
+                        gen_op_load_fpr_FT0(rs1);
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fsubs();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x46:
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fsubd();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x47: /* fsubq */
+                        goto nfpu_insn;
+                    case 0x49:
+                        gen_op_load_fpr_FT0(rs1);
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fmuls();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x4a:
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fmuld();
+                        gen_op_store_DT0_fpr(rd);
+                        break;
+                    case 0x4b: /* fmulq */
+                        goto nfpu_insn;
+                    case 0x4d:
+                        gen_op_load_fpr_FT0(rs1);
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fdivs();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x4e:
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fdivd();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x4f: /* fdivq */
+                        goto nfpu_insn;
+                    case 0x69:
+                        gen_op_load_fpr_FT0(rs1);
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fsmuld();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x6e: /* fdmulq */
+                        goto nfpu_insn;
+                    case 0xc4:
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fitos();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0xc6:
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fdtos();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0xc7: /* fqtos */
+                        goto nfpu_insn;
+                    case 0xc8:
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fitod();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0xc9:
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fstod();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0xcb: /* fqtod */
+                        goto nfpu_insn;
+                    case 0xcc: /* fitoq */
+                        goto nfpu_insn;
+                    case 0xcd: /* fstoq */
+                        goto nfpu_insn;
+                    case 0xce: /* fdtoq */
+                        goto nfpu_insn;
+                    case 0xd1:
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fstoi();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0xd2:
+                        gen_op_load_fpr_DT1(rs2);
+                        gen_op_fdtoi();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0xd3: /* fqtoi */
+                        goto nfpu_insn;
 #ifdef TARGET_SPARC64
-		    case 0x2: /* V9 fmovd */
-                	gen_op_load_fpr_DT0(DFPREG(rs2));
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x6: /* V9 fnegd */
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fnegd();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0xa: /* V9 fabsd */
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fabsd();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x81: /* V9 fstox */
-                	gen_op_load_fpr_FT1(rs2);
-			gen_op_fstox();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x82: /* V9 fdtox */
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fdtox();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x84: /* V9 fxtos */
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fxtos();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x88: /* V9 fxtod */
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
-			gen_op_fxtod();
-			gen_op_store_DT0_fpr(DFPREG(rd));
-			break;
-		    case 0x3: /* V9 fmovq */
-		    case 0x7: /* V9 fnegq */
-		    case 0xb: /* V9 fabsq */
-		    case 0x83: /* V9 fqtox */
-		    case 0x8c: /* V9 fxtoq */
-		        goto nfpu_insn;
+                    case 0x2: /* V9 fmovd */
+                        gen_op_load_fpr_DT0(DFPREG(rs2));
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x6: /* V9 fnegd */
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fnegd();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0xa: /* V9 fabsd */
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fabsd();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x81: /* V9 fstox */
+                        gen_op_load_fpr_FT1(rs2);
+                        gen_op_fstox();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x82: /* V9 fdtox */
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fdtox();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x84: /* V9 fxtos */
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fxtos();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x88: /* V9 fxtod */
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
+                        gen_op_fxtod();
+                        gen_op_store_DT0_fpr(DFPREG(rd));
+                        break;
+                    case 0x3: /* V9 fmovq */
+                    case 0x7: /* V9 fnegq */
+                    case 0xb: /* V9 fabsq */
+                    case 0x83: /* V9 fqtox */
+                    case 0x8c: /* V9 fxtoq */
+                        goto nfpu_insn;
 #endif
-		    default:
-                	goto illegal_insn;
-		}
-	    } else if (xop == 0x35) {	/* FPU Operations */
+                    default:
+                        goto illegal_insn;
+                }
+            } else if (xop == 0x35) {   /* FPU Operations */
 #ifdef TARGET_SPARC64
-		int cond;
+                int cond;
 #endif
                 if (gen_trap_ifnofpu(dc))
                     goto jmp_insn;
+                gen_op_clear_ieee_excp_and_FTT();
                 rs1 = GET_FIELD(insn, 13, 17);
-	        rs2 = GET_FIELD(insn, 27, 31);
-	        xop = GET_FIELD(insn, 18, 26);
+                rs2 = GET_FIELD(insn, 27, 31);
+                xop = GET_FIELD(insn, 18, 26);
 #ifdef TARGET_SPARC64
-		if ((xop & 0x11f) == 0x005) { // V9 fmovsr
-		    cond = GET_FIELD_SP(insn, 14, 17);
-		    gen_op_load_fpr_FT0(rd);
-		    gen_op_load_fpr_FT1(rs2);
-		    rs1 = GET_FIELD(insn, 13, 17);
-		    gen_movl_reg_T0(rs1);
-		    flush_T2(dc);
-		    gen_cond_reg(cond);
-		    gen_op_fmovs_cc();
-		    gen_op_store_FT0_fpr(rd);
-		    break;
-		} else if ((xop & 0x11f) == 0x006) { // V9 fmovdr
-		    cond = GET_FIELD_SP(insn, 14, 17);
-		    gen_op_load_fpr_DT0(rd);
-		    gen_op_load_fpr_DT1(rs2);
-		    flush_T2(dc);
-		    rs1 = GET_FIELD(insn, 13, 17);
-		    gen_movl_reg_T0(rs1);
-		    gen_cond_reg(cond);
-		    gen_op_fmovs_cc();
-		    gen_op_store_DT0_fpr(rd);
-		    break;
-		} else if ((xop & 0x11f) == 0x007) { // V9 fmovqr
-		    goto nfpu_insn;
-		}
+                if ((xop & 0x11f) == 0x005) { // V9 fmovsr
+                    cond = GET_FIELD_SP(insn, 14, 17);
+                    gen_op_load_fpr_FT0(rd);
+                    gen_op_load_fpr_FT1(rs2);
+                    rs1 = GET_FIELD(insn, 13, 17);
+                    gen_movl_reg_T0(rs1);
+                    flush_T2(dc);
+                    gen_cond_reg(cond);
+                    gen_op_fmovs_cc();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr
+                    cond = GET_FIELD_SP(insn, 14, 17);
+                    gen_op_load_fpr_DT0(rd);
+                    gen_op_load_fpr_DT1(rs2);
+                    flush_T2(dc);
+                    rs1 = GET_FIELD(insn, 13, 17);
+                    gen_movl_reg_T0(rs1);
+                    gen_cond_reg(cond);
+                    gen_op_fmovs_cc();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr
+                    goto nfpu_insn;
+                }
 #endif
-		switch (xop) {
+                switch (xop) {
 #ifdef TARGET_SPARC64
-		    case 0x001: /* V9 fmovscc %fcc0 */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_FT0(rd);
-                	gen_op_load_fpr_FT1(rs2);
-			flush_T2(dc);
-			gen_fcond[0][cond]();
-			gen_op_fmovs_cc();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x002: /* V9 fmovdcc %fcc0 */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_DT0(rd);
-                	gen_op_load_fpr_DT1(rs2);
-			flush_T2(dc);
-			gen_fcond[0][cond]();
-			gen_op_fmovd_cc();
-			gen_op_store_DT0_fpr(rd);
-			break;
-		    case 0x003: /* V9 fmovqcc %fcc0 */
-		        goto nfpu_insn;
-		    case 0x041: /* V9 fmovscc %fcc1 */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_FT0(rd);
-                	gen_op_load_fpr_FT1(rs2);
-			flush_T2(dc);
-			gen_fcond[1][cond]();
-			gen_op_fmovs_cc();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x042: /* V9 fmovdcc %fcc1 */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_DT0(rd);
-                	gen_op_load_fpr_DT1(rs2);
-			flush_T2(dc);
-			gen_fcond[1][cond]();
-			gen_op_fmovd_cc();
-			gen_op_store_DT0_fpr(rd);
-			break;
-		    case 0x043: /* V9 fmovqcc %fcc1 */
-		        goto nfpu_insn;
-		    case 0x081: /* V9 fmovscc %fcc2 */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_FT0(rd);
-                	gen_op_load_fpr_FT1(rs2);
-			flush_T2(dc);
-			gen_fcond[2][cond]();
-			gen_op_fmovs_cc();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x082: /* V9 fmovdcc %fcc2 */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_DT0(rd);
-                	gen_op_load_fpr_DT1(rs2);
-			flush_T2(dc);
-			gen_fcond[2][cond]();
-			gen_op_fmovd_cc();
-			gen_op_store_DT0_fpr(rd);
-			break;
-		    case 0x083: /* V9 fmovqcc %fcc2 */
-		        goto nfpu_insn;
-		    case 0x0c1: /* V9 fmovscc %fcc3 */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_FT0(rd);
-                	gen_op_load_fpr_FT1(rs2);
-			flush_T2(dc);
-			gen_fcond[3][cond]();
-			gen_op_fmovs_cc();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x0c2: /* V9 fmovdcc %fcc3 */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_DT0(rd);
-                	gen_op_load_fpr_DT1(rs2);
-			flush_T2(dc);
-			gen_fcond[3][cond]();
-			gen_op_fmovd_cc();
-			gen_op_store_DT0_fpr(rd);
-			break;
-		    case 0x0c3: /* V9 fmovqcc %fcc3 */
-		        goto nfpu_insn;
-		    case 0x101: /* V9 fmovscc %icc */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_FT0(rd);
-                	gen_op_load_fpr_FT1(rs2);
-			flush_T2(dc);
-			gen_cond[0][cond]();
-			gen_op_fmovs_cc();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x102: /* V9 fmovdcc %icc */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_DT0(rd);
-                	gen_op_load_fpr_DT1(rs2);
-			flush_T2(dc);
-			gen_cond[0][cond]();
-			gen_op_fmovd_cc();
-			gen_op_store_DT0_fpr(rd);
-			break;
-		    case 0x103: /* V9 fmovqcc %icc */
-		        goto nfpu_insn;
-		    case 0x181: /* V9 fmovscc %xcc */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_FT0(rd);
-                	gen_op_load_fpr_FT1(rs2);
-			flush_T2(dc);
-			gen_cond[1][cond]();
-			gen_op_fmovs_cc();
-			gen_op_store_FT0_fpr(rd);
-			break;
-		    case 0x182: /* V9 fmovdcc %xcc */
-			cond = GET_FIELD_SP(insn, 14, 17);
-                	gen_op_load_fpr_DT0(rd);
-                	gen_op_load_fpr_DT1(rs2);
-			flush_T2(dc);
-			gen_cond[1][cond]();
-			gen_op_fmovd_cc();
-			gen_op_store_DT0_fpr(rd);
-			break;
-		    case 0x183: /* V9 fmovqcc %xcc */
-		        goto nfpu_insn;
+                    case 0x001: /* V9 fmovscc %fcc0 */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_FT0(rd);
+                        gen_op_load_fpr_FT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[0][cond]();
+                        gen_op_fmovs_cc();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x002: /* V9 fmovdcc %fcc0 */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_DT0(rd);
+                        gen_op_load_fpr_DT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[0][cond]();
+                        gen_op_fmovd_cc();
+                        gen_op_store_DT0_fpr(rd);
+                        break;
+                    case 0x003: /* V9 fmovqcc %fcc0 */
+                        goto nfpu_insn;
+                    case 0x041: /* V9 fmovscc %fcc1 */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_FT0(rd);
+                        gen_op_load_fpr_FT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[1][cond]();
+                        gen_op_fmovs_cc();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x042: /* V9 fmovdcc %fcc1 */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_DT0(rd);
+                        gen_op_load_fpr_DT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[1][cond]();
+                        gen_op_fmovd_cc();
+                        gen_op_store_DT0_fpr(rd);
+                        break;
+                    case 0x043: /* V9 fmovqcc %fcc1 */
+                        goto nfpu_insn;
+                    case 0x081: /* V9 fmovscc %fcc2 */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_FT0(rd);
+                        gen_op_load_fpr_FT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[2][cond]();
+                        gen_op_fmovs_cc();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x082: /* V9 fmovdcc %fcc2 */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_DT0(rd);
+                        gen_op_load_fpr_DT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[2][cond]();
+                        gen_op_fmovd_cc();
+                        gen_op_store_DT0_fpr(rd);
+                        break;
+                    case 0x083: /* V9 fmovqcc %fcc2 */
+                        goto nfpu_insn;
+                    case 0x0c1: /* V9 fmovscc %fcc3 */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_FT0(rd);
+                        gen_op_load_fpr_FT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[3][cond]();
+                        gen_op_fmovs_cc();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x0c2: /* V9 fmovdcc %fcc3 */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_DT0(rd);
+                        gen_op_load_fpr_DT1(rs2);
+                        flush_T2(dc);
+                        gen_fcond[3][cond]();
+                        gen_op_fmovd_cc();
+                        gen_op_store_DT0_fpr(rd);
+                        break;
+                    case 0x0c3: /* V9 fmovqcc %fcc3 */
+                        goto nfpu_insn;
+                    case 0x101: /* V9 fmovscc %icc */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_FT0(rd);
+                        gen_op_load_fpr_FT1(rs2);
+                        flush_T2(dc);
+                        gen_cond[0][cond]();
+                        gen_op_fmovs_cc();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x102: /* V9 fmovdcc %icc */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_DT0(rd);
+                        gen_op_load_fpr_DT1(rs2);
+                        flush_T2(dc);
+                        gen_cond[0][cond]();
+                        gen_op_fmovd_cc();
+                        gen_op_store_DT0_fpr(rd);
+                        break;
+                    case 0x103: /* V9 fmovqcc %icc */
+                        goto nfpu_insn;
+                    case 0x181: /* V9 fmovscc %xcc */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_FT0(rd);
+                        gen_op_load_fpr_FT1(rs2);
+                        flush_T2(dc);
+                        gen_cond[1][cond]();
+                        gen_op_fmovs_cc();
+                        gen_op_store_FT0_fpr(rd);
+                        break;
+                    case 0x182: /* V9 fmovdcc %xcc */
+                        cond = GET_FIELD_SP(insn, 14, 17);
+                        gen_op_load_fpr_DT0(rd);
+                        gen_op_load_fpr_DT1(rs2);
+                        flush_T2(dc);
+                        gen_cond[1][cond]();
+                        gen_op_fmovd_cc();
+                        gen_op_store_DT0_fpr(rd);
+                        break;
+                    case 0x183: /* V9 fmovqcc %xcc */
+                        goto nfpu_insn;
 #endif
-		    case 0x51: /* V9 %fcc */
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
+                    case 0x51: /* V9 %fcc */
+                        gen_op_load_fpr_FT0(rs1);
+                        gen_op_load_fpr_FT1(rs2);
 #ifdef TARGET_SPARC64
-			gen_fcmps[rd & 3]();
+                        gen_fcmps[rd & 3]();
 #else
-			gen_op_fcmps();
+                        gen_op_fcmps();
 #endif
-			break;
-		    case 0x52: /* V9 %fcc */
-                	gen_op_load_fpr_DT0(DFPREG(rs1));
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
+                        break;
+                    case 0x52: /* V9 %fcc */
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
 #ifdef TARGET_SPARC64
-			gen_fcmpd[rd & 3]();
+                        gen_fcmpd[rd & 3]();
 #else
-			gen_op_fcmpd();
+                        gen_op_fcmpd();
 #endif
-			break;
-		    case 0x53: /* fcmpq */
-		        goto nfpu_insn;
-		    case 0x55: /* fcmpes, V9 %fcc */
-                	gen_op_load_fpr_FT0(rs1);
-                	gen_op_load_fpr_FT1(rs2);
+                        break;
+                    case 0x53: /* fcmpq */
+                        goto nfpu_insn;
+                    case 0x55: /* fcmpes, V9 %fcc */
+                        gen_op_load_fpr_FT0(rs1);
+                        gen_op_load_fpr_FT1(rs2);
 #ifdef TARGET_SPARC64
-			gen_fcmps[rd & 3]();
+                        gen_fcmpes[rd & 3]();
 #else
-			gen_op_fcmps(); /* XXX should trap if qNaN or sNaN  */
+                        gen_op_fcmpes();
 #endif
-			break;
-		    case 0x56: /* fcmped, V9 %fcc */
-                	gen_op_load_fpr_DT0(DFPREG(rs1));
-                	gen_op_load_fpr_DT1(DFPREG(rs2));
+                        break;
+                    case 0x56: /* fcmped, V9 %fcc */
+                        gen_op_load_fpr_DT0(DFPREG(rs1));
+                        gen_op_load_fpr_DT1(DFPREG(rs2));
 #ifdef TARGET_SPARC64
-			gen_fcmpd[rd & 3]();
+                        gen_fcmped[rd & 3]();
 #else
-			gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN  */
+                        gen_op_fcmped();
 #endif
-			break;
-		    case 0x57: /* fcmpeq */
-		        goto nfpu_insn;
-		    default:
-                	goto illegal_insn;
-		}
+                        break;
+                    case 0x57: /* fcmpeq */
+                        goto nfpu_insn;
+                    default:
+                        goto illegal_insn;
+                }
 #if defined(OPTIM)
-	    } else if (xop == 0x2) {
-		// clr/mov shortcut
+            } else if (xop == 0x2) {
+                // clr/mov shortcut
 
                 rs1 = GET_FIELD(insn, 13, 17);
-		if (rs1 == 0) {
-		    // or %g0, x, y -> mov T1, x; mov y, T1
-		    if (IS_IMM) {	/* immediate */
-			rs2 = GET_FIELDs(insn, 19, 31);
-			gen_movl_simm_T1(rs2);
-		    } else {		/* register */
-			rs2 = GET_FIELD(insn, 27, 31);
-			gen_movl_reg_T1(rs2);
-		    }
-		    gen_movl_T1_reg(rd);
-		} else {
-		    gen_movl_reg_T0(rs1);
-		    if (IS_IMM) {	/* immediate */
-			// or x, #0, y -> mov T1, x; mov y, T1
-			rs2 = GET_FIELDs(insn, 19, 31);
-			if (rs2 != 0) {
-			    gen_movl_simm_T1(rs2);
-			    gen_op_or_T1_T0();
-			}
-		    } else {		/* register */
-			// or x, %g0, y -> mov T1, x; mov y, T1
-			rs2 = GET_FIELD(insn, 27, 31);
-			if (rs2 != 0) {
-			    gen_movl_reg_T1(rs2);
-			    gen_op_or_T1_T0();
-			}
-		    }
-		    gen_movl_T0_reg(rd);
-		}
+                if (rs1 == 0) {
+                    // or %g0, x, y -> mov T1, x; mov y, T1
+                    if (IS_IMM) {       /* immediate */
+                        rs2 = GET_FIELDs(insn, 19, 31);
+                        gen_movl_simm_T1(rs2);
+                    } else {            /* register */
+                        rs2 = GET_FIELD(insn, 27, 31);
+                        gen_movl_reg_T1(rs2);
+                    }
+                    gen_movl_T1_reg(rd);
+                } else {
+                    gen_movl_reg_T0(rs1);
+                    if (IS_IMM) {       /* immediate */
+                        // or x, #0, y -> mov T1, x; mov y, T1
+                        rs2 = GET_FIELDs(insn, 19, 31);
+                        if (rs2 != 0) {
+                            gen_movl_simm_T1(rs2);
+                            gen_op_or_T1_T0();
+                        }
+                    } else {            /* register */
+                        // or x, %g0, y -> mov T1, x; mov y, T1
+                        rs2 = GET_FIELD(insn, 27, 31);
+                        if (rs2 != 0) {
+                            gen_movl_reg_T1(rs2);
+                            gen_op_or_T1_T0();
+                        }
+                    }
+                    gen_movl_T0_reg(rd);
+                }
 #endif
 #ifdef TARGET_SPARC64
-	    } else if (xop == 0x25) { /* sll, V9 sllx ( == sll) */
+            } else if (xop == 0x25) { /* sll, V9 sllx */
                 rs1 = GET_FIELD(insn, 13, 17);
-		gen_movl_reg_T0(rs1);
-		if (IS_IMM) {	/* immediate */
+                gen_movl_reg_T0(rs1);
+                if (IS_IMM) {   /* immediate */
                     rs2 = GET_FIELDs(insn, 20, 31);
                     gen_movl_simm_T1(rs2);
-                } else {		/* register */
+                } else {                /* register */
                     rs2 = GET_FIELD(insn, 27, 31);
                     gen_movl_reg_T1(rs2);
                 }
-		gen_op_sll();
-		gen_movl_T0_reg(rd);
-	    } else if (xop == 0x26) { /* srl, V9 srlx */
+                if (insn & (1 << 12))
+                    gen_op_sllx();
+                else
+                    gen_op_sll();
+                gen_movl_T0_reg(rd);
+            } else if (xop == 0x26) { /* srl, V9 srlx */
                 rs1 = GET_FIELD(insn, 13, 17);
-		gen_movl_reg_T0(rs1);
-		if (IS_IMM) {	/* immediate */
+                gen_movl_reg_T0(rs1);
+                if (IS_IMM) {   /* immediate */
                     rs2 = GET_FIELDs(insn, 20, 31);
                     gen_movl_simm_T1(rs2);
-                } else {		/* register */
+                } else {                /* register */
                     rs2 = GET_FIELD(insn, 27, 31);
                     gen_movl_reg_T1(rs2);
                 }
-		if (insn & (1 << 12))
-		    gen_op_srlx();
-		else
-		    gen_op_srl();
-		gen_movl_T0_reg(rd);
-	    } else if (xop == 0x27) { /* sra, V9 srax */
+                if (insn & (1 << 12))
+                    gen_op_srlx();
+                else
+                    gen_op_srl();
+                gen_movl_T0_reg(rd);
+            } else if (xop == 0x27) { /* sra, V9 srax */
                 rs1 = GET_FIELD(insn, 13, 17);
-		gen_movl_reg_T0(rs1);
-		if (IS_IMM) {	/* immediate */
+                gen_movl_reg_T0(rs1);
+                if (IS_IMM) {   /* immediate */
                     rs2 = GET_FIELDs(insn, 20, 31);
                     gen_movl_simm_T1(rs2);
-                } else {		/* register */
+                } else {                /* register */
                     rs2 = GET_FIELD(insn, 27, 31);
                     gen_movl_reg_T1(rs2);
                 }
-		if (insn & (1 << 12))
-		    gen_op_srax();
-		else
-		    gen_op_sra();
-		gen_movl_T0_reg(rd);
+                if (insn & (1 << 12))
+                    gen_op_srax();
+                else
+                    gen_op_sra();
+                gen_movl_T0_reg(rd);
 #endif
-	    } else if (xop < 0x38) {
+            } else if (xop < 0x36) {
                 rs1 = GET_FIELD(insn, 13, 17);
-		gen_movl_reg_T0(rs1);
-		if (IS_IMM) {	/* immediate */
+                gen_movl_reg_T0(rs1);
+                if (IS_IMM) {   /* immediate */
                     rs2 = GET_FIELDs(insn, 19, 31);
                     gen_movl_simm_T1(rs2);
-                } else {		/* register */
+                } else {                /* register */
                     rs2 = GET_FIELD(insn, 27, 31);
                     gen_movl_reg_T1(rs2);
                 }
@@ -1754,10 +1940,10 @@
                             gen_op_logic_T0_cc();
                         break;
                     case 0x2:
-			gen_op_or_T1_T0();
-			if (xop & 0x10)
-			    gen_op_logic_T0_cc();
-			break;
+                        gen_op_or_T1_T0();
+                        if (xop & 0x10)
+                            gen_op_logic_T0_cc();
+                        break;
                     case 0x3:
                         gen_op_xor_T1_T0();
                         if (xop & 0x10)
@@ -1791,7 +1977,7 @@
                             gen_op_addx_T1_T0();
                         break;
 #ifdef TARGET_SPARC64
-		    case 0x9: /* V9 mulx */
+                    case 0x9: /* V9 mulx */
                         gen_op_mulx_T1_T0();
                         break;
 #endif
@@ -1812,7 +1998,7 @@
                             gen_op_subx_T1_T0();
                         break;
 #ifdef TARGET_SPARC64
-		    case 0xd: /* V9 udivx */
+                    case 0xd: /* V9 udivx */
                         gen_op_udivx_T1_T0();
                         break;
 #endif
@@ -1829,29 +2015,40 @@
                     default:
                         goto illegal_insn;
                     }
-		    gen_movl_T0_reg(rd);
+                    gen_movl_T0_reg(rd);
                 } else {
                     switch (xop) {
-		    case 0x20: /* taddcc */
-		    case 0x21: /* tsubcc */
-		    case 0x22: /* taddcctv */
-		    case 0x23: /* tsubcctv */
-			goto illegal_insn;
+                    case 0x20: /* taddcc */
+                        gen_op_tadd_T1_T0_cc();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x21: /* tsubcc */
+                        gen_op_tsub_T1_T0_cc();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x22: /* taddcctv */
+                        gen_op_tadd_T1_T0_ccTV();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x23: /* tsubcctv */
+                        gen_op_tsub_T1_T0_ccTV();
+                        gen_movl_T0_reg(rd);
+                        break;
                     case 0x24: /* mulscc */
                         gen_op_mulscc_T1_T0();
                         gen_movl_T0_reg(rd);
                         break;
 #ifndef TARGET_SPARC64
-                    case 0x25:	/* sll */
-			gen_op_sll();
+                    case 0x25:  /* sll */
+                        gen_op_sll();
                         gen_movl_T0_reg(rd);
                         break;
                     case 0x26:  /* srl */
-			gen_op_srl();
+                        gen_op_srl();
                         gen_movl_T0_reg(rd);
                         break;
                     case 0x27:  /* sra */
-			gen_op_sra();
+                        gen_op_sra();
                         gen_movl_T0_reg(rd);
                         break;
 #endif
@@ -1859,58 +2056,82 @@
                         {
                             switch(rd) {
                             case 0: /* wry */
-				gen_op_xor_T1_T0();
-				gen_op_movtl_env_T0(offsetof(CPUSPARCState, y));
+                                gen_op_xor_T1_T0();
+                                gen_op_movtl_env_T0(offsetof(CPUSPARCState, y));
                                 break;
-#ifdef TARGET_SPARC64
-			    case 0x2: /* V9 wrccr */
+#ifndef TARGET_SPARC64
+                            case 0x01 ... 0x0f: /* undefined in the
+                                                   SPARCv8 manual, nop
+                                                   on the microSPARC
+                                                   II */
+                            case 0x10 ... 0x1f: /* implementation-dependent
+                                                   in the SPARCv8
+                                                   manual, nop on the
+                                                   microSPARC II */
+                                break;
+#else
+                            case 0x2: /* V9 wrccr */
+                                gen_op_xor_T1_T0();
                                 gen_op_wrccr();
-				break;
-			    case 0x3: /* V9 wrasi */
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, asi));
-				break;
-			    case 0x6: /* V9 wrfprs */
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs));
-				break;
-			    case 0xf: /* V9 sir, nop if user */
+                                break;
+                            case 0x3: /* V9 wrasi */
+                                gen_op_xor_T1_T0();
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, asi));
+                                break;
+                            case 0x6: /* V9 wrfprs */
+                                gen_op_xor_T1_T0();
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs));
+                                save_state(dc);
+                                gen_op_next_insn();
+                                gen_op_movl_T0_0();
+                                gen_op_exit_tb();
+                                dc->is_br = 1;
+                                break;
+                            case 0xf: /* V9 sir, nop if user */
 #if !defined(CONFIG_USER_ONLY)
-				if (supervisor(dc))
-				    gen_op_sir();
+                                if (supervisor(dc))
+                                    gen_op_sir();
 #endif
-				break;
-			    case 0x13: /* Graphics Status */
+                                break;
+                            case 0x13: /* Graphics Status */
                                 if (gen_trap_ifnofpu(dc))
                                     goto jmp_insn;
-				gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr));
-				break;
-			    case 0x17: /* Tick compare */
+                                gen_op_xor_T1_T0();
+                                gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr));
+                                break;
+                            case 0x17: /* Tick compare */
 #if !defined(CONFIG_USER_ONLY)
-				if (!supervisor(dc))
-				    goto illegal_insn;
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
 #endif
-				gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr));
-				break;
-			    case 0x18: /* System tick */
+                                gen_op_xor_T1_T0();
+                                gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr));
+                                gen_op_wrtick_cmpr();
+                                break;
+                            case 0x18: /* System tick */
 #if !defined(CONFIG_USER_ONLY)
-				if (!supervisor(dc))
-				    goto illegal_insn;
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
 #endif
-				gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
-				break;
-			    case 0x19: /* System tick compare */
+                                gen_op_xor_T1_T0();
+                                gen_op_wrstick();
+                                break;
+                            case 0x19: /* System tick compare */
 #if !defined(CONFIG_USER_ONLY)
-				if (!supervisor(dc))
-				    goto illegal_insn;
+                                if (!supervisor(dc))
+                                    goto illegal_insn;
 #endif
-				gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
-				break;
+                                gen_op_xor_T1_T0();
+                                gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
+                                gen_op_wrstick_cmpr();
+                                break;
 
-			    case 0x10: /* Performance Control */
-			    case 0x11: /* Performance Instrumentation Counter */
-			    case 0x12: /* Dispatch Control */
-			    case 0x14: /* Softint set */
-			    case 0x15: /* Softint clear */
-			    case 0x16: /* Softint write */
+                            case 0x10: /* Performance Control */
+                            case 0x11: /* Performance Instrumentation Counter */
+                            case 0x12: /* Dispatch Control */
+                            case 0x14: /* Softint set */
+                            case 0x15: /* Softint clear */
+                            case 0x16: /* Softint write */
 #endif
                             default:
                                 goto illegal_insn;
@@ -1920,17 +2141,22 @@
 #if !defined(CONFIG_USER_ONLY)
                     case 0x31: /* wrpsr, V9 saved, restored */
                         {
-			    if (!supervisor(dc))
-				goto priv_insn;
+                            if (!supervisor(dc))
+                                goto priv_insn;
 #ifdef TARGET_SPARC64
-			    switch (rd) {
-			    case 0:
-				gen_op_saved();
-				break;
-			    case 1:
-				gen_op_restored();
-				break;
-			    default:
+                            switch (rd) {
+                            case 0:
+                                gen_op_saved();
+                                break;
+                            case 1:
+                                gen_op_restored();
+                                break;
+                            case 2: /* UA2005 allclean */
+                            case 3: /* UA2005 otherw */
+                            case 4: /* UA2005 normalw */
+                            case 5: /* UA2005 invalw */
+                                // XXX
+                            default:
                                 goto illegal_insn;
                             }
 #else
@@ -1938,252 +2164,663 @@
                             gen_op_wrpsr();
                             save_state(dc);
                             gen_op_next_insn();
-			    gen_op_movl_T0_0();
-			    gen_op_exit_tb();
-			    dc->is_br = 1;
+                            gen_op_movl_T0_0();
+                            gen_op_exit_tb();
+                            dc->is_br = 1;
 #endif
                         }
                         break;
                     case 0x32: /* wrwim, V9 wrpr */
                         {
-			    if (!supervisor(dc))
-				goto priv_insn;
+                            if (!supervisor(dc))
+                                goto priv_insn;
                             gen_op_xor_T1_T0();
 #ifdef TARGET_SPARC64
-			    switch (rd) {
-			    case 0: // tpc
-				gen_op_wrtpc();
-				break;
-			    case 1: // tnpc
-				gen_op_wrtnpc();
-				break;
-			    case 2: // tstate
-				gen_op_wrtstate();
-				break;
-			    case 3: // tt
-				gen_op_wrtt();
-				break;
-			    case 4: // tick
-				gen_op_wrtick();
-				break;
-			    case 5: // tba
-				gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
-				break;
-			    case 6: // pstate
-				gen_op_wrpstate();
+                            switch (rd) {
+                            case 0: // tpc
+                                gen_op_wrtpc();
+                                break;
+                            case 1: // tnpc
+                                gen_op_wrtnpc();
+                                break;
+                            case 2: // tstate
+                                gen_op_wrtstate();
+                                break;
+                            case 3: // tt
+                                gen_op_wrtt();
+                                break;
+                            case 4: // tick
+                                gen_op_wrtick();
+                                break;
+                            case 5: // tba
+                                gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
+                                break;
+                            case 6: // pstate
+                                gen_op_wrpstate();
                                 save_state(dc);
                                 gen_op_next_insn();
                                 gen_op_movl_T0_0();
                                 gen_op_exit_tb();
                                 dc->is_br = 1;
-				break;
-			    case 7: // tl
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, tl));
-				break;
-			    case 8: // pil
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, psrpil));
-				break;
-			    case 9: // cwp
-				gen_op_wrcwp();
-				break;
-			    case 10: // cansave
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, cansave));
-				break;
-			    case 11: // canrestore
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, canrestore));
-				break;
-			    case 12: // cleanwin
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, cleanwin));
-				break;
-			    case 13: // otherwin
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, otherwin));
-				break;
-			    case 14: // wstate
-				gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate));
-				break;
-			    default:
-				goto illegal_insn;
-			    }
-#else
-			    gen_op_wrwim();
-#endif
-                        }
-                        break;
-#ifndef TARGET_SPARC64
-                    case 0x33: /* wrtbr, V9 unimp */
-                        {
-			    if (!supervisor(dc))
-				goto priv_insn;
-                            gen_op_xor_T1_T0();
-			    gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
-                        }
-                        break;
-#endif
-#endif
-#ifdef TARGET_SPARC64
-		    case 0x2c: /* V9 movcc */
-			{
-			    int cc = GET_FIELD_SP(insn, 11, 12);
-			    int cond = GET_FIELD_SP(insn, 14, 17);
-			    if (IS_IMM) {	/* immediate */
-				rs2 = GET_FIELD_SPs(insn, 0, 10);
-				gen_movl_simm_T1(rs2);
-			    }
-			    else {
-				rs2 = GET_FIELD_SP(insn, 0, 4);
-				gen_movl_reg_T1(rs2);
-			    }
-			    gen_movl_reg_T0(rd);
-			    flush_T2(dc);
-			    if (insn & (1 << 18)) {
-				if (cc == 0)
-				    gen_cond[0][cond]();
-				else if (cc == 2)
-				    gen_cond[1][cond]();
-				else
-				    goto illegal_insn;
-			    } else {
-				gen_fcond[cc][cond]();
-			    }
-			    gen_op_mov_cc();
-			    gen_movl_T0_reg(rd);
-			    break;
-			}
-		    case 0x2d: /* V9 sdivx */
-                        gen_op_sdivx_T1_T0();
-			gen_movl_T0_reg(rd);
-                        break;
-		    case 0x2e: /* V9 popc */
-			{
-			    if (IS_IMM) {	/* immediate */
-				rs2 = GET_FIELD_SPs(insn, 0, 12);
-				gen_movl_simm_T1(rs2);
-				// XXX optimize: popc(constant)
-			    }
-			    else {
-				rs2 = GET_FIELD_SP(insn, 0, 4);
-				gen_movl_reg_T1(rs2);
-			    }
-			    gen_op_popc();
-			    gen_movl_T0_reg(rd);
-			}
-		    case 0x2f: /* V9 movr */
-			{
-			    int cond = GET_FIELD_SP(insn, 10, 12);
-			    rs1 = GET_FIELD(insn, 13, 17);
-			    flush_T2(dc);
-			    gen_movl_reg_T0(rs1);
-			    gen_cond_reg(cond);
-			    if (IS_IMM) {	/* immediate */
-				rs2 = GET_FIELD_SPs(insn, 0, 10);
-				gen_movl_simm_T1(rs2);
-			    }
-			    else {
-				rs2 = GET_FIELD_SP(insn, 0, 4);
-				gen_movl_reg_T1(rs2);
-			    }
-			    gen_movl_reg_T0(rd);
-			    gen_op_mov_cc();
-			    gen_movl_T0_reg(rd);
-			    break;
-			}
-		    case 0x36: /* UltraSparc shutdown, VIS */
-			{
-			    int opf = GET_FIELD_SP(insn, 5, 13);
-                            rs1 = GET_FIELD(insn, 13, 17);
-                            rs2 = GET_FIELD(insn, 27, 31);
-
-                            switch (opf) {
-                            case 0x018: /* VIS I alignaddr */
-                                if (gen_trap_ifnofpu(dc))
-                                    goto jmp_insn;
-                                gen_movl_reg_T0(rs1);
-                                gen_movl_reg_T1(rs2);
-                                gen_op_alignaddr();
-                                gen_movl_T0_reg(rd);
                                 break;
-                            case 0x01a: /* VIS I alignaddrl */
-                                if (gen_trap_ifnofpu(dc))
-                                    goto jmp_insn;
-                                // XXX
+                            case 7: // tl
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, tl));
                                 break;
-                            case 0x048: /* VIS I faligndata */
-                                if (gen_trap_ifnofpu(dc))
-                                    goto jmp_insn;
-                                gen_op_load_fpr_DT0(rs1);
-                                gen_op_load_fpr_DT1(rs2);
-                                gen_op_faligndata();
-                                gen_op_store_DT0_fpr(rd);
+                            case 8: // pil
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, psrpil));
+                                break;
+                            case 9: // cwp
+                                gen_op_wrcwp();
+                                break;
+                            case 10: // cansave
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, cansave));
+                                break;
+                            case 11: // canrestore
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, canrestore));
+                                break;
+                            case 12: // cleanwin
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, cleanwin));
+                                break;
+                            case 13: // otherwin
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, otherwin));
+                                break;
+                            case 14: // wstate
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate));
+                                break;
+                            case 16: // UA2005 gl
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, gl));
+                                break;
+                            case 26: // UA2005 strand status
+                                if (!hypervisor(dc))
+                                    goto priv_insn;
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, ssr));
                                 break;
                             default:
                                 goto illegal_insn;
                             }
-                            break;
-			}
+#else
+                            gen_op_wrwim();
 #endif
-		    default:
-			goto illegal_insn;
-		    }
-		}
+                        }
+                        break;
+                    case 0x33: /* wrtbr, UA2005 wrhpr */
+                        {
+#ifndef TARGET_SPARC64
+                            if (!supervisor(dc))
+                                goto priv_insn;
+                            gen_op_xor_T1_T0();
+                            gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
+#else
+                            if (!hypervisor(dc))
+                                goto priv_insn;
+                            gen_op_xor_T1_T0();
+                            switch (rd) {
+                            case 0: // hpstate
+                                // XXX gen_op_wrhpstate();
+                                save_state(dc);
+                                gen_op_next_insn();
+                                gen_op_movl_T0_0();
+                                gen_op_exit_tb();
+                                dc->is_br = 1;
+                                break;
+                            case 1: // htstate
+                                // XXX gen_op_wrhtstate();
+                                break;
+                            case 3: // hintp
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, hintp));
+                                break;
+                            case 5: // htba
+                                gen_op_movl_env_T0(offsetof(CPUSPARCState, htba));
+                                break;
+                            case 31: // hstick_cmpr
+                                gen_op_movtl_env_T0(offsetof(CPUSPARCState, hstick_cmpr));
+                                gen_op_wrhstick_cmpr();
+                                break;
+                            case 6: // hver readonly
+                            default:
+                                goto illegal_insn;
+                            }
+#endif
+                        }
+                        break;
+#endif
 #ifdef TARGET_SPARC64
-	    } else if (xop == 0x39) { /* V9 return */
+                    case 0x2c: /* V9 movcc */
+                        {
+                            int cc = GET_FIELD_SP(insn, 11, 12);
+                            int cond = GET_FIELD_SP(insn, 14, 17);
+                            if (IS_IMM) {       /* immediate */
+                                rs2 = GET_FIELD_SPs(insn, 0, 10);
+                                gen_movl_simm_T1(rs2);
+                            }
+                            else {
+                                rs2 = GET_FIELD_SP(insn, 0, 4);
+                                gen_movl_reg_T1(rs2);
+                            }
+                            gen_movl_reg_T0(rd);
+                            flush_T2(dc);
+                            if (insn & (1 << 18)) {
+                                if (cc == 0)
+                                    gen_cond[0][cond]();
+                                else if (cc == 2)
+                                    gen_cond[1][cond]();
+                                else
+                                    goto illegal_insn;
+                            } else {
+                                gen_fcond[cc][cond]();
+                            }
+                            gen_op_mov_cc();
+                            gen_movl_T0_reg(rd);
+                            break;
+                        }
+                    case 0x2d: /* V9 sdivx */
+                        gen_op_sdivx_T1_T0();
+                        gen_movl_T0_reg(rd);
+                        break;
+                    case 0x2e: /* V9 popc */
+                        {
+                            if (IS_IMM) {       /* immediate */
+                                rs2 = GET_FIELD_SPs(insn, 0, 12);
+                                gen_movl_simm_T1(rs2);
+                                // XXX optimize: popc(constant)
+                            }
+                            else {
+                                rs2 = GET_FIELD_SP(insn, 0, 4);
+                                gen_movl_reg_T1(rs2);
+                            }
+                            gen_op_popc();
+                            gen_movl_T0_reg(rd);
+                        }
+                    case 0x2f: /* V9 movr */
+                        {
+                            int cond = GET_FIELD_SP(insn, 10, 12);
+                            rs1 = GET_FIELD(insn, 13, 17);
+                            flush_T2(dc);
+                            gen_movl_reg_T0(rs1);
+                            gen_cond_reg(cond);
+                            if (IS_IMM) {       /* immediate */
+                                rs2 = GET_FIELD_SPs(insn, 0, 9);
+                                gen_movl_simm_T1(rs2);
+                            }
+                            else {
+                                rs2 = GET_FIELD_SP(insn, 0, 4);
+                                gen_movl_reg_T1(rs2);
+                            }
+                            gen_movl_reg_T0(rd);
+                            gen_op_mov_cc();
+                            gen_movl_T0_reg(rd);
+                            break;
+                        }
+#endif
+                    default:
+                        goto illegal_insn;
+                    }
+                }
+            } else if (xop == 0x36) { /* UltraSparc shutdown, VIS, V8 CPop1 */
+#ifdef TARGET_SPARC64
+                int opf = GET_FIELD_SP(insn, 5, 13);
                 rs1 = GET_FIELD(insn, 13, 17);
-		gen_movl_reg_T0(rs1);
-                if (IS_IMM) {	/* immediate */
-		    rs2 = GET_FIELDs(insn, 19, 31);
-#if defined(OPTIM)
-		    if (rs2) {
+                rs2 = GET_FIELD(insn, 27, 31);
+                if (gen_trap_ifnofpu(dc))
+                    goto jmp_insn;
+
+                switch (opf) {
+                case 0x000: /* VIS I edge8cc */
+                case 0x001: /* VIS II edge8n */
+                case 0x002: /* VIS I edge8lcc */
+                case 0x003: /* VIS II edge8ln */
+                case 0x004: /* VIS I edge16cc */
+                case 0x005: /* VIS II edge16n */
+                case 0x006: /* VIS I edge16lcc */
+                case 0x007: /* VIS II edge16ln */
+                case 0x008: /* VIS I edge32cc */
+                case 0x009: /* VIS II edge32n */
+                case 0x00a: /* VIS I edge32lcc */
+                case 0x00b: /* VIS II edge32ln */
+                    // XXX
+                    goto illegal_insn;
+                case 0x010: /* VIS I array8 */
+                    gen_movl_reg_T0(rs1);
+                    gen_movl_reg_T1(rs2);
+                    gen_op_array8();
+                    gen_movl_T0_reg(rd);
+                    break;
+                case 0x012: /* VIS I array16 */
+                    gen_movl_reg_T0(rs1);
+                    gen_movl_reg_T1(rs2);
+                    gen_op_array16();
+                    gen_movl_T0_reg(rd);
+                    break;
+                case 0x014: /* VIS I array32 */
+                    gen_movl_reg_T0(rs1);
+                    gen_movl_reg_T1(rs2);
+                    gen_op_array32();
+                    gen_movl_T0_reg(rd);
+                    break;
+                case 0x018: /* VIS I alignaddr */
+                    gen_movl_reg_T0(rs1);
+                    gen_movl_reg_T1(rs2);
+                    gen_op_alignaddr();
+                    gen_movl_T0_reg(rd);
+                    break;
+                case 0x019: /* VIS II bmask */
+                case 0x01a: /* VIS I alignaddrl */
+                    // XXX
+                    goto illegal_insn;
+                case 0x020: /* VIS I fcmple16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fcmple16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x022: /* VIS I fcmpne16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fcmpne16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x024: /* VIS I fcmple32 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fcmple32();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x026: /* VIS I fcmpne32 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fcmpne32();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x028: /* VIS I fcmpgt16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fcmpgt16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x02a: /* VIS I fcmpeq16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fcmpeq16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x02c: /* VIS I fcmpgt32 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fcmpgt32();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x02e: /* VIS I fcmpeq32 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fcmpeq32();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x031: /* VIS I fmul8x16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fmul8x16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x033: /* VIS I fmul8x16au */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fmul8x16au();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x035: /* VIS I fmul8x16al */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fmul8x16al();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x036: /* VIS I fmul8sux16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fmul8sux16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x037: /* VIS I fmul8ulx16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fmul8ulx16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x038: /* VIS I fmuld8sux16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fmuld8sux16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x039: /* VIS I fmuld8ulx16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fmuld8ulx16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x03a: /* VIS I fpack32 */
+                case 0x03b: /* VIS I fpack16 */
+                case 0x03d: /* VIS I fpackfix */
+                case 0x03e: /* VIS I pdist */
+                    // XXX
+                    goto illegal_insn;
+                case 0x048: /* VIS I faligndata */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_faligndata();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x04b: /* VIS I fpmerge */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fpmerge();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x04c: /* VIS II bshuffle */
+                    // XXX
+                    goto illegal_insn;
+                case 0x04d: /* VIS I fexpand */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fexpand();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x050: /* VIS I fpadd16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fpadd16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x051: /* VIS I fpadd16s */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fpadd16s();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x052: /* VIS I fpadd32 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fpadd32();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x053: /* VIS I fpadd32s */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fpadd32s();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x054: /* VIS I fpsub16 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fpsub16();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x055: /* VIS I fpsub16s */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fpsub16s();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x056: /* VIS I fpsub32 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fpadd32();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x057: /* VIS I fpsub32s */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fpsub32s();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x060: /* VIS I fzero */
+                    gen_op_movl_DT0_0();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x061: /* VIS I fzeros */
+                    gen_op_movl_FT0_0();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x062: /* VIS I fnor */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fnor();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x063: /* VIS I fnors */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fnors();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x064: /* VIS I fandnot2 */
+                    gen_op_load_fpr_DT1(rs1);
+                    gen_op_load_fpr_DT0(rs2);
+                    gen_op_fandnot();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x065: /* VIS I fandnot2s */
+                    gen_op_load_fpr_FT1(rs1);
+                    gen_op_load_fpr_FT0(rs2);
+                    gen_op_fandnots();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x066: /* VIS I fnot2 */
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fnot();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x067: /* VIS I fnot2s */
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fnot();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x068: /* VIS I fandnot1 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fandnot();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x069: /* VIS I fandnot1s */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fandnots();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x06a: /* VIS I fnot1 */
+                    gen_op_load_fpr_DT1(rs1);
+                    gen_op_fnot();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x06b: /* VIS I fnot1s */
+                    gen_op_load_fpr_FT1(rs1);
+                    gen_op_fnot();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x06c: /* VIS I fxor */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fxor();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x06d: /* VIS I fxors */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fxors();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x06e: /* VIS I fnand */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fnand();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x06f: /* VIS I fnands */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fnands();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x070: /* VIS I fand */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fand();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x071: /* VIS I fands */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fands();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x072: /* VIS I fxnor */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fxnor();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x073: /* VIS I fxnors */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fxnors();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x074: /* VIS I fsrc1 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x075: /* VIS I fsrc1s */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x076: /* VIS I fornot2 */
+                    gen_op_load_fpr_DT1(rs1);
+                    gen_op_load_fpr_DT0(rs2);
+                    gen_op_fornot();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x077: /* VIS I fornot2s */
+                    gen_op_load_fpr_FT1(rs1);
+                    gen_op_load_fpr_FT0(rs2);
+                    gen_op_fornots();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x078: /* VIS I fsrc2 */
+                    gen_op_load_fpr_DT0(rs2);
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x079: /* VIS I fsrc2s */
+                    gen_op_load_fpr_FT0(rs2);
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x07a: /* VIS I fornot1 */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_fornot();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x07b: /* VIS I fornot1s */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fornots();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x07c: /* VIS I for */
+                    gen_op_load_fpr_DT0(rs1);
+                    gen_op_load_fpr_DT1(rs2);
+                    gen_op_for();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x07d: /* VIS I fors */
+                    gen_op_load_fpr_FT0(rs1);
+                    gen_op_load_fpr_FT1(rs2);
+                    gen_op_fors();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x07e: /* VIS I fone */
+                    gen_op_movl_DT0_1();
+                    gen_op_store_DT0_fpr(rd);
+                    break;
+                case 0x07f: /* VIS I fones */
+                    gen_op_movl_FT0_1();
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x080: /* VIS I shutdown */
+                case 0x081: /* VIS II siam */
+                    // XXX
+                    goto illegal_insn;
+                default:
+                    goto illegal_insn;
+                }
+#else
+                goto ncp_insn;
 #endif
-			gen_movl_simm_T1(rs2);
-			gen_op_add_T1_T0();
-#if defined(OPTIM)
-		    }
+            } else if (xop == 0x37) { /* V8 CPop2, V9 impdep2 */
+#ifdef TARGET_SPARC64
+                goto illegal_insn;
+#else
+                goto ncp_insn;
 #endif
-                } else {		/* register */
+#ifdef TARGET_SPARC64
+            } else if (xop == 0x39) { /* V9 return */
+                rs1 = GET_FIELD(insn, 13, 17);
+                save_state(dc);
+                gen_movl_reg_T0(rs1);
+                if (IS_IMM) {   /* immediate */
+                    rs2 = GET_FIELDs(insn, 19, 31);
+#if defined(OPTIM)
+                    if (rs2) {
+#endif
+                        gen_movl_simm_T1(rs2);
+                        gen_op_add_T1_T0();
+#if defined(OPTIM)
+                    }
+#endif
+                } else {                /* register */
                     rs2 = GET_FIELD(insn, 27, 31);
 #if defined(OPTIM)
-		    if (rs2) {
+                    if (rs2) {
 #endif
-			gen_movl_reg_T1(rs2);
-			gen_op_add_T1_T0();
+                        gen_movl_reg_T1(rs2);
+                        gen_op_add_T1_T0();
 #if defined(OPTIM)
-		    }
+                    }
 #endif
                 }
-		gen_op_restore();
-		gen_mov_pc_npc(dc);
-		gen_op_movl_npc_T0();
-		dc->npc = DYNAMIC_PC;
-		goto jmp_insn;
+                gen_op_restore();
+                gen_mov_pc_npc(dc);
+                gen_op_check_align_T0_3();
+                gen_op_movl_npc_T0();
+                dc->npc = DYNAMIC_PC;
+                goto jmp_insn;
 #endif
-	    } else {
+            } else {
                 rs1 = GET_FIELD(insn, 13, 17);
-		gen_movl_reg_T0(rs1);
-                if (IS_IMM) {	/* immediate */
-		    rs2 = GET_FIELDs(insn, 19, 31);
+                gen_movl_reg_T0(rs1);
+                if (IS_IMM) {   /* immediate */
+                    rs2 = GET_FIELDs(insn, 19, 31);
 #if defined(OPTIM)
-		    if (rs2) {
+                    if (rs2) {
 #endif
-			gen_movl_simm_T1(rs2);
-			gen_op_add_T1_T0();
+                        gen_movl_simm_T1(rs2);
+                        gen_op_add_T1_T0();
 #if defined(OPTIM)
-		    }
+                    }
 #endif
-                } else {		/* register */
+                } else {                /* register */
                     rs2 = GET_FIELD(insn, 27, 31);
 #if defined(OPTIM)
-		    if (rs2) {
+                    if (rs2) {
 #endif
-			gen_movl_reg_T1(rs2);
-			gen_op_add_T1_T0();
+                        gen_movl_reg_T1(rs2);
+                        gen_op_add_T1_T0();
 #if defined(OPTIM)
-		    }
+                    }
 #endif
                 }
-		switch (xop) {
-		case 0x38:	/* jmpl */
-		    {
-			if (rd != 0) {
+                switch (xop) {
+                case 0x38:      /* jmpl */
+                    {
+                        if (rd != 0) {
 #ifdef TARGET_SPARC64
                             if (dc->pc == (uint32_t)dc->pc) {
                                 gen_op_movl_T1_im(dc->pc);
@@ -2191,377 +2828,504 @@
                                 gen_op_movq_T1_im64(dc->pc >> 32, dc->pc);
                             }
 #else
-			    gen_op_movl_T1_im(dc->pc);
+                            gen_op_movl_T1_im(dc->pc);
 #endif
-			    gen_movl_T1_reg(rd);
-			}
+                            gen_movl_T1_reg(rd);
+                        }
                         gen_mov_pc_npc(dc);
-			gen_op_movl_npc_T0();
-			dc->npc = DYNAMIC_PC;
-		    }
-		    goto jmp_insn;
+                        gen_op_check_align_T0_3();
+                        gen_op_movl_npc_T0();
+                        dc->npc = DYNAMIC_PC;
+                    }
+                    goto jmp_insn;
 #if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
-		case 0x39:	/* rett, V9 return */
-		    {
-			if (!supervisor(dc))
-			    goto priv_insn;
+                case 0x39:      /* rett, V9 return */
+                    {
+                        if (!supervisor(dc))
+                            goto priv_insn;
                         gen_mov_pc_npc(dc);
-			gen_op_movl_npc_T0();
-			dc->npc = DYNAMIC_PC;
-			gen_op_rett();
-		    }
-		    goto jmp_insn;
+                        gen_op_check_align_T0_3();
+                        gen_op_movl_npc_T0();
+                        dc->npc = DYNAMIC_PC;
+                        gen_op_rett();
+                    }
+                    goto jmp_insn;
 #endif
-		case 0x3b: /* flush */
-		    gen_op_flush_T0();
-		    break;
-		case 0x3c:	/* save */
-		    save_state(dc);
-		    gen_op_save();
-		    gen_movl_T0_reg(rd);
-		    break;
-		case 0x3d:	/* restore */
-		    save_state(dc);
-		    gen_op_restore();
-		    gen_movl_T0_reg(rd);
-		    break;
+                case 0x3b: /* flush */
+                    gen_op_flush_T0();
+                    break;
+                case 0x3c:      /* save */
+                    save_state(dc);
+                    gen_op_save();
+                    gen_movl_T0_reg(rd);
+                    break;
+                case 0x3d:      /* restore */
+                    save_state(dc);
+                    gen_op_restore();
+                    gen_movl_T0_reg(rd);
+                    break;
 #if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
-		case 0x3e:      /* V9 done/retry */
-		    {
-			switch (rd) {
-			case 0:
-			    if (!supervisor(dc))
-				goto priv_insn;
-			    dc->npc = DYNAMIC_PC;
-			    dc->pc = DYNAMIC_PC;
-			    gen_op_done();
-			    goto jmp_insn;
-			case 1:
-			    if (!supervisor(dc))
-				goto priv_insn;
-			    dc->npc = DYNAMIC_PC;
-			    dc->pc = DYNAMIC_PC;
-			    gen_op_retry();
-			    goto jmp_insn;
-			default:
-			    goto illegal_insn;
-			}
-		    }
-		    break;
+                case 0x3e:      /* V9 done/retry */
+                    {
+                        switch (rd) {
+                        case 0:
+                            if (!supervisor(dc))
+                                goto priv_insn;
+                            dc->npc = DYNAMIC_PC;
+                            dc->pc = DYNAMIC_PC;
+                            gen_op_done();
+                            goto jmp_insn;
+                        case 1:
+                            if (!supervisor(dc))
+                                goto priv_insn;
+                            dc->npc = DYNAMIC_PC;
+                            dc->pc = DYNAMIC_PC;
+                            gen_op_retry();
+                            goto jmp_insn;
+                        default:
+                            goto illegal_insn;
+                        }
+                    }
+                    break;
 #endif
-		default:
-		    goto illegal_insn;
-		}
+                default:
+                    goto illegal_insn;
+                }
             }
-	    break;
-	}
-	break;
-    case 3:			/* load/store instructions */
-	{
-	    unsigned int xop = GET_FIELD(insn, 7, 12);
-	    rs1 = GET_FIELD(insn, 13, 17);
-	    gen_movl_reg_T0(rs1);
-	    if (IS_IMM) {	/* immediate */
-		rs2 = GET_FIELDs(insn, 19, 31);
+            break;
+        }
+        break;
+    case 3:                     /* load/store instructions */
+        {
+            unsigned int xop = GET_FIELD(insn, 7, 12);
+            rs1 = GET_FIELD(insn, 13, 17);
+            save_state(dc);
+            gen_movl_reg_T0(rs1);
+            if (xop == 0x3c || xop == 0x3e)
+            {
+                rs2 = GET_FIELD(insn, 27, 31);
+                gen_movl_reg_T1(rs2);
+            }
+            else if (IS_IMM) {       /* immediate */
+                rs2 = GET_FIELDs(insn, 19, 31);
 #if defined(OPTIM)
-		if (rs2 != 0) {
+                if (rs2 != 0) {
 #endif
-		    gen_movl_simm_T1(rs2);
-		    gen_op_add_T1_T0();
+                    gen_movl_simm_T1(rs2);
+                    gen_op_add_T1_T0();
 #if defined(OPTIM)
-		}
+                }
 #endif
-	    } else {		/* register */
-		rs2 = GET_FIELD(insn, 27, 31);
+            } else {            /* register */
+                rs2 = GET_FIELD(insn, 27, 31);
 #if defined(OPTIM)
-		if (rs2 != 0) {
+                if (rs2 != 0) {
 #endif
-		    gen_movl_reg_T1(rs2);
-		    gen_op_add_T1_T0();
+                    gen_movl_reg_T1(rs2);
+                    gen_op_add_T1_T0();
 #if defined(OPTIM)
-		}
+                }
 #endif
-	    }
-	    if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || \
-		    (xop > 0x17 && xop < 0x1d ) || \
-		    (xop > 0x2c && xop < 0x33) || xop == 0x1f) {
-		switch (xop) {
-		case 0x0:	/* load word */
-		    gen_op_ldst(ld);
-		    break;
-		case 0x1:	/* load unsigned byte */
-		    gen_op_ldst(ldub);
-		    break;
-		case 0x2:	/* load unsigned halfword */
-		    gen_op_ldst(lduh);
-		    break;
-		case 0x3:	/* load double word */
-		    gen_op_ldst(ldd);
-		    gen_movl_T0_reg(rd + 1);
-		    break;
-		case 0x9:	/* load signed byte */
-		    gen_op_ldst(ldsb);
-		    break;
-		case 0xa:	/* load signed halfword */
-		    gen_op_ldst(ldsh);
-		    break;
-		case 0xd:	/* ldstub -- XXX: should be atomically */
-		    gen_op_ldst(ldstub);
-		    break;
-		case 0x0f:	/* swap register with memory. Also atomically */
-		    gen_movl_reg_T1(rd);
-		    gen_op_ldst(swap);
-		    break;
-#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
-		case 0x10:	/* load word alternate */
-#ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
+            }
+            if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) ||
+                (xop > 0x17 && xop <= 0x1d ) ||
+                (xop > 0x2c && xop <= 0x33) || xop == 0x1f || xop == 0x3d) {
+                switch (xop) {
+                case 0x0:       /* load word */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
 #endif
-		    gen_op_lda(insn, 1, 4, 0);
-		    break;
-		case 0x11:	/* load unsigned byte alternate */
 #ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
-#endif
-		    gen_op_lduba(insn, 1, 1, 0);
-		    break;
-		case 0x12:	/* load unsigned halfword alternate */
-#ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
-#endif
-		    gen_op_lduha(insn, 1, 2, 0);
-		    break;
-		case 0x13:	/* load double word alternate */
-#ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
-#endif
-		    gen_op_ldda(insn, 1, 8, 0);
-		    gen_movl_T0_reg(rd + 1);
-		    break;
-		case 0x19:	/* load signed byte alternate */
-#ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
-#endif
-		    gen_op_ldsba(insn, 1, 1, 1);
-		    break;
-		case 0x1a:	/* load signed halfword alternate */
-#ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
-#endif
-		    gen_op_ldsha(insn, 1, 2 ,1);
-		    break;
-		case 0x1d:	/* ldstuba -- XXX: should be atomically */
-#ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
-#endif
-		    gen_op_ldstuba(insn, 1, 1, 0);
-		    break;
-		case 0x1f:	/* swap reg with alt. memory. Also atomically */
-#ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
-#endif
-		    gen_movl_reg_T1(rd);
-		    gen_op_swapa(insn, 1, 4, 0);
-		    break;
-
-#ifndef TARGET_SPARC64
-                    /* avoid warnings */
-                    (void) &gen_op_stfa;
-                    (void) &gen_op_stdfa;
-                    (void) &gen_op_ldfa;
-                    (void) &gen_op_lddfa;
+                    gen_op_ldst(ld);
 #else
-#if !defined(CONFIG_USER_ONLY)
-		    (void) &gen_op_cas;
-		    (void) &gen_op_casx;
+                    gen_op_ldst(lduw);
 #endif
+                    break;
+                case 0x1:       /* load unsigned byte */
+                    gen_op_ldst(ldub);
+                    break;
+                case 0x2:       /* load unsigned halfword */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_1();
 #endif
+                    gen_op_ldst(lduh);
+                    break;
+                case 0x3:       /* load double word */
+                    gen_op_check_align_T0_7();
+                    if (rd & 1)
+                        goto illegal_insn;
+                    gen_op_ldst(ldd);
+                    gen_movl_T0_reg(rd + 1);
+                    break;
+                case 0x9:       /* load signed byte */
+                    gen_op_ldst(ldsb);
+                    break;
+                case 0xa:       /* load signed halfword */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_1();
 #endif
-#ifdef TARGET_SPARC64
-		case 0x08: /* V9 ldsw */
-		    gen_op_ldst(ldsw);
-		    break;
-		case 0x0b: /* V9 ldx */
-		    gen_op_ldst(ldx);
-		    break;
-		case 0x18: /* V9 ldswa */
-		    gen_op_ldswa(insn, 1, 4, 1);
-		    break;
-		case 0x1b: /* V9 ldxa */
-		    gen_op_ldxa(insn, 1, 8, 0);
-		    break;
-		case 0x2d: /* V9 prefetch, no effect */
-		    goto skip_move;
-		case 0x30: /* V9 ldfa */
-		    gen_op_ldfa(insn, 1, 8, 0); // XXX
-		    break;
-		case 0x33: /* V9 lddfa */
-		    gen_op_lddfa(insn, 1, 8, 0); // XXX
-
-		    break;
-		case 0x3d: /* V9 prefetcha, no effect */
-		    goto skip_move;
-		case 0x32: /* V9 ldqfa */
-		    goto nfpu_insn;
+                    gen_op_ldst(ldsh);
+                    break;
+                case 0xd:       /* ldstub -- XXX: should be atomically */
+                    gen_op_ldst(ldstub);
+                    break;
+                case 0x0f:      /* swap register with memory. Also atomically */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
 #endif
-		default:
-		    goto illegal_insn;
-		}
-		gen_movl_T1_reg(rd);
-#ifdef TARGET_SPARC64
-	    skip_move: ;
-#endif
-	    } else if (xop >= 0x20 && xop < 0x24) {
-                if (gen_trap_ifnofpu(dc))
-                    goto jmp_insn;
-		switch (xop) {
-		case 0x20:	/* load fpreg */
-		    gen_op_ldst(ldf);
-		    gen_op_store_FT0_fpr(rd);
-		    break;
-		case 0x21:	/* load fsr */
-		    gen_op_ldst(ldf);
-		    gen_op_ldfsr();
-		    break;
-		case 0x22:      /* load quad fpreg */
-		    goto nfpu_insn;
-		case 0x23:	/* load double fpreg */
-		    gen_op_ldst(lddf);
-		    gen_op_store_DT0_fpr(DFPREG(rd));
-		    break;
-		default:
-		    goto illegal_insn;
-		}
-	    } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \
-		       xop == 0xe || xop == 0x1e) {
-		gen_movl_reg_T1(rd);
-		switch (xop) {
-		case 0x4:
-		    gen_op_ldst(st);
-		    break;
-		case 0x5:
-		    gen_op_ldst(stb);
-		    break;
-		case 0x6:
-		    gen_op_ldst(sth);
-		    break;
-		case 0x7:
-                    flush_T2(dc);
-		    gen_movl_reg_T2(rd + 1);
-		    gen_op_ldst(std);
-		    break;
+                    gen_movl_reg_T1(rd);
+                    gen_op_ldst(swap);
+                    break;
 #if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
-		case 0x14:
+                case 0x10:      /* load word alternate */
 #ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#elif CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
 #endif
-		    gen_op_sta(insn, 0, 4, 0);
+                    gen_ld_asi(insn, 4, 0);
                     break;
-		case 0x15:
+                case 0x11:      /* load unsigned byte alternate */
 #ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
 #endif
-		    gen_op_stba(insn, 0, 1, 0);
+                    gen_ld_asi(insn, 1, 0);
                     break;
-		case 0x16:
+                case 0x12:      /* load unsigned halfword alternate */
 #ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#elif CONFIG_USER_ONLY
+                    gen_op_check_align_T0_1();
 #endif
-		    gen_op_stha(insn, 0, 2, 0);
+                    gen_ld_asi(insn, 2, 0);
                     break;
-		case 0x17:
+                case 0x13:      /* load double word alternate */
 #ifndef TARGET_SPARC64
-		    if (!supervisor(dc))
-			goto priv_insn;
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
 #endif
+                    if (rd & 1)
+                        goto illegal_insn;
+                    gen_op_check_align_T0_7();
+                    gen_ldda_asi(insn);
+                    gen_movl_T0_reg(rd + 1);
+                    break;
+                case 0x19:      /* load signed byte alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    gen_ld_asi(insn, 1, 1);
+                    break;
+                case 0x1a:      /* load signed halfword alternate */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#elif CONFIG_USER_ONLY
+                    gen_op_check_align_T0_1();
+#endif
+                    gen_ld_asi(insn, 2, 1);
+                    break;
+                case 0x1d:      /* ldstuba -- XXX: should be atomically */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    gen_ldstub_asi(insn);
+                    break;
+                case 0x1f:      /* swap reg with alt. memory. Also atomically */
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#elif CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_movl_reg_T1(rd);
+                    gen_swap_asi(insn);
+                    break;
+
+#ifndef TARGET_SPARC64
+                case 0x30: /* ldc */
+                case 0x31: /* ldcsr */
+                case 0x33: /* lddc */
+                    goto ncp_insn;
+#endif
+#endif
+#ifdef TARGET_SPARC64
+                case 0x08: /* V9 ldsw */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_op_ldst(ldsw);
+                    break;
+                case 0x0b: /* V9 ldx */
+                    gen_op_check_align_T0_7();
+                    gen_op_ldst(ldx);
+                    break;
+                case 0x18: /* V9 ldswa */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_ld_asi(insn, 4, 1);
+                    break;
+                case 0x1b: /* V9 ldxa */
+                    gen_op_check_align_T0_7();
+                    gen_ld_asi(insn, 8, 0);
+                    break;
+                case 0x2d: /* V9 prefetch, no effect */
+                    goto skip_move;
+                case 0x30: /* V9 ldfa */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_ldf_asi(insn, 4);
+                    goto skip_move;
+                case 0x33: /* V9 lddfa */
+                    gen_op_check_align_T0_3();
+                    gen_ldf_asi(insn, 8);
+                    goto skip_move;
+                case 0x3d: /* V9 prefetcha, no effect */
+                    goto skip_move;
+                case 0x32: /* V9 ldqfa */
+                    goto nfpu_insn;
+#endif
+                default:
+                    goto illegal_insn;
+                }
+                gen_movl_T1_reg(rd);
+#ifdef TARGET_SPARC64
+            skip_move: ;
+#endif
+            } else if (xop >= 0x20 && xop < 0x24) {
+                if (gen_trap_ifnofpu(dc))
+                    goto jmp_insn;
+                switch (xop) {
+                case 0x20:      /* load fpreg */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_op_ldst(ldf);
+                    gen_op_store_FT0_fpr(rd);
+                    break;
+                case 0x21:      /* load fsr */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_op_ldst(ldf);
+                    gen_op_ldfsr();
+                    break;
+                case 0x22:      /* load quad fpreg */
+                    goto nfpu_insn;
+                case 0x23:      /* load double fpreg */
+                    gen_op_check_align_T0_7();
+                    gen_op_ldst(lddf);
+                    gen_op_store_DT0_fpr(DFPREG(rd));
+                    break;
+                default:
+                    goto illegal_insn;
+                }
+            } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \
+                       xop == 0xe || xop == 0x1e) {
+                gen_movl_reg_T1(rd);
+                switch (xop) {
+                case 0x4:
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_op_ldst(st);
+                    break;
+                case 0x5:
+                    gen_op_ldst(stb);
+                    break;
+                case 0x6:
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_1();
+#endif
+                    gen_op_ldst(sth);
+                    break;
+                case 0x7:
+                    if (rd & 1)
+                        goto illegal_insn;
+                    gen_op_check_align_T0_7();
                     flush_T2(dc);
-		    gen_movl_reg_T2(rd + 1);
-		    gen_op_stda(insn, 0, 8, 0);
+                    gen_movl_reg_T2(rd + 1);
+                    gen_op_ldst(std);
+                    break;
+#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
+                case 0x14:
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_st_asi(insn, 4);
+                    break;
+                case 0x15:
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    gen_st_asi(insn, 1);
+                    break;
+                case 0x16:
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_1();
+#endif
+                    gen_st_asi(insn, 2);
+                    break;
+                case 0x17:
+#ifndef TARGET_SPARC64
+                    if (IS_IMM)
+                        goto illegal_insn;
+                    if (!supervisor(dc))
+                        goto priv_insn;
+#endif
+                    if (rd & 1)
+                        goto illegal_insn;
+                    gen_op_check_align_T0_7();
+                    flush_T2(dc);
+                    gen_movl_reg_T2(rd + 1);
+                    gen_stda_asi(insn);
                     break;
 #endif
 #ifdef TARGET_SPARC64
-		case 0x0e: /* V9 stx */
-		    gen_op_ldst(stx);
-		    break;
-		case 0x1e: /* V9 stxa */
-		    gen_op_stxa(insn, 0, 8, 0); // XXX
-		    break;
+                case 0x0e: /* V9 stx */
+                    gen_op_check_align_T0_7();
+                    gen_op_ldst(stx);
+                    break;
+                case 0x1e: /* V9 stxa */
+                    gen_op_check_align_T0_7();
+                    gen_st_asi(insn, 8);
+                    break;
 #endif
-		default:
-		    goto illegal_insn;
-		}
-	    } else if (xop > 0x23 && xop < 0x28) {
+                default:
+                    goto illegal_insn;
+                }
+            } else if (xop > 0x23 && xop < 0x28) {
                 if (gen_trap_ifnofpu(dc))
                     goto jmp_insn;
-		switch (xop) {
-		case 0x24:
+                switch (xop) {
+                case 0x24:
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
                     gen_op_load_fpr_FT0(rd);
-		    gen_op_ldst(stf);
-		    break;
-		case 0x25: /* stfsr, V9 stxfsr */
-		    gen_op_stfsr();
-		    gen_op_ldst(stf);
-		    break;
-		case 0x26: /* stdfq */
-		    goto nfpu_insn;
-		case 0x27:
-                    gen_op_load_fpr_DT0(DFPREG(rd));
-		    gen_op_ldst(stdf);
-		    break;
-		default:
-		    goto illegal_insn;
-		}
-	    } else if (xop > 0x33 && xop < 0x3f) {
-#ifdef TARGET_SPARC64
-		switch (xop) {
-		case 0x34: /* V9 stfa */
-		    gen_op_stfa(insn, 0, 0, 0); // XXX
-		    break;
-		case 0x37: /* V9 stdfa */
-		    gen_op_stdfa(insn, 0, 0, 0); // XXX
-		    break;
-		case 0x3c: /* V9 casa */
-		    gen_op_casa(insn, 0, 4, 0); // XXX
-		    break;
-		case 0x3e: /* V9 casxa */
-		    gen_op_casxa(insn, 0, 8, 0); // XXX
-		    break;
-		case 0x36: /* V9 stqfa */
-		    goto nfpu_insn;
-		default:
-		    goto illegal_insn;
-		}
-#else
-		goto illegal_insn;
+                    gen_op_ldst(stf);
+                    break;
+                case 0x25: /* stfsr, V9 stxfsr */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
 #endif
+                    gen_op_stfsr();
+                    gen_op_ldst(stf);
+                    break;
+#if !defined(CONFIG_USER_ONLY)
+                case 0x26: /* stdfq */
+                    if (!supervisor(dc))
+                        goto priv_insn;
+                    if (gen_trap_ifnofpu(dc))
+                        goto jmp_insn;
+                    goto nfq_insn;
+#endif
+                case 0x27:
+                    gen_op_check_align_T0_7();
+                    gen_op_load_fpr_DT0(DFPREG(rd));
+                    gen_op_ldst(stdf);
+                    break;
+                default:
+                    goto illegal_insn;
+                }
+            } else if (xop > 0x33 && xop < 0x3f) {
+                switch (xop) {
+#ifdef TARGET_SPARC64
+                case 0x34: /* V9 stfa */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    gen_op_load_fpr_FT0(rd);
+                    gen_stf_asi(insn, 4);
+                    break;
+                case 0x37: /* V9 stdfa */
+                    gen_op_check_align_T0_3();
+                    gen_op_load_fpr_DT0(DFPREG(rd));
+                    gen_stf_asi(insn, 8);
+                    break;
+                case 0x3c: /* V9 casa */
+#ifdef CONFIG_USER_ONLY
+                    gen_op_check_align_T0_3();
+#endif
+                    flush_T2(dc);
+                    gen_movl_reg_T2(rd);
+                    gen_cas_asi(insn);
+                    gen_movl_T1_reg(rd);
+                    break;
+                case 0x3e: /* V9 casxa */
+                    gen_op_check_align_T0_7();
+                    flush_T2(dc);
+                    gen_movl_reg_T2(rd);
+                    gen_casx_asi(insn);
+                    gen_movl_T1_reg(rd);
+                    break;
+                case 0x36: /* V9 stqfa */
+                    goto nfpu_insn;
+#else
+                case 0x34: /* stc */
+                case 0x35: /* stcsr */
+                case 0x36: /* stdcq */
+                case 0x37: /* stdc */
+                    goto ncp_insn;
+#endif
+                default:
+                    goto illegal_insn;
+                }
             }
-	    else
-		goto illegal_insn;
-	}
-	break;
+            else
+                goto illegal_insn;
+        }
+        break;
     }
     /* default case for non jump instructions */
     if (dc->npc == DYNAMIC_PC) {
-	dc->pc = DYNAMIC_PC;
-	gen_op_next_insn();
+        dc->pc = DYNAMIC_PC;
+        gen_op_next_insn();
     } else if (dc->npc == JUMP_PC) {
         /* we can do a static jump */
-        gen_branch2(dc, (long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]);
+        gen_branch2(dc, dc->jump_pc[0], dc->jump_pc[1]);
         dc->is_br = 1;
     } else {
-	dc->pc = dc->npc;
-	dc->npc = dc->npc + 4;
+        dc->pc = dc->npc;
+        dc->npc = dc->npc + 4;
     }
  jmp_insn:
     return;
@@ -2581,10 +3345,25 @@
     save_state(dc);
     gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
     dc->is_br = 1;
+    return;
+#if !defined(CONFIG_USER_ONLY)
+ nfq_insn:
+    save_state(dc);
+    gen_op_fpexception_im(FSR_FTT_SEQ_ERROR);
+    dc->is_br = 1;
+    return;
+#endif
+#ifndef TARGET_SPARC64
+ ncp_insn:
+    save_state(dc);
+    gen_op_exception(TT_NCP_INSN);
+    dc->is_br = 1;
+    return;
+#endif
 }
 
 static inline int gen_intermediate_code_internal(TranslationBlock * tb,
-						 int spc, CPUSPARCState *env)
+                                                 int spc, CPUSPARCState *env)
 {
     target_ulong pc_start, last_pc;
     uint16_t *gen_opc_end;
@@ -2617,12 +3396,12 @@
         if (env->nb_breakpoints > 0) {
             for(j = 0; j < env->nb_breakpoints; j++) {
                 if (env->breakpoints[j] == dc->pc) {
-		    if (dc->pc != pc_start)
-			save_state(dc);
+                    if (dc->pc != pc_start)
+                        save_state(dc);
                     gen_op_debug();
-		    gen_op_movl_T0_0();
-		    gen_op_exit_tb();
-		    dc->is_br = 1;
+                    gen_op_movl_T0_0();
+                    gen_op_exit_tb();
+                    dc->is_br = 1;
                     goto exit_gen_loop;
                 }
             }
@@ -2640,14 +3419,14 @@
                 gen_opc_instr_start[lj] = 1;
             }
         }
-	last_pc = dc->pc;
-	disas_sparc_insn(dc);
+        last_pc = dc->pc;
+        disas_sparc_insn(dc);
 
-	if (dc->is_br)
-	    break;
-	/* if the next PC is different, we abort now */
-	if (dc->pc != (last_pc + 4))
-	    break;
+        if (dc->is_br)
+            break;
+        /* if the next PC is different, we abort now */
+        if (dc->pc != (last_pc + 4))
+            break;
         /* if we reach a page boundary, we stop generation so that the
            PC of a TT_TFAULT exception is always in the right page */
         if ((dc->pc & (TARGET_PAGE_SIZE - 1)) == 0)
@@ -2661,14 +3440,14 @@
             break;
         }
     } while ((gen_opc_ptr < gen_opc_end) &&
-	     (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
+             (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
 
  exit_gen_loop:
     if (!dc->is_br) {
-        if (dc->pc != DYNAMIC_PC && 
+        if (dc->pc != DYNAMIC_PC &&
             (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
             /* static PC and NPC: we can use direct chaining */
-            gen_branch(dc, (long)tb, dc->pc, dc->npc);
+            gen_branch(dc, dc->pc, dc->npc);
         } else {
             if (dc->pc != DYNAMIC_PC)
                 gen_jmp_im(dc->pc);
@@ -2683,7 +3462,6 @@
         lj++;
         while (lj <= j)
             gen_opc_instr_start[lj++] = 0;
-        tb->size = 0;
 #if 0
         if (loglevel > 0) {
             page_dump(logfile);
@@ -2696,10 +3474,10 @@
     }
 #ifdef DEBUG_DISAS
     if (loglevel & CPU_LOG_TB_IN_ASM) {
-	fprintf(logfile, "--------------\n");
-	fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-	target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0);
-	fprintf(logfile, "\n");
+        fprintf(logfile, "--------------\n");
+        fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+        target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0);
+        fprintf(logfile, "\n");
         if (loglevel & CPU_LOG_TB_OP) {
             fprintf(logfile, "OP:\n");
             dump_ops(gen_opc_buf, gen_opparam_buf);
@@ -2724,7 +3502,6 @@
 
 void cpu_reset(CPUSPARCState *env)
 {
-    memset(env, 0, sizeof(*env));
     tlb_flush(env, 1);
     env->cwp = 0;
     env->wim = 1;
@@ -2732,20 +3509,22 @@
 #if defined(CONFIG_USER_ONLY)
     env->user_mode_only = 1;
 #ifdef TARGET_SPARC64
-    env->cleanwin = NWINDOWS - 1;
-    env->cansave = NWINDOWS - 1;
+    env->cleanwin = NWINDOWS - 2;
+    env->cansave = NWINDOWS - 2;
+    env->pstate = PS_RMO | PS_PEF | PS_IE;
+    env->asi = 0x82; // Primary no-fault
 #endif
 #else
+    env->psret = 0;
     env->psrs = 1;
     env->psrps = 1;
-    env->gregs[1] = ram_size;
 #ifdef TARGET_SPARC64
     env->pstate = PS_PRIV;
-    env->version = GET_VER(env);
     env->pc = 0x1fff0000000ULL;
 #else
-    env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */
-    env->pc = 0xffd00000;
+    env->pc = 0;
+    env->mmuregs[0] &= ~(MMU_E | MMU_NF);
+    env->mmuregs[0] |= MMU_BM;
 #endif
     env->npc = env->pc + 4;
 #endif
@@ -2757,15 +3536,99 @@
 
     env = qemu_mallocz(sizeof(CPUSPARCState));
     if (!env)
-	return NULL;
+        return NULL;
     cpu_exec_init(env);
     cpu_reset(env);
     return (env);
 }
 
+static const sparc_def_t sparc_defs[] = {
+#ifdef TARGET_SPARC64
+    {
+        .name = "TI UltraSparc II",
+        .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0 << 24)
+                       | (MAXTL << 8) | (NWINDOWS - 1)),
+        .fpu_version = 0x00000000,
+        .mmu_version = 0,
+    },
+#else
+    {
+        .name = "Fujitsu MB86904",
+        .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
+    },
+    {
+        .name = "Fujitsu MB86907",
+        .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+        .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+        .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
+    },
+    {
+        .name = "TI MicroSparc I",
+        .iu_version = 0x41000000,
+        .fpu_version = 4 << 17,
+        .mmu_version = 0x41000000,
+    },
+    {
+        .name = "TI SuperSparc II",
+        .iu_version = 0x40000000,
+        .fpu_version = 0 << 17,
+        .mmu_version = 0x04000000,
+    },
+    {
+        .name = "Ross RT620",
+        .iu_version = 0x1e000000,
+        .fpu_version = 1 << 17,
+        .mmu_version = 0x17000000,
+    },
+#endif
+};
+
+int sparc_find_by_name(const unsigned char *name, const sparc_def_t **def)
+{
+    int ret;
+    unsigned int i;
+
+    ret = -1;
+    *def = NULL;
+    for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) {
+        if (strcasecmp(name, sparc_defs[i].name) == 0) {
+            *def = &sparc_defs[i];
+            ret = 0;
+            break;
+        }
+    }
+
+    return ret;
+}
+
+void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+    unsigned int i;
+
+    for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) {
+        (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x\n",
+                       sparc_defs[i].name,
+                       sparc_defs[i].iu_version,
+                       sparc_defs[i].fpu_version,
+                       sparc_defs[i].mmu_version);
+    }
+}
+
+int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def)
+{
+    env->version = def->iu_version;
+    env->fsr = def->fpu_version;
+#if !defined(TARGET_SPARC64)
+    env->mmuregs[0] |= def->mmu_version;
+#endif
+    return 0;
+}
+
 #define GET_FLAG(a,b) ((env->psr & a)?b:'-')
 
-void cpu_dump_state(CPUState *env, FILE *f, 
+void cpu_dump_state(CPUState *env, FILE *f,
                     int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                     int flags)
 {
@@ -2774,22 +3637,22 @@
     cpu_fprintf(f, "pc: " TARGET_FMT_lx "  npc: " TARGET_FMT_lx "\n", env->pc, env->npc);
     cpu_fprintf(f, "General Registers:\n");
     for (i = 0; i < 4; i++)
-	cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]);
+        cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]);
     cpu_fprintf(f, "\n");
     for (; i < 8; i++)
-	cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]);
+        cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]);
     cpu_fprintf(f, "\nCurrent Register Window:\n");
     for (x = 0; x < 3; x++) {
-	for (i = 0; i < 4; i++)
-	    cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t",
-		    (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i,
-		    env->regwptr[i + x * 8]);
-	cpu_fprintf(f, "\n");
-	for (; i < 8; i++)
-	    cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t",
-		    (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i,
-		    env->regwptr[i + x * 8]);
-	cpu_fprintf(f, "\n");
+        for (i = 0; i < 4; i++)
+            cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t",
+                    (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i,
+                    env->regwptr[i + x * 8]);
+        cpu_fprintf(f, "\n");
+        for (; i < 8; i++)
+            cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t",
+                    (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i,
+                    env->regwptr[i + x * 8]);
+        cpu_fprintf(f, "\n");
     }
     cpu_fprintf(f, "\nFloating Point Registers:\n");
     for (i = 0; i < 32; i++) {
@@ -2800,23 +3663,23 @@
             cpu_fprintf(f, "\n");
     }
 #ifdef TARGET_SPARC64
-    cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d\n",
-		env->pstate, GET_CCR(env), env->asi, env->tl);
+    cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n",
+                env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs);
     cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d cleanwin %d cwp %d\n",
-		env->cansave, env->canrestore, env->otherwin, env->wstate,
-		env->cleanwin, NWINDOWS - 1 - env->cwp);
+                env->cansave, env->canrestore, env->otherwin, env->wstate,
+                env->cleanwin, NWINDOWS - 1 - env->cwp);
 #else
     cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env),
-	    GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
-	    GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'),
-	    env->psrs?'S':'-', env->psrps?'P':'-', 
-	    env->psret?'E':'-', env->wim);
+            GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
+            GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'),
+            env->psrs?'S':'-', env->psrps?'P':'-',
+            env->psret?'E':'-', env->wim);
 #endif
     cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env));
 }
 
 #if defined(CONFIG_USER_ONLY)
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     return addr;
 }
@@ -2826,7 +3689,7 @@
                                  int *access_index, target_ulong address, int rw,
                                  int is_user);
 
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
 {
     target_phys_addr_t phys_addr;
     int prot, access_index;
@@ -2834,6 +3697,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
diff --git a/tests/Makefile b/tests/Makefile
index 79a3d55..ec3a93c 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -82,6 +82,9 @@
 hello-arm.o: hello-arm.c
 	arm-linux-gcc -Wall -g -O2 -c -o $@ $<
 
+test-arm-iwmmxt: test-arm-iwmmxt.s
+	cpp < $< | arm-linux-gnu-gcc -Wall -static -march=iwmmxt -mabi=aapcs -x assembler - -o $@
+
 # MIPS test
 hello-mips: hello-mips.c
 	mips-linux-gnu-gcc -nostdlib -static -mno-abicalls -fno-PIC -mabi=32 -Wall -Wextra -g -O2 -o $@ $<
diff --git a/tests/hello-arm.c b/tests/hello-arm.c
index f84e6cb..e0daa7a 100644
--- a/tests/hello-arm.c
+++ b/tests/hello-arm.c
@@ -83,7 +83,7 @@
   	: "r0","r1","r2","r3","lr");							\
   __syscall_return(type,__res);								\
 }
-  
+
 
 #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)	\
 type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) {			\
diff --git a/tests/linux-test.c b/tests/linux-test.c
index 6ca9029..2f82def 100644
--- a/tests/linux-test.c
+++ b/tests/linux-test.c
@@ -1,6 +1,6 @@
 /*
  *  linux and CPU test
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -58,7 +58,7 @@
 int __chk_error(const char *filename, int line, int ret)
 {
     if (ret < 0) {
-        error1(filename, line, "%m (ret=%d, errno=%d)", 
+        error1(filename, line, "%m (ret=%d, errno=%d)",
                ret, errno);
     }
     return ret;
@@ -93,11 +93,11 @@
 
     if (getcwd(cur_dir, sizeof(cur_dir)) == NULL)
         error("getcwd");
-    
+
     chk_error(mkdir(TESTPATH, 0755));
-    
+
     chk_error(chdir(TESTPATH));
-    
+
     /* open/read/write/close/readv/writev/lseek */
 
     fd = chk_error(open("file1", O_WRONLY | O_TRUNC | O_CREAT, 0644));
@@ -124,7 +124,7 @@
         error("read");
     if (memcmp(buf, buf2, FILE_BUF_SIZE) != 0)
         error("memcmp");
-    
+
 #define FOFFSET 16
     ret = chk_error(lseek(fd, FOFFSET, SEEK_SET));
     if (ret != 16)
@@ -138,7 +138,7 @@
         error("readv");
     if (memcmp(buf + FOFFSET, buf3, FILE_BUF_SIZE - FOFFSET) != 0)
         error("memcmp");
-    
+
     chk_error(close(fd));
 
     /* access */
@@ -171,18 +171,18 @@
     chk_error(ftruncate(fd, 50));
     chk_error(fstat(fd, &st));
     chk_error(close(fd));
-    
+
     if (st.st_size != 50)
         error("stat size");
     if (!S_ISREG(st.st_mode))
         error("stat mode");
-    
+
     /* symlink/lstat */
     chk_error(symlink("file2", "file3"));
     chk_error(lstat("file3", &st));
     if (!S_ISLNK(st.st_mode))
         error("stat mode");
-    
+
     /* getdents */
     dir = opendir(TESTPATH);
     if (!dir)
@@ -241,7 +241,7 @@
     ti = tv2.tv_sec - tv.tv_sec;
     if (ti >= 2)
         error("gettimeofday");
-    
+
     chk_error(getrusage(RUSAGE_SELF, &rusg1));
     for(i = 0;i < 10000; i++);
     chk_error(getrusage(RUSAGE_SELF, &rusg2));
@@ -272,7 +272,7 @@
 {
     int len;
     len = strlen(buf);
-    if (len < buf_size) 
+    if (len < buf_size)
         pstrcpy(buf + len, buf_size - len, s);
     return buf;
 }
@@ -327,7 +327,7 @@
     chk_error(getsockopt(server_fd, SOL_SOCKET, SO_TYPE, &val, &len));
     if (val != SOCK_STREAM)
         error("getsockopt");
-    
+
     pid = chk_error(fork());
     if (pid == 0) {
         client_fd = client_socket();
@@ -419,11 +419,11 @@
     int pid1, pid2, status1, status2;
 
     stack1 = malloc(STACK_SIZE);
-    pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE, 
+    pid1 = chk_error(clone(thread1_func, stack1 + STACK_SIZE,
                            CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello1"));
 
     stack2 = malloc(STACK_SIZE);
-    pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE, 
+    pid2 = chk_error(clone(thread2_func, stack2 + STACK_SIZE,
                            CLONE_VM | CLONE_FS | CLONE_FILES | SIGCHLD, "hello2"));
 
     while (waitpid(pid1, &status1, 0) != pid1);
@@ -465,7 +465,7 @@
     sigemptyset(&act.sa_mask);
     act.sa_flags = 0;
     chk_error(sigaction(SIGALRM, &act, NULL));
-    
+
     it.it_interval.tv_sec = 0;
     it.it_interval.tv_usec = 10 * 1000;
     it.it_value.tv_sec = 0;
@@ -475,7 +475,7 @@
     if (oit.it_value.tv_sec != it.it_value.tv_sec ||
         oit.it_value.tv_usec != it.it_value.tv_usec)
         error("itimer");
-    
+
     while (alarm_count < 5) {
         usleep(10 * 1000);
     }
@@ -498,7 +498,7 @@
     if (setjmp(jmp_env) == 0) {
         *(uint8_t *)0 = 0;
     }
-    
+
     act.sa_handler = SIG_DFL;
     sigemptyset(&act.sa_mask);
     act.sa_flags = 0;
diff --git a/tests/qruncom.c b/tests/qruncom.c
index 421e6a9..ad0d938 100644
--- a/tests/qruncom.c
+++ b/tests/qruncom.c
@@ -59,7 +59,7 @@
     return 0;
 }
 
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl, 
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
                      unsigned long addr, unsigned int sel)
 {
     unsigned int e1, e2;
@@ -141,7 +141,7 @@
     *(uint16_t *)seg_to_linear(env->segs[R_SS].selector, env->regs[R_ESP]) = val;
 }
 
-static void host_segv_handler(int host_signum, siginfo_t *info, 
+static void host_segv_handler(int host_signum, siginfo_t *info,
                               void *puc)
 {
     if (cpu_signal_handler(host_signum, info, puc)) {
@@ -160,9 +160,9 @@
     if (argc != 2)
         usage();
     filename = argv[1];
-    
-    vm86_mem = mmap((void *)0x00000000, 0x110000, 
-                    PROT_WRITE | PROT_READ | PROT_EXEC, 
+
+    vm86_mem = mmap((void *)0x00000000, 0x110000,
+                    PROT_WRITE | PROT_READ | PROT_EXEC,
                     MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
     if (vm86_mem == MAP_FAILED) {
         perror("mmap");
@@ -185,7 +185,7 @@
     /* install exception handler for CPU emulator */
     {
         struct sigaction act;
-        
+
         sigfillset(&act.sa_mask);
         act.sa_flags = SA_SIGINFO;
         //        act.sa_flags |= SA_ONSTACK;
@@ -218,23 +218,23 @@
     /* flags setup : we activate the IRQs by default as in user
        mode. We also activate the VM86 flag to run DOS code */
     env->eflags |= IF_MASK | VM_MASK;
-    
+
     /* init basic registers */
     env->eip = 0x100;
     env->regs[R_ESP] = 0xfffe;
     seg = (COM_BASE_ADDR - 0x100) >> 4;
 
-    cpu_x86_load_seg_cache(env, R_CS, seg, 
+    cpu_x86_load_seg_cache(env, R_CS, seg,
                            (seg << 4), 0xffff, 0);
-    cpu_x86_load_seg_cache(env, R_SS, seg, 
+    cpu_x86_load_seg_cache(env, R_SS, seg,
                            (seg << 4), 0xffff, 0);
-    cpu_x86_load_seg_cache(env, R_DS, seg, 
+    cpu_x86_load_seg_cache(env, R_DS, seg,
                            (seg << 4), 0xffff, 0);
-    cpu_x86_load_seg_cache(env, R_ES, seg, 
+    cpu_x86_load_seg_cache(env, R_ES, seg,
                            (seg << 4), 0xffff, 0);
-    cpu_x86_load_seg_cache(env, R_FS, seg, 
+    cpu_x86_load_seg_cache(env, R_FS, seg,
                            (seg << 4), 0xffff, 0);
-    cpu_x86_load_seg_cache(env, R_GS, seg, 
+    cpu_x86_load_seg_cache(env, R_GS, seg,
                            (seg << 4), 0xffff, 0);
 
     /* exception support */
@@ -260,7 +260,7 @@
     set_idt(17, 0);
     set_idt(18, 0);
     set_idt(19, 0);
-        
+
     /* put return code */
     *seg_to_linear(env->segs[R_CS].selector, 0) = 0xb4; /* mov ah, $0 */
     *seg_to_linear(env->segs[R_CS].selector, 1) = 0x00;
@@ -275,7 +275,7 @@
     env->regs[R_EDI] = 0xfffe;
 
     /* inform the emulator of the mmaped memory */
-    page_set_flags(0x00000000, 0x110000, 
+    page_set_flags(0x00000000, 0x110000,
                    PAGE_WRITE | PAGE_READ | PAGE_EXEC | PAGE_VALID);
 
     for(;;) {
diff --git a/tests/runcom.c b/tests/runcom.c
index 43deeca..cbbaf31 100644
--- a/tests/runcom.c
+++ b/tests/runcom.c
@@ -51,7 +51,7 @@
 
 void dump_regs(struct vm86_regs *r)
 {
-    fprintf(stderr, 
+    fprintf(stderr,
             "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
             "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
             "EIP=%08lx EFL=%08lx\n"
@@ -80,9 +80,9 @@
     if (argc != 2)
         usage();
     filename = argv[1];
-    
-    vm86_mem = mmap((void *)0x00000000, 0x110000, 
-                    PROT_WRITE | PROT_READ | PROT_EXEC, 
+
+    vm86_mem = mmap((void *)0x00000000, 0x110000,
+                    PROT_WRITE | PROT_READ | PROT_EXEC,
                     MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
     if (vm86_mem == MAP_FAILED) {
         perror("mmap");
@@ -147,7 +147,7 @@
         case VM86_INTx:
             {
                 int int_num, ah;
-                
+
                 int_num = VM86_ARG(ret);
                 if (int_num != 0x21)
                     goto unknown_int;
diff --git a/tests/test-arm-iwmmxt.s b/tests/test-arm-iwmmxt.s
new file mode 100644
index 0000000..d647f94
--- /dev/null
+++ b/tests/test-arm-iwmmxt.s
@@ -0,0 +1,49 @@
+@ Checks whether iwMMXt is functional.
+.code	32
+.globl	main
+
+main:
+ldr	r0, =data0
+ldr	r1, =data1
+ldr	r2, =data2
+#ifndef FPA
+wldrd	wr0, [r0, #0]
+wldrd	wr1, [r0, #8]
+wldrd	wr2, [r1, #0]
+wldrd	wr3, [r1, #8]
+wsubb	wr2, wr2, wr0
+wsubb	wr3, wr3, wr1
+wldrd	wr0, [r2, #0]
+wldrd	wr1, [r2, #8]
+waddb	wr0, wr0, wr2
+waddb	wr1, wr1, wr3
+wstrd	wr0, [r2, #0]
+wstrd	wr1, [r2, #8]
+#else
+ldfe	f0, [r0, #0]
+ldfe	f1, [r0, #8]
+ldfe	f2, [r1, #0]
+ldfe	f3, [r1, #8]
+adfdp	f2, f2, f0
+adfdp	f3, f3, f1
+ldfe	f0, [r2, #0]
+ldfe	f1, [r2, #8]
+adfd	f0, f0, f2
+adfd	f1, f1, f3
+stfe	f0, [r2, #0]
+stfe	f1, [r2, #8]
+#endif
+mov	r0, #1
+mov	r1, r2
+mov	r2, #0x11
+swi	#0x900004
+mov	r0, #0
+swi	#0x900001
+
+.data
+data0:
+.string	"aaaabbbbccccdddd"
+data1:
+.string	"bbbbccccddddeeee"
+data2:
+.string	"hvLLWs\x1fsdrs9\x1fNJ-\n"
diff --git a/tests/test-i386-code16.S b/tests/test-i386-code16.S
index e400e73..8f51052 100644
--- a/tests/test-i386-code16.S
+++ b/tests/test-i386-code16.S
@@ -7,7 +7,7 @@
 code16_start:
 
         .globl code16_func1
-        
+
         /* basic test */
 code16_func1 = . - code16_start
         mov $1, %eax
@@ -24,7 +24,7 @@
         pop %ax
         data32 lret
 
-/* test various jmp opcodes */        
+/* test various jmp opcodes */
         .globl code16_func3
 code16_func3 = . - code16_start
         jmp 1f
@@ -36,9 +36,9 @@
         jz 2f
         add $2, %ax
 2:
-        
+
         call myfunc
-        
+
         lcall $CS_SEG, $(myfunc2 - code16_start)
 
         ljmp $CS_SEG, $(myjmp1 - code16_start)
@@ -50,7 +50,7 @@
 myjmp2_next:
 
         data32 lret
-        
+
 myfunc2_addr:
         .short myfunc2 - code16_start
         .short CS_SEG
diff --git a/tests/test-i386-muldiv.h b/tests/test-i386-muldiv.h
index fd0d991..015f59e 100644
--- a/tests/test-i386-muldiv.h
+++ b/tests/test-i386-muldiv.h
@@ -1,5 +1,5 @@
 
-void glue(glue(test_, OP), b)(long op0, long op1) 
+void glue(glue(test_, OP), b)(long op0, long op1)
 {
     long res, s1, s0, flags;
     s0 = op0;
@@ -8,7 +8,7 @@
     flags = 0;
     asm ("push %4\n\t"
          "popf\n\t"
-         stringify(OP)"b %b2\n\t" 
+         stringify(OP)"b %b2\n\t"
          "pushf\n\t"
          "pop %1\n\t"
          : "=a" (res), "=g" (flags)
@@ -17,7 +17,7 @@
            stringify(OP) "b", s0, s1, res, flags & CC_MASK);
 }
 
-void glue(glue(test_, OP), w)(long op0h, long op0, long op1) 
+void glue(glue(test_, OP), w)(long op0h, long op0, long op1)
 {
     long res, s1, flags, resh;
     s1 = op1;
@@ -26,7 +26,7 @@
     flags = 0;
     asm ("push %5\n\t"
          "popf\n\t"
-         stringify(OP) "w %w3\n\t" 
+         stringify(OP) "w %w3\n\t"
          "pushf\n\t"
          "pop %1\n\t"
          : "=a" (res), "=g" (flags), "=d" (resh)
@@ -35,7 +35,7 @@
            stringify(OP) "w", op0h, op0, s1, resh, res, flags & CC_MASK);
 }
 
-void glue(glue(test_, OP), l)(long op0h, long op0, long op1) 
+void glue(glue(test_, OP), l)(long op0h, long op0, long op1)
 {
     long res, s1, flags, resh;
     s1 = op1;
@@ -44,7 +44,7 @@
     flags = 0;
     asm ("push %5\n\t"
          "popf\n\t"
-         stringify(OP) "l %k3\n\t" 
+         stringify(OP) "l %k3\n\t"
          "pushf\n\t"
          "pop %1\n\t"
          : "=a" (res), "=g" (flags), "=d" (resh)
@@ -54,7 +54,7 @@
 }
 
 #if defined(__x86_64__)
-void glue(glue(test_, OP), q)(long op0h, long op0, long op1) 
+void glue(glue(test_, OP), q)(long op0h, long op0, long op1)
 {
     long res, s1, flags, resh;
     s1 = op1;
@@ -63,7 +63,7 @@
     flags = 0;
     asm ("push %5\n\t"
          "popf\n\t"
-         stringify(OP) "q %3\n\t" 
+         stringify(OP) "q %3\n\t"
          "pushf\n\t"
          "pop %1\n\t"
          : "=a" (res), "=g" (flags), "=d" (resh)
diff --git a/tests/test-i386-vm86.S b/tests/test-i386-vm86.S
index a972f1b..3bb96c9 100644
--- a/tests/test-i386-vm86.S
+++ b/tests/test-i386-vm86.S
@@ -14,7 +14,7 @@
         movw %ax, %es
         es movw $GET_OFFSET(int90_test), 0x90 * 4
         es movw %cs, 0x90 * 4 + 2
-        
+
         /* launch int 0x90 */
 
         int $0x90
@@ -24,23 +24,23 @@
         movb $0x09, %ah
         int $0x21
 
-        pushf 
+        pushf
         popw %dx
         movb $0xff, %ah
         int $0x21
 
         cli
-        pushf 
+        pushf
         popw %dx
         movb $0xff, %ah
         int $0x21
 
-        sti        
-        pushfl 
+        sti
+        pushfl
         popl %edx
         movb $0xff, %ah
         int $0x21
-        
+
 #if 0
         movw $GET_OFFSET(IF_msg1), %dx
         movb $0x09, %ah
@@ -54,11 +54,11 @@
         cli
 #endif
 
-        pushf 
+        pushf
         popw %dx
         movb $0xff, %ah
         int $0x21
-        
+
         pushfl
         movw %sp, %bx
         orw $0x200, (%bx)
@@ -73,7 +73,7 @@
         int $0x21
 
 int90_test:
-        pushf 
+        pushf
         pop %dx
         movb $0xff, %ah
         int $0x21
@@ -82,15 +82,15 @@
         movw 4(%bx), %dx
         movb $0xff, %ah
         int $0x21
-        
+
         movw $GET_OFFSET(int90_msg), %dx
         movb $0x09, %ah
         int $0x21
         iret
-                    
+
 int90_msg:
         .string "INT90 started\n$"
- 
+
 hello_world:
         .string "Hello VM86 world\n$"
 
@@ -101,4 +101,3 @@
         .string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$"
 
 vm86_code_end:
-        
\ No newline at end of file
diff --git a/tests/test-i386.c b/tests/test-i386.c
index 2673915..2d4b0a0 100644
--- a/tests/test-i386.c
+++ b/tests/test-i386.c
@@ -1,6 +1,6 @@
 /*
  *  x86 CPU test
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -470,7 +470,7 @@
 #define OP imul
 #include "test-i386-muldiv.h"
 
-void test_imulw2(long op0, long op1) 
+void test_imulw2(long op0, long op1)
 {
     long res, s1, s0, flags;
     s0 = op0;
@@ -479,7 +479,7 @@
     flags = 0;
     asm volatile ("push %4\n\t"
          "popf\n\t"
-         "imulw %w2, %w0\n\t" 
+         "imulw %w2, %w0\n\t"
          "pushf\n\t"
          "pop %1\n\t"
          : "=q" (res), "=g" (flags)
@@ -488,7 +488,7 @@
            "imulw", s0, s1, res, flags & CC_MASK);
 }
 
-void test_imull2(long op0, long op1) 
+void test_imull2(long op0, long op1)
 {
     long res, s1, s0, flags;
     s0 = op0;
@@ -497,7 +497,7 @@
     flags = 0;
     asm volatile ("push %4\n\t"
          "popf\n\t"
-         "imull %k2, %k0\n\t" 
+         "imull %k2, %k0\n\t"
          "pushf\n\t"
          "pop %1\n\t"
          : "=q" (res), "=g" (flags)
@@ -507,7 +507,7 @@
 }
 
 #if defined(__x86_64__)
-void test_imulq2(long op0, long op1) 
+void test_imulq2(long op0, long op1)
 {
     long res, s1, s0, flags;
     s0 = op0;
@@ -516,7 +516,7 @@
     flags = 0;
     asm volatile ("push %4\n\t"
          "popf\n\t"
-         "imulq %2, %0\n\t" 
+         "imulq %2, %0\n\t"
          "pushf\n\t"
          "pop %1\n\t"
          : "=q" (res), "=g" (flags)
@@ -739,7 +739,7 @@
         uint32_t ignored[4];
         long double fpregs[8];
     } float_env32;
-    
+
     asm volatile ("fnstenv %0\n" : : "m" (float_env32));
     float_env32.fpus &= ~0x7f;
     asm volatile ("fldenv %0\n" : : "m" (float_env32));
@@ -758,14 +758,14 @@
         "fstsw %%ax\n"
         : "=a" (fpus)
         : "t" (a), "u" (b));
-    printf("fcom(%f %f)=%04lx \n", 
+    printf("fcom(%f %f)=%04lx \n",
            a, b, fpus & (0x4500 | FPUS_EMASK));
     fpu_clear_exceptions();
     asm("fucom %2\n"
         "fstsw %%ax\n"
         : "=a" (fpus)
         : "t" (a), "u" (b));
-    printf("fucom(%f %f)=%04lx\n", 
+    printf("fucom(%f %f)=%04lx\n",
            a, b, fpus & (0x4500 | FPUS_EMASK));
     if (TEST_FCOMI) {
         /* test f(u)comi instruction */
@@ -776,7 +776,7 @@
             "pop %0\n"
             : "=r" (eflags), "=a" (fpus)
             : "t" (a), "u" (b));
-        printf("fcomi(%f %f)=%04lx %02lx\n", 
+        printf("fcomi(%f %f)=%04lx %02lx\n",
                a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C));
         fpu_clear_exceptions();
         asm("fucomi %3, %2\n"
@@ -785,7 +785,7 @@
             "pop %0\n"
             : "=r" (eflags), "=a" (fpus)
             : "t" (a), "u" (b));
-        printf("fucomi(%f %f)=%04lx %02lx\n", 
+        printf("fucomi(%f %f)=%04lx %02lx\n",
                a, b, fpus & FPUS_EMASK, eflags & (CC_Z | CC_P | CC_C));
     }
     fpu_clear_exceptions();
@@ -813,7 +813,7 @@
     printf("(float)%f = %f\n", a, fa);
     printf("(long double)%f = %Lf\n", a, la);
     printf("a=" FMT64X "\n", *(uint64_t *)&a);
-    printf("la=" FMT64X " %04x\n", *(uint64_t *)&la, 
+    printf("la=" FMT64X " %04x\n", *(uint64_t *)&la,
            *(unsigned short *)((char *)(&la) + 8));
 
     /* test all roundings */
@@ -855,7 +855,7 @@
 
     asm("fbstp %0" : "=m" (bcd[0]) : "t" (a) : "st");
     asm("fbld %1" : "=t" (b) : "m" (bcd[0]));
-    printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n", 
+    printf("a=%f bcd=%04x%04x%04x%04x%04x b=%f\n",
            a, bcd[4], bcd[3], bcd[2], bcd[1], bcd[0], b);
 }
 
@@ -1041,7 +1041,7 @@
     TEST_BCD(aaa, 0x12340306, 0, (CC_C | CC_A));
     TEST_BCD(aaa, 0x1234040a, 0, (CC_C | CC_A));
     TEST_BCD(aaa, 0x123405fa, 0, (CC_C | CC_A));
-    
+
     TEST_BCD(aas, 0x12340205, CC_A, (CC_C | CC_A));
     TEST_BCD(aas, 0x12340306, CC_A, (CC_C | CC_A));
     TEST_BCD(aas, 0x1234040a, CC_A, (CC_C | CC_A));
@@ -1157,12 +1157,12 @@
             else
                 op1 = op0;
             op2 = 0x6532432432434;
-            asm("cmpxchg8b %1\n" 
+            asm("cmpxchg8b %1\n"
                 "pushf\n"
                 "pop %2\n"
                 : "=A" (op0), "=m" (op1), "=g" (eflags)
                 : "0" (op0), "m" (op1), "b" ((int)op2), "c" ((int)(op2 >> 32)));
-            printf("cmpxchg8b: op0=" FMT64X " op1=" FMT64X " CC=%02lx\n", 
+            printf("cmpxchg8b: op0=" FMT64X " op1=" FMT64X " CC=%02lx\n",
                     op0, op1, eflags & CC_Z);
         }
     }
@@ -1276,9 +1276,9 @@
 
     segoff.seg = MK_SEL(2);
     segoff.offset = 0xabcdef12;
-    asm volatile("lfs %2, %0\n\t" 
+    asm volatile("lfs %2, %0\n\t"
                  "movl %%fs, %1\n\t"
-                 : "=r" (res), "=g" (res2) 
+                 : "=r" (res), "=g" (res2)
                  : "m" (segoff));
     printf("FS:reg = %04x:%08x\n", res2, res);
 
@@ -1317,15 +1317,15 @@
     modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
 
     /* call the first function */
-    asm volatile ("lcall %1, %2" 
+    asm volatile ("lcall %1, %2"
                   : "=a" (res)
                   : "i" (MK_SEL(1)), "i" (&code16_func1): "memory", "cc");
     printf("func1() = 0x%08x\n", res);
-    asm volatile ("lcall %2, %3" 
+    asm volatile ("lcall %2, %3"
                   : "=a" (res), "=c" (res2)
                   : "i" (MK_SEL(1)), "i" (&code16_func2): "memory", "cc");
     printf("func2() = 0x%08x spdec=%d\n", res, res2);
-    asm volatile ("lcall %1, %2" 
+    asm volatile ("lcall %1, %2"
                   : "=a" (res)
                   : "i" (MK_SEL(1)), "i" (&code16_func3): "memory", "cc");
     printf("func3() = 0x%08x\n", res);
@@ -1373,7 +1373,7 @@
         asm volatile ("mov %%cs, %0" : "=r" (cs_sel));
 
         asm volatile ("push %1\n"
-                      "call func_lret\n" 
+                      "call func_lret\n"
                       : "=a" (res)
                       : "r" (cs_sel) : "memory", "cc");
         printf("func_lret=" FMTLX "\n", res);
@@ -1381,11 +1381,11 @@
         /* NOTE: we assume that &func_lret < 4GB */
         desc.offset = (long)&func_lret;
         desc.seg = cs_sel;
-        
+
         asm volatile ("xor %%rax, %%rax\n"
                       "rex64 lcall %1\n"
                       : "=a" (res)
-                      : "m" (desc) 
+                      : "m" (desc)
                       : "memory", "cc");
         printf("func_lret2=" FMTLX "\n", res);
 
@@ -1400,12 +1400,12 @@
         printf("func_lret3=" FMTLX "\n", res);
     }
 #else
-    asm volatile ("push %%cs ; call %1" 
+    asm volatile ("push %%cs ; call %1"
                   : "=a" (res)
                   : "m" (func_lret): "memory", "cc");
     printf("func_lret=" FMTLX "\n", res);
 
-    asm volatile ("pushf ; push %%cs ; call %1" 
+    asm volatile ("pushf ; push %%cs ; call %1"
                   : "=a" (res)
                   : "m" (func_iret): "memory", "cc");
     printf("func_iret=" FMTLX "\n", res);
@@ -1472,7 +1472,7 @@
    TEST_STRING(stos, "");
    TEST_STRING(stos, "rep ");
    TEST_STRING(lods, ""); /* to verify stos */
-   TEST_STRING(lods, "rep "); 
+   TEST_STRING(lods, "rep ");
    TEST_STRING(movs, "");
    TEST_STRING(movs, "rep ");
    TEST_STRING(lods, ""); /* to verify stos */
@@ -1526,8 +1526,8 @@
     uint8_t *vm86_mem;
     int seg, ret;
 
-    vm86_mem = mmap((void *)0x00000000, 0x110000, 
-                    PROT_WRITE | PROT_READ | PROT_EXEC, 
+    vm86_mem = mmap((void *)0x00000000, 0x110000,
+                    PROT_WRITE | PROT_READ | PROT_EXEC,
                     MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
     if (vm86_mem == MAP_FAILED) {
         printf("ERROR: could not map vm86 memory");
@@ -1550,7 +1550,7 @@
 
     /* move code to proper address. We use the same layout as a .com
        dos program. */
-    memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP, 
+    memcpy(vm86_mem + (VM86_CODE_CS << 4) + VM86_CODE_IP,
            &vm86_code_start, &vm86_code_end - &vm86_code_start);
 
     /* mark int 0x21 as being emulated */
@@ -1562,7 +1562,7 @@
         case VM86_INTx:
             {
                 int int_num, ah, v;
-                
+
                 int_num = VM86_ARG(ret);
                 if (int_num != 0x21)
                     goto unknown_int;
@@ -1665,7 +1665,7 @@
 {
     struct sigaction act;
     volatile int val;
-    
+
     act.sa_sigaction = sig_handler;
     sigemptyset(&act.sa_mask);
     act.sa_flags = SA_SIGINFO | SA_NODEFER;
@@ -1718,7 +1718,7 @@
         ldt.seg_not_present = 1;
         ldt.useable = 1;
         modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
-        
+
         if (setjmp(jmp_env) == 0) {
             /* segment not present */
             asm volatile ("movl %0, %%fs" : : "r" (MK_SEL(1)));
@@ -1743,7 +1743,7 @@
         /* read from an invalid address */
         v1 = *(char *)0x1234;
     }
-    
+
     /* test illegal instruction reporting */
     printf("UD2 exception:\n");
     if (setjmp(jmp_env) == 0) {
@@ -1755,7 +1755,7 @@
         /* now execute an invalid instruction */
         asm volatile("lock nop");
     }
-    
+
     printf("INT exception:\n");
     if (setjmp(jmp_env) == 0) {
         asm volatile ("int $0xfd");
@@ -1827,7 +1827,7 @@
         asm volatile ("pushf\n"
                       "orl $0x00100, (%%esp)\n"
                       "popf\n"
-                      "movl $0xabcd, %0\n" 
+                      "movl $0xabcd, %0\n"
                       "movl $0x0, %0\n" : "=m" (val) : : "cc", "memory");
     }
     printf("val=0x%x\n", val);
@@ -1858,7 +1858,7 @@
     asm volatile ("pushf\n"
                   "orl $0x00100, (%%esp)\n"
                   "popf\n"
-                  "movl $0xabcd, %0\n" 
+                  "movl $0xabcd, %0\n"
 
                   /* jmp test */
                   "movl $3, %%ecx\n"
@@ -1884,13 +1884,13 @@
                   "rep cmpsb\n"
                   "movl $4, %%ecx\n"
                   "rep cmpsb\n"
-                  
+
                   /* getpid() syscall: single step should skip one
                      instruction */
                   "movl $20, %%eax\n"
                   "int $0x80\n"
                   "movl $0, %%eax\n"
-                  
+
                   /* when modifying SS, trace is not done on the next
                      instruction */
                   "movl %%ss, %%ecx\n"
@@ -1906,12 +1906,12 @@
                   "popl %%ss\n"
                   "addl $1, %0\n"
                   "movl $1, %%eax\n"
-                  
+
                   "pushf\n"
                   "andl $~0x00100, (%%esp)\n"
                   "popf\n"
-                  : "=m" (val) 
-                  : 
+                  : "=m" (val)
+                  :
                   : "cc", "memory", "eax", "ecx", "esi", "edi");
     printf("val=%d\n", val);
     for(i = 0; i < 4; i++)
@@ -2282,14 +2282,14 @@
         " fxrstor %0\n"
         " fxsave %1\n"
         " fninit\n"
-        : "=m" (*(uint32_t *)fp2), "=m" (*(uint32_t *)fp) 
+        : "=m" (*(uint32_t *)fp2), "=m" (*(uint32_t *)fp)
         : "m" (a), "m" (b));
     printf("fpuc=%04x\n", fp->fpuc);
     printf("fpus=%04x\n", fp->fpus);
     printf("fptag=%04x\n", fp->fptag);
     for(i = 0; i < 3; i++) {
         printf("ST%d: " FMT64X " %04x\n",
-               i, 
+               i,
                *(uint64_t *)&fp->fpregs1[i * 16],
                *(uint16_t *)&fp->fpregs1[i * 16 + 8]);
     }
@@ -2301,7 +2301,7 @@
 #endif
     for(i = 0; i < nb_xmm; i++) {
         printf("xmm%d: " FMT64X "" FMT64X "\n",
-               i, 
+               i,
                *(uint64_t *)&fp->xmm_regs[i * 16],
                *(uint64_t *)&fp->xmm_regs[i * 16 + 8]);
     }
@@ -2341,7 +2341,7 @@
 
     MMX_OP2(pmulhuw);
     MMX_OP2(pmulhw);
-    
+
     MMX_OP2(psubsb);
     MMX_OP2(psubsw);
     MMX_OP2(pminsw);
@@ -2380,7 +2380,7 @@
 
     asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "y" (a.q[0]));
     printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]);
-    
+
     asm volatile ("pmovmskb %1, %0" : "=r" (r.l[0]) : "x" (a.dq));
     printf("%-9s: r=%08x\n", "pmovmskb", r.l[0]);
 
@@ -2392,21 +2392,21 @@
         a.q[1] = test_values[0][1];
         b.q[0] = test_values[1][0];
         b.q[1] = test_values[1][1];
-        asm volatile("maskmovq %1, %0" : 
+        asm volatile("maskmovq %1, %0" :
                      : "y" (a.q[0]), "y" (b.q[0]), "D" (&r)
-                     : "memory"); 
-        printf("%-9s: r=" FMT64X " a=" FMT64X " b=" FMT64X "\n", 
-               "maskmov", 
-               r.q[0], 
-               a.q[0], 
+                     : "memory");
+        printf("%-9s: r=" FMT64X " a=" FMT64X " b=" FMT64X "\n",
+               "maskmov",
+               r.q[0],
+               a.q[0],
                b.q[0]);
-        asm volatile("maskmovdqu %1, %0" : 
+        asm volatile("maskmovdqu %1, %0" :
                      : "x" (a.dq), "x" (b.dq), "D" (&r)
-                     : "memory"); 
-        printf("%-9s: r=" FMT64X "" FMT64X " a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X "\n", 
-               "maskmov", 
-               r.q[1], r.q[0], 
-               a.q[1], a.q[0], 
+                     : "memory");
+        printf("%-9s: r=" FMT64X "" FMT64X " a=" FMT64X "" FMT64X " b=" FMT64X "" FMT64X "\n",
+               "maskmov",
+               r.q[1], r.q[0],
+               a.q[1], a.q[0],
                b.q[1], b.q[0]);
     }
 
@@ -2506,8 +2506,8 @@
         SSE_OPS(cmpnlt);
         SSE_OPS(cmpnle);
         SSE_OPS(cmpord);
-        
-        
+
+
         a.d[0] = 2.7;
         a.d[1] = -3.4;
         b.d[0] = 45.7;
diff --git a/tests/test_path.c b/tests/test_path.c
index a9b52de..7d6e831 100644
--- a/tests/test_path.c
+++ b/tests/test_path.c
@@ -149,4 +149,4 @@
     }
     return 0;
 }
-	
+
diff --git a/texi2pod.pl b/texi2pod.pl
index 176627e..112d449 100755
--- a/texi2pod.pl
+++ b/texi2pod.pl
@@ -229,7 +229,7 @@
 	$inf = gensym();
 
 	# Try cwd and $ibase.
-	open($inf, "<" . $1) 
+	open($inf, "<" . $1)
 	    or open($inf, "<" . $ibase . "/" . $1)
 		or die "cannot open $1 or $ibase/$1: $!\n";
 	next;
diff --git a/thunk.c b/thunk.c
index bc9bd28..dbeb2b1 100644
--- a/thunk.c
+++ b/thunk.c
@@ -1,6 +1,6 @@
 /*
  *  Generic thunking code to convert data between host and target CPU
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -64,7 +64,7 @@
     int nb_fields, offset, max_align, align, size, i, j;
 
     se = struct_entries + id;
-    
+
     /* first we count the number of fields */
     type_ptr = types;
     nb_fields = 0;
@@ -76,7 +76,7 @@
     se->nb_fields = nb_fields;
     se->name = name;
 #ifdef DEBUG
-    printf("struct %s: id=%d nb_fields=%d\n", 
+    printf("struct %s: id=%d nb_fields=%d\n",
            se->name, id, se->nb_fields);
 #endif
     /* now we can alloc the data */
@@ -100,7 +100,7 @@
         se->size[i] = offset;
         se->align[i] = max_align;
 #ifdef DEBUG
-        printf("%s: size=%d align=%d\n", 
+        printf("%s: size=%d align=%d\n",
                i == THUNK_HOST ? "host" : "target", offset, max_align);
 #endif
     }
@@ -116,7 +116,7 @@
 
 
 /* now we can define the main conversion functions */
-const argtype *thunk_convert(void *dst, const void *src, 
+const argtype *thunk_convert(void *dst, const void *src,
                              const argtype *type_ptr, int to_host)
 {
     int type;
@@ -182,7 +182,7 @@
             uint8_t  *d;
             const argtype *field_types;
             const int *dst_offsets, *src_offsets;
-            
+
             se = struct_entries + *type_ptr++;
             if (se->convert[0] != NULL) {
                 /* specific conversion is needed */
@@ -195,8 +195,8 @@
                 d = dst;
                 s = src;
                 for(i = 0;i < se->nb_fields; i++) {
-                    field_types = thunk_convert(d + dst_offsets[i], 
-                                                s + src_offsets[i], 
+                    field_types = thunk_convert(d + dst_offsets[i],
+                                                s + src_offsets[i],
                                                 field_types, to_host);
                 }
             }
@@ -214,7 +214,7 @@
 /* Utility function: Table-driven functions to translate bitmasks
  * between X86 and Alpha formats...
  */
-unsigned int target_to_host_bitmask(unsigned int x86_mask, 
+unsigned int target_to_host_bitmask(unsigned int x86_mask,
                                     bitmask_transtbl * trans_tbl)
 {
     bitmask_transtbl *	btp;
@@ -228,7 +228,7 @@
     return(alpha_mask);
 }
 
-unsigned int host_to_target_bitmask(unsigned int alpha_mask, 
+unsigned int host_to_target_bitmask(unsigned int alpha_mask,
                                     bitmask_transtbl * trans_tbl)
 {
     bitmask_transtbl *	btp;
diff --git a/thunk.h b/thunk.h
index 42fd96f..7811df3 100644
--- a/thunk.h
+++ b/thunk.h
@@ -1,6 +1,6 @@
 /*
  *  Generic thunking code to convert data between host and target CPU
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -69,7 +69,7 @@
 
 void thunk_register_struct(int id, const char *name, const argtype *types);
 void thunk_register_struct_direct(int id, const char *name, StructEntry *se1);
-const argtype *thunk_convert(void *dst, const void *src, 
+const argtype *thunk_convert(void *dst, const void *src,
                              const argtype *type_ptr, int to_host);
 #ifndef NO_THUNK_TYPE_SIZE
 
@@ -150,9 +150,9 @@
 
 #endif /* NO_THUNK_TYPE_SIZE */
 
-unsigned int target_to_host_bitmask(unsigned int x86_mask, 
+unsigned int target_to_host_bitmask(unsigned int x86_mask,
                                     bitmask_transtbl * trans_tbl);
-unsigned int host_to_target_bitmask(unsigned int alpha_mask, 
+unsigned int host_to_target_bitmask(unsigned int alpha_mask,
                                     bitmask_transtbl * trans_tbl);
 
 #endif
diff --git a/translate-all.c b/translate-all.c
index 4336547..197c48c 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1,6 +1,6 @@
 /*
  *  Host code generation
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
@@ -89,7 +89,7 @@
     for(;;) {
         c = *opc_ptr++;
         n = op_nb_args[c];
-        fprintf(logfile, "0x%04x: %s", 
+        fprintf(logfile, "0x%04x: %s",
                 (int)(opc_ptr - opc_buf - 1), op_str[c]);
         for(i = 0; i < n; i++) {
             fprintf(logfile, " 0x%x", opparam_ptr[i]);
@@ -110,11 +110,11 @@
     uint8_t *gen_code_ptr;
     int c, i;
     unsigned long gen_code_addr[OPC_BUF_SIZE];
-    
+
     if (nb_gen_labels == 0)
         return;
     /* compute the address of each op code */
-    
+
     gen_code_ptr = gen_code_buf;
     i = 0;
     for(;;) {
@@ -125,7 +125,7 @@
         gen_code_ptr += opc_copy_size[c];
         i++;
     }
-    
+
     /* compute the address of each label */
     for(i = 0; i < nb_gen_labels; i++) {
         gen_labels[i] = gen_code_addr[gen_labels[i]];
@@ -133,7 +133,7 @@
 }
 
 /* return non zero if the very first instruction is invalid so that
-   the virtual CPU can trigger an exception. 
+   the virtual CPU can trigger an exception.
 
    '*gen_code_size_ptr' contains the size of the generated code (host
    code).
@@ -185,9 +185,9 @@
     return 0;
 }
 
-/* The cpu state corresponding to 'searched_pc' is restored. 
+/* The cpu state corresponding to 'searched_pc' is restored.
  */
-int cpu_restore_state(TranslationBlock *tb, 
+int cpu_restore_state(TranslationBlock *tb,
                       CPUState *env, unsigned long searched_pc,
                       void *puc)
 {
@@ -202,7 +202,7 @@
 #endif
     if (gen_intermediate_code_pc(env, tb) < 0)
         return -1;
-    
+
     /* find opc index corresponding to search_pc */
     tc_ptr = (unsigned long)tb->tc_ptr;
     if (searched_pc < tc_ptr)
@@ -234,8 +234,8 @@
                     fprintf(logfile, "0x%04x: " TARGET_FMT_lx "\n", i, gen_opc_pc[i]);
                 }
             }
-            fprintf(logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n", 
-                    searched_pc, j, gen_opc_pc[j] - tb->cs_base, 
+            fprintf(logfile, "spc=0x%08lx j=0x%x eip=" TARGET_FMT_lx " cs_base=%x\n",
+                    searched_pc, j, gen_opc_pc[j] - tb->cs_base,
                     (uint32_t)tb->cs_base);
         }
 #endif
@@ -256,7 +256,7 @@
         } else if (npc == 2) {
             target_ulong t2 = (target_ulong)puc;
             /* jump PC: use T2 and the jump targets of the translation */
-            if (t2) 
+            if (t2)
                 env->npc = gen_opc_jump_pc[0];
             else
                 env->npc = gen_opc_jump_pc[1];
@@ -279,7 +279,7 @@
         case INDEX_op_ ## op ## _user:\
         case INDEX_op_ ## op ## _kernel
 #endif
-            
+
         CASE3(stfd):
         CASE3(stfs):
         CASE3(lfd):
@@ -305,9 +305,11 @@
 #elif defined(TARGET_M68K)
     env->pc = gen_opc_pc[j];
 #elif defined(TARGET_MIPS)
-    env->PC = gen_opc_pc[j];
+    env->PC[env->current_tc] = gen_opc_pc[j];
     env->hflags &= ~MIPS_HFLAG_BMASK;
     env->hflags |= gen_opc_hflags[j];
+#elif defined(TARGET_ALPHA)
+    env->pc = gen_opc_pc[j];
 #endif
     return 0;
 }
diff --git a/translate-op.c b/translate-op.c
index fddac70..37c61e1 100644
--- a/translate-op.c
+++ b/translate-op.c
@@ -1,6 +1,6 @@
 /*
  *  Host code generation
- * 
+ *
  *  Copyright (c) 2003 Fabrice Bellard
  *
  * This library is free software; you can redistribute it and/or
diff --git a/uboot_image.h b/uboot_image.h
new file mode 100644
index 0000000..d5a5b30
--- /dev/null
+++ b/uboot_image.h
@@ -0,0 +1,160 @@
+/*
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ********************************************************************
+ * NOTE: This header file defines an interface to U-Boot. Including
+ * this (unmodified) header file in another file is considered normal
+ * use of U-Boot, and does *not* fall under the heading of "derived
+ * work".
+ ********************************************************************
+ */
+
+#ifndef __UBOOT_IMAGE_H__
+#define __UBOOT_IMAGE_H__
+
+/*
+ * Operating System Codes
+ */
+#define IH_OS_INVALID		0	/* Invalid OS	*/
+#define IH_OS_OPENBSD		1	/* OpenBSD	*/
+#define IH_OS_NETBSD		2	/* NetBSD	*/
+#define IH_OS_FREEBSD		3	/* FreeBSD	*/
+#define IH_OS_4_4BSD		4	/* 4.4BSD	*/
+#define IH_OS_LINUX		5	/* Linux	*/
+#define IH_OS_SVR4		6	/* SVR4		*/
+#define IH_OS_ESIX		7	/* Esix		*/
+#define IH_OS_SOLARIS		8	/* Solaris	*/
+#define IH_OS_IRIX		9	/* Irix		*/
+#define IH_OS_SCO		10	/* SCO		*/
+#define IH_OS_DELL		11	/* Dell		*/
+#define IH_OS_NCR		12	/* NCR		*/
+#define IH_OS_LYNXOS		13	/* LynxOS	*/
+#define IH_OS_VXWORKS		14	/* VxWorks	*/
+#define IH_OS_PSOS		15	/* pSOS		*/
+#define IH_OS_QNX		16	/* QNX		*/
+#define IH_OS_U_BOOT		17	/* Firmware	*/
+#define IH_OS_RTEMS		18	/* RTEMS	*/
+#define IH_OS_ARTOS		19	/* ARTOS	*/
+#define IH_OS_UNITY		20	/* Unity OS	*/
+
+/*
+ * CPU Architecture Codes (supported by Linux)
+ */
+#define IH_CPU_INVALID		0	/* Invalid CPU	*/
+#define IH_CPU_ALPHA		1	/* Alpha	*/
+#define IH_CPU_ARM		2	/* ARM		*/
+#define IH_CPU_I386		3	/* Intel x86	*/
+#define IH_CPU_IA64		4	/* IA64		*/
+#define IH_CPU_MIPS		5	/* MIPS		*/
+#define IH_CPU_MIPS64		6	/* MIPS	 64 Bit */
+#define IH_CPU_PPC		7	/* PowerPC	*/
+#define IH_CPU_S390		8	/* IBM S390	*/
+#define IH_CPU_SH		9	/* SuperH	*/
+#define IH_CPU_SPARC		10	/* Sparc	*/
+#define IH_CPU_SPARC64		11	/* Sparc 64 Bit */
+#define IH_CPU_M68K		12	/* M68K		*/
+#define IH_CPU_NIOS		13	/* Nios-32	*/
+#define IH_CPU_MICROBLAZE	14	/* MicroBlaze   */
+#define IH_CPU_NIOS2		15	/* Nios-II	*/
+#define IH_CPU_BLACKFIN		16	/* Blackfin	*/
+#define IH_CPU_AVR32		17	/* AVR32	*/
+
+/*
+ * Image Types
+ *
+ * "Standalone Programs" are directly runnable in the environment
+ *	provided by U-Boot; it is expected that (if they behave
+ *	well) you can continue to work in U-Boot after return from
+ *	the Standalone Program.
+ * "OS Kernel Images" are usually images of some Embedded OS which
+ *	will take over control completely. Usually these programs
+ *	will install their own set of exception handlers, device
+ *	drivers, set up the MMU, etc. - this means, that you cannot
+ *	expect to re-enter U-Boot except by resetting the CPU.
+ * "RAMDisk Images" are more or less just data blocks, and their
+ *	parameters (address, size) are passed to an OS kernel that is
+ *	being started.
+ * "Multi-File Images" contain several images, typically an OS
+ *	(Linux) kernel image and one or more data images like
+ *	RAMDisks. This construct is useful for instance when you want
+ *	to boot over the network using BOOTP etc., where the boot
+ *	server provides just a single image file, but you want to get
+ *	for instance an OS kernel and a RAMDisk image.
+ *
+ *	"Multi-File Images" start with a list of image sizes, each
+ *	image size (in bytes) specified by an "uint32_t" in network
+ *	byte order. This list is terminated by an "(uint32_t)0".
+ *	Immediately after the terminating 0 follow the images, one by
+ *	one, all aligned on "uint32_t" boundaries (size rounded up to
+ *	a multiple of 4 bytes - except for the last file).
+ *
+ * "Firmware Images" are binary images containing firmware (like
+ *	U-Boot or FPGA images) which usually will be programmed to
+ *	flash memory.
+ *
+ * "Script files" are command sequences that will be executed by
+ *	U-Boot's command interpreter; this feature is especially
+ *	useful when you configure U-Boot to use a real shell (hush)
+ *	as command interpreter (=> Shell Scripts).
+ */
+
+#define IH_TYPE_INVALID		0	/* Invalid Image		*/
+#define IH_TYPE_STANDALONE	1	/* Standalone Program		*/
+#define IH_TYPE_KERNEL		2	/* OS Kernel Image		*/
+#define IH_TYPE_RAMDISK		3	/* RAMDisk Image		*/
+#define IH_TYPE_MULTI		4	/* Multi-File Image		*/
+#define IH_TYPE_FIRMWARE	5	/* Firmware Image		*/
+#define IH_TYPE_SCRIPT		6	/* Script file			*/
+#define IH_TYPE_FILESYSTEM	7	/* Filesystem Image (any type)	*/
+#define IH_TYPE_FLATDT		8	/* Binary Flat Device Tree Blob	*/
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE		0	/*  No	 Compression Used	*/
+#define IH_COMP_GZIP		1	/* gzip	 Compression Used	*/
+#define IH_COMP_BZIP2		2	/* bzip2 Compression Used	*/
+
+#define IH_MAGIC	0x27051956	/* Image Magic Number		*/
+#define IH_NMLEN		32	/* Image Name Length		*/
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+
+typedef struct uboot_image_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint8_t		ih_os;		/* Operating System		*/
+	uint8_t		ih_arch;	/* CPU architecture		*/
+	uint8_t		ih_type;	/* Image Type			*/
+	uint8_t		ih_comp;	/* Compression Type		*/
+	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
+} uboot_image_header_t;
+
+
+#endif	/* __IMAGE_H__ */
diff --git a/usb-linux.c b/usb-linux.c
index 50386ea..3a23301 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -2,7 +2,7 @@
  * Linux host USB redirector
  *
  * Copyright (c) 2005 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -41,9 +41,9 @@
 };
 
 typedef int USBScanFunc(void *opaque, int bus_num, int addr, int class_id,
-                        int vendor_id, int product_id, 
+                        int vendor_id, int product_id,
                         const char *product_name, int speed);
-static int usb_host_find_device(int *pbus_num, int *paddr, 
+static int usb_host_find_device(int *pbus_num, int *paddr,
                                 char *product_name, int product_name_size,
                                 const char *devname);
 
@@ -65,7 +65,7 @@
        done by the host OS */
     ioctl(s->fd, USBDEVFS_RESET);
 #endif
-} 
+}
 
 static void usb_host_handle_destroy(USBDevice *dev)
 {
@@ -157,12 +157,12 @@
     int bus_num, addr;
     char product_name[PRODUCT_NAME_SZ];
 
-    if (usb_host_find_device(&bus_num, &addr, 
+    if (usb_host_find_device(&bus_num, &addr,
                              product_name, sizeof(product_name),
-                             devname) < 0) 
+                             devname) < 0)
         return NULL;
-    
-    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d", 
+
+    snprintf(buf, sizeof(buf), USBDEVFS_PATH "/%03d/%03d",
              bus_num, addr);
     fd = open(buf, O_RDWR);
     if (fd < 0) {
@@ -176,7 +176,7 @@
         perror("read descr");
         goto fail;
     }
-    
+
     i = 0;
     dev_descr_len = descr[0];
     if (dev_descr_len > descr_len)
@@ -228,7 +228,7 @@
 
 #ifdef DEBUG
     printf("host USB device %d.%d grabbed\n", bus_num, addr);
-#endif    
+#endif
 
     dev = qemu_mallocz(sizeof(USBHostDevice));
     if (!dev)
@@ -256,7 +256,7 @@
 }
 
 static int get_tag_value(char *buf, int buf_size,
-                         const char *str, const char *tag, 
+                         const char *str, const char *tag,
                          const char *stopchars)
 {
     const char *p;
@@ -285,7 +285,7 @@
     int bus_num, addr, speed, device_count, class_id, product_id, vendor_id;
     int ret;
     char product_name[512];
-    
+
     f = fopen(USBDEVFS_PATH "/devices", "r");
     if (!f) {
         term_printf("Could not open %s\n", USBDEVFS_PATH "/devices");
@@ -302,7 +302,7 @@
         if (line[0] == 'T' && line[1] == ':') {
             if (device_count && (vendor_id || product_id)) {
                 /* New device.  Add the previously discovered device.  */
-                ret = func(opaque, bus_num, addr, class_id, vendor_id, 
+                ret = func(opaque, bus_num, addr, class_id, vendor_id,
                            product_id, product_name, speed);
                 if (ret)
                     goto the_end;
@@ -346,7 +346,7 @@
     }
     if (device_count && (vendor_id || product_id)) {
         /* Add the last device.  */
-        ret = func(opaque, bus_num, addr, class_id, vendor_id, 
+        ret = func(opaque, bus_num, addr, class_id, vendor_id,
                    product_id, product_name, speed);
     }
  the_end:
@@ -362,9 +362,9 @@
     char product_name[PRODUCT_NAME_SZ];
 } FindDeviceState;
 
-static int usb_host_find_device_scan(void *opaque, int bus_num, int addr, 
+static int usb_host_find_device_scan(void *opaque, int bus_num, int addr,
                                      int class_id,
-                                     int vendor_id, int product_id, 
+                                     int vendor_id, int product_id,
                                      const char *product_name, int speed)
 {
     FindDeviceState *s = opaque;
@@ -381,10 +381,10 @@
     }
 }
 
-/* the syntax is : 
-   'bus.addr' (decimal numbers) or 
+/* the syntax is :
+   'bus.addr' (decimal numbers) or
    'vendor_id:product_id' (hexa numbers) */
-static int usb_host_find_device(int *pbus_num, int *paddr, 
+static int usb_host_find_device(int *pbus_num, int *paddr,
                                 char *product_name, int product_name_size,
                                 const char *devname)
 {
@@ -454,31 +454,31 @@
 }
 
 void usb_info_device(int bus_num, int addr, int class_id,
-                     int vendor_id, int product_id, 
+                     int vendor_id, int product_id,
                      const char *product_name,
                      int speed)
 {
     const char *class_str, *speed_str;
 
     switch(speed) {
-    case USB_SPEED_LOW: 
-        speed_str = "1.5"; 
+    case USB_SPEED_LOW:
+        speed_str = "1.5";
         break;
-    case USB_SPEED_FULL: 
-        speed_str = "12"; 
+    case USB_SPEED_FULL:
+        speed_str = "12";
         break;
-    case USB_SPEED_HIGH: 
-        speed_str = "480"; 
+    case USB_SPEED_HIGH:
+        speed_str = "480";
         break;
     default:
-        speed_str = "?"; 
+        speed_str = "?";
         break;
     }
 
-    term_printf("  Device %d.%d, speed %s Mb/s\n", 
+    term_printf("  Device %d.%d, speed %s Mb/s\n",
                 bus_num, addr, speed_str);
     class_str = usb_class_str(class_id);
-    if (class_str) 
+    if (class_str)
         term_printf("    %s:", class_str);
     else
         term_printf("    Class %02x:", class_id);
@@ -488,9 +488,9 @@
     term_printf("\n");
 }
 
-static int usb_host_info_device(void *opaque, int bus_num, int addr, 
+static int usb_host_info_device(void *opaque, int bus_num, int addr,
                                 int class_id,
-                                int vendor_id, int product_id, 
+                                int vendor_id, int product_id,
                                 const char *product_name,
                                 int speed)
 {
diff --git a/vl.c b/vl.c
index 804a64a..30c6561 100644
--- a/vl.c
+++ b/vl.c
@@ -1,8 +1,8 @@
 /*
  * QEMU System Emulator
- * 
+ *
  * Copyright (c) 2003-2007 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -42,11 +42,15 @@
 #include <netinet/in.h>
 #include <dirent.h>
 #include <netdb.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
 #ifdef _BSD
 #include <sys/stat.h>
 #ifndef __APPLE__
 #include <libutil.h>
 #endif
+#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+#include <freebsd/stdlib.h>
 #else
 #ifndef __sun__
 #include <linux/if.h>
@@ -54,9 +58,33 @@
 #include <pty.h>
 #include <malloc.h>
 #include <linux/rtc.h>
+
+/* For the benefit of older linux systems which don't supply it,
+   we use a local copy of hpet.h. */
+/* #include <linux/hpet.h> */
+#include "hpet.h"
+
 #include <linux/ppdev.h>
+#include <linux/parport.h>
+#else
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
 #endif
 #endif
+#else
+#include <winsock2.h>
+int inet_aton(const char *cp, struct in_addr *ia);
 #endif
 
 #if defined(CONFIG_SLIRP)
@@ -130,10 +158,12 @@
 /* Note: bs_table[MAX_DISKS] is a dummy block driver if none available
    to store the VM snapshots */
 BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD];
+BlockDriverState *pflash_table[MAX_PFLASH];
+BlockDriverState *sd_bdrv;
+BlockDriverState *mtd_bdrv;
 /* point to the block driver where the snapshots are managed */
 BlockDriverState *bs_snapshots;
 int vga_ram_size;
-int bios_size;
 static DisplayState display_state;
 int nographic;
 const char* keyboard_layout = NULL;
@@ -143,19 +173,21 @@
 int pit_min_timer_count = 0;
 int nb_nics;
 NICInfo nd_table[MAX_NICS];
-QEMUTimer *gui_timer;
 int vm_running;
 int rtc_utc = 1;
 int cirrus_vga_enabled = 1;
+int vmsvga_enabled = 0;
 #ifdef TARGET_SPARC
 int graphic_width = 1024;
 int graphic_height = 768;
+int graphic_depth = 8;
 #else
 int graphic_width = 800;
 int graphic_height = 600;
-#endif
 int graphic_depth = 15;
+#endif
 int full_screen = 0;
+int no_frame = 0;
 int no_quit = 0;
 int balloon_used = 0;
 CharDriverState *vmchannel_hds[MAX_VMCHANNEL_DEVICES];
@@ -178,6 +210,8 @@
 int acpi_enabled = 1;
 int fd_bootchk = 1;
 int no_reboot = 0;
+int cursor_hide = 1;
+int graphic_rotate = 0;
 int daemonize = 0;
 const char *incoming;
 const char *option_rom[MAX_OPTION_ROMS];
@@ -186,6 +220,17 @@
 int autostart = 1;
 int time_drift_fix = 0;
 const char *cpu_vendor_string;
+#ifdef TARGET_ARM
+int old_param = 0;
+#endif
+const char *qemu_name;
+int alt_grab = 0;
+#ifdef TARGET_SPARC
+unsigned int nb_prom_envs = 0;
+const char *prom_envs[MAX_PROM_ENVS];
+#endif
+
+#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
 
 /***********************************************************/
 /* x86 ISA bus support */
@@ -196,7 +241,7 @@
 uint32_t default_ioport_readb(void *opaque, uint32_t address)
 {
 #ifdef DEBUG_UNUSED_IOPORT
-    fprintf(stderr, "inb: port=0x%04x\n", address);
+    fprintf(stderr, "unused inb: port=0x%04x\n", address);
 #endif
     return 0xff;
 }
@@ -204,7 +249,7 @@
 void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
 {
 #ifdef DEBUG_UNUSED_IOPORT
-    fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data);
+    fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data);
 #endif
 }
 
@@ -228,7 +273,7 @@
 uint32_t default_ioport_readl(void *opaque, uint32_t address)
 {
 #ifdef DEBUG_UNUSED_IOPORT
-    fprintf(stderr, "inl: port=0x%04x\n", address);
+    fprintf(stderr, "unused inl: port=0x%04x\n", address);
 #endif
     return 0xffffffff;
 }
@@ -236,7 +281,7 @@
 void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
 {
 #ifdef DEBUG_UNUSED_IOPORT
-    fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data);
+    fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data);
 #endif
 }
 
@@ -255,7 +300,7 @@
 }
 
 /* size is the word size in byte */
-int register_ioport_read(int start, int length, int size, 
+int register_ioport_read(int start, int length, int size,
                          IOPortReadFunc *func, void *opaque)
 {
     int i, bsize;
@@ -280,7 +325,7 @@
 }
 
 /* size is the word size in byte */
-int register_ioport_write(int start, int length, int size, 
+int register_ioport_write(int start, int length, int size,
                           IOPortWriteFunc *func, void *opaque)
 {
     int i, bsize;
@@ -326,7 +371,7 @@
 #ifdef DEBUG_IOPORT
     if (loglevel & CPU_LOG_IOPORT)
         fprintf(logfile, "outb: %04x %02x\n", addr, val);
-#endif    
+#endif
     ioport_write_table[0][addr](ioport_opaque[addr], addr, val);
 #ifdef USE_KQEMU
     if (env)
@@ -339,7 +384,7 @@
 #ifdef DEBUG_IOPORT
     if (loglevel & CPU_LOG_IOPORT)
         fprintf(logfile, "outw: %04x %04x\n", addr, val);
-#endif    
+#endif
     ioport_write_table[1][addr](ioport_opaque[addr], addr, val);
 #ifdef USE_KQEMU
     if (env)
@@ -516,6 +561,7 @@
 {
     QEMUPutMouseEvent *mouse_event;
     void *mouse_event_opaque;
+    int width;
 
     if (!qemu_put_mouse_event_current) {
         return;
@@ -527,7 +573,16 @@
         qemu_put_mouse_event_current->qemu_put_mouse_event_opaque;
 
     if (mouse_event) {
-        mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state);
+        if (graphic_rotate) {
+            if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute)
+                width = 0x7fff;
+            else
+                width = graphic_width;
+            mouse_event(mouse_event_opaque,
+                                 width - dy, dx, dz, buttons_state);
+        } else
+            mouse_event(mouse_event_opaque,
+                                 dx, dy, dz, buttons_state);
     }
 }
 
@@ -592,7 +647,7 @@
             uint32_t high, low;
 #else
             uint32_t low, high;
-#endif            
+#endif
         } l;
     } u, res;
     uint64_t rl, rh;
@@ -658,7 +713,7 @@
         struct timespec ts;
         clock_gettime(CLOCK_MONOTONIC, &ts);
         return ts.tv_sec * 1000000000LL + ts.tv_nsec;
-    } else 
+    } else
 #endif
     {
         /* XXX: using gettimeofday leads to problems if the date
@@ -732,7 +787,7 @@
 
 /***********************************************************/
 /* timers */
- 
+
 #define QEMU_TIMER_REALTIME 0
 #define QEMU_TIMER_VIRTUAL  1
 
@@ -749,18 +804,158 @@
     struct QEMUTimer *next;
 };
 
+struct qemu_alarm_timer {
+    char const *name;
+    unsigned int flags;
+
+    int (*start)(struct qemu_alarm_timer *t);
+    void (*stop)(struct qemu_alarm_timer *t);
+    void (*rearm)(struct qemu_alarm_timer *t);
+    void *priv;
+};
+
+#define ALARM_FLAG_DYNTICKS  0x1
+
+static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
+{
+    return t->flags & ALARM_FLAG_DYNTICKS;
+}
+
+static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
+{
+    if (!alarm_has_dynticks(t))
+        return;
+
+    t->rearm(t);
+}
+
+/* TODO: MIN_TIMER_REARM_US should be optimized */
+#define MIN_TIMER_REARM_US 250
+
+static struct qemu_alarm_timer *alarm_timer;
+
+#ifdef _WIN32
+
+struct qemu_alarm_win32 {
+    MMRESULT timerId;
+    HANDLE host_alarm;
+    unsigned int period;
+} alarm_win32_data = {0, NULL, -1};
+
+static int win32_start_timer(struct qemu_alarm_timer *t);
+static void win32_stop_timer(struct qemu_alarm_timer *t);
+static void win32_rearm_timer(struct qemu_alarm_timer *t);
+
+#else
+
+static int unix_start_timer(struct qemu_alarm_timer *t);
+static void unix_stop_timer(struct qemu_alarm_timer *t);
+
+#ifdef __linux__
+
+static int dynticks_start_timer(struct qemu_alarm_timer *t);
+static void dynticks_stop_timer(struct qemu_alarm_timer *t);
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
+
+static int hpet_start_timer(struct qemu_alarm_timer *t);
+static void hpet_stop_timer(struct qemu_alarm_timer *t);
+
+static int rtc_start_timer(struct qemu_alarm_timer *t);
+static void rtc_stop_timer(struct qemu_alarm_timer *t);
+
+#endif /* __linux__ */
+
+#endif /* _WIN32 */
+
+static struct qemu_alarm_timer alarm_timers[] = {
+#ifndef _WIN32
+#ifdef __linux__
+    {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer,
+     dynticks_stop_timer, dynticks_rearm_timer, NULL},
+    /* HPET - if available - is preferred */
+    {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL},
+    /* ...otherwise try RTC */
+    {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL},
+#endif
+    {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL},
+#else
+    {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer,
+     win32_stop_timer, win32_rearm_timer, &alarm_win32_data},
+    {"win32", 0, win32_start_timer,
+     win32_stop_timer, NULL, &alarm_win32_data},
+#endif
+    {NULL, }
+};
+
+static void show_available_alarms()
+{
+    int i;
+
+    printf("Available alarm timers, in order of precedence:\n");
+    for (i = 0; alarm_timers[i].name; i++)
+        printf("%s\n", alarm_timers[i].name);
+}
+
+static void configure_alarms(char const *opt)
+{
+    int i;
+    int cur = 0;
+    int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;
+    char *arg;
+    char *name;
+
+    if (!strcmp(opt, "help")) {
+        show_available_alarms();
+        exit(0);
+    }
+
+    arg = strdup(opt);
+
+    /* Reorder the array */
+    name = strtok(arg, ",");
+    while (name) {
+        struct qemu_alarm_timer tmp;
+
+        for (i = 0; i < count && alarm_timers[i].name; i++) {
+            if (!strcmp(alarm_timers[i].name, name))
+                break;
+        }
+
+        if (i == count) {
+            fprintf(stderr, "Unknown clock %s\n", name);
+            goto next;
+        }
+
+        if (i < cur)
+            /* Ignore */
+            goto next;
+
+	/* Swap */
+        tmp = alarm_timers[i];
+        alarm_timers[i] = alarm_timers[cur];
+        alarm_timers[cur] = tmp;
+
+        cur++;
+next:
+        name = strtok(NULL, ",");
+    }
+
+    free(arg);
+
+    if (cur) {
+	/* Disable remaining timers */
+        for (i = cur; i < count; i++)
+            alarm_timers[i].name = NULL;
+    }
+
+    /* debug */
+    show_available_alarms();
+}
+
 QEMUClock *rt_clock;
 QEMUClock *vm_clock;
 
 static QEMUTimer *active_timers[2];
-#ifdef _WIN32
-static MMRESULT timerID;
-static HANDLE host_alarm = NULL;
-static unsigned int period = 1;
-#else
-/* frequency of the times() clock tick */
-static int timer_freq;
-#endif
 
 QEMUClock *qemu_new_clock(int type)
 {
@@ -806,6 +1001,8 @@
         }
         pt = &t->next;
     }
+
+    qemu_rearm_alarm_timer(alarm_timer);
 }
 
 /* modify the current timer so that it will be fired when current_time
@@ -824,7 +1021,7 @@
         t = *pt;
         if (!t)
             break;
-        if (t->expire_time > expire_time) 
+        if (t->expire_time > expire_time)
             break;
         pt = &t->next;
     }
@@ -853,7 +1050,7 @@
 static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time)
 {
     QEMUTimer *ts;
-    
+
     for(;;) {
         ts = *ptimer_head;
         if (!ts || ts->expire_time > current_time)
@@ -861,10 +1058,11 @@
         /* remove timer from the list before calling the callback */
         *ptimer_head = ts->next;
         ts->next = NULL;
-        
+
         /* run the callback (the timer list can be modified) */
         ts->cb(ts->opaque);
     }
+    qemu_rearm_alarm_timer(alarm_timer);
 }
 
 int64_t qemu_get_clock(QEMUClock *clock)
@@ -937,7 +1135,7 @@
 }
 
 #ifdef _WIN32
-void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg, 
+void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
                                  DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
 #else
 static void host_alarm_handler(int host_signum)
@@ -972,12 +1170,14 @@
         last_clock = ti;
     }
 #endif
-    if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
+    if (alarm_has_dynticks(alarm_timer) ||
+        qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
                            qemu_get_clock(vm_clock)) ||
         qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
                            qemu_get_clock(rt_clock))) {
 #ifdef _WIN32
-        SetEvent(host_alarm);
+        struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
+        SetEvent(data->host_alarm);
 #endif
         CPUState *env = cpu_single_env;
         if (env) {
@@ -992,18 +1192,107 @@
     }
 }
 
+static uint64_t qemu_next_deadline(void)
+{
+    int64_t nearest_delta_us = UINT64_MAX;
+    int64_t vmdelta_us;
+
+    if (active_timers[QEMU_TIMER_REALTIME])
+        nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
+                            qemu_get_clock(rt_clock))*1000;
+
+    if (active_timers[QEMU_TIMER_VIRTUAL]) {
+        /* round up */
+        vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
+                      qemu_get_clock(vm_clock)+999)/1000;
+        if (vmdelta_us < nearest_delta_us)
+            nearest_delta_us = vmdelta_us;
+    }
+
+    /* Avoid arming the timer to negative, zero, or too low values */
+    if (nearest_delta_us <= MIN_TIMER_REARM_US)
+        nearest_delta_us = MIN_TIMER_REARM_US;
+
+    return nearest_delta_us;
+}
+
 #ifndef _WIN32
 
 #if defined(__linux__)
 
 #define RTC_FREQ 1024
 
-static int use_rtc = 1;
-static int rtc_fd;
-
-static int start_rtc_timer(void)
+static void enable_sigio_timer(int fd)
 {
-    rtc_fd = open("/dev/rtc", O_RDONLY);
+    struct sigaction act;
+
+    /* timer signal */
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+#if defined (TARGET_I386) && defined(USE_CODE_COPY)
+    act.sa_flags |= SA_ONSTACK;
+#endif
+    act.sa_handler = host_alarm_handler;
+
+    sigaction(SIGIO, &act, NULL);
+    fcntl(fd, F_SETFL, O_ASYNC);
+    fcntl(fd, F_SETOWN, getpid());
+}
+
+static int hpet_start_timer(struct qemu_alarm_timer *t)
+{
+    struct hpet_info info;
+    int r, fd;
+
+    fd = open("/dev/hpet", O_RDONLY);
+    if (fd < 0)
+        return -1;
+
+    /* Set frequency */
+    r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
+    if (r < 0) {
+        fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
+                "error, but for better emulation accuracy type:\n"
+                "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
+        goto fail;
+    }
+
+    /* Check capabilities */
+    r = ioctl(fd, HPET_INFO, &info);
+    if (r < 0)
+        goto fail;
+
+    /* Enable periodic mode */
+    r = ioctl(fd, HPET_EPI, 0);
+    if (info.hi_flags && (r < 0))
+        goto fail;
+
+    /* Enable interrupt */
+    r = ioctl(fd, HPET_IE_ON, 0);
+    if (r < 0)
+        goto fail;
+
+    enable_sigio_timer(fd);
+    t->priv = (void *)(long)fd;
+
+    return 0;
+fail:
+    close(fd);
+    return -1;
+}
+
+static void hpet_stop_timer(struct qemu_alarm_timer *t)
+{
+    int fd = (long)t->priv;
+
+    close(fd);
+}
+
+static int rtc_start_timer(struct qemu_alarm_timer *t)
+{
+    int rtc_fd;
+
+    TFR(rtc_fd = open("/dev/rtc", O_RDONLY));
     if (rtc_fd < 0)
         return -1;
     if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
@@ -1017,117 +1306,250 @@
         close(rtc_fd);
         return -1;
     }
-    pit_min_timer_count = PIT_FREQ / RTC_FREQ;
+
+    enable_sigio_timer(rtc_fd);
+
+    t->priv = (void *)(long)rtc_fd;
+
     return 0;
 }
 
-#else
-
-static int start_rtc_timer(void)
+static void rtc_stop_timer(struct qemu_alarm_timer *t)
 {
-    return -1;
+    int rtc_fd = (long)t->priv;
+
+    close(rtc_fd);
 }
 
-#endif /* !defined(__linux__) */
+static int dynticks_start_timer(struct qemu_alarm_timer *t)
+{
+    struct sigevent ev;
+    timer_t host_timer;
+    struct sigaction act;
+
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+#if defined(TARGET_I386) && defined(USE_CODE_COPY)
+    act.sa_flags |= SA_ONSTACK;
+#endif
+    act.sa_handler = host_alarm_handler;
+
+    sigaction(SIGALRM, &act, NULL);
+
+    ev.sigev_value.sival_int = 0;
+    ev.sigev_notify = SIGEV_SIGNAL;
+    ev.sigev_signo = SIGALRM;
+
+    if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
+        perror("timer_create");
+
+        /* disable dynticks */
+        fprintf(stderr, "Dynamic Ticks disabled\n");
+
+        return -1;
+    }
+
+    t->priv = (void *)host_timer;
+
+    return 0;
+}
+
+static void dynticks_stop_timer(struct qemu_alarm_timer *t)
+{
+    timer_t host_timer = (timer_t)t->priv;
+
+    timer_delete(host_timer);
+}
+
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
+{
+    timer_t host_timer = (timer_t)t->priv;
+    struct itimerspec timeout;
+    int64_t nearest_delta_us = INT64_MAX;
+    int64_t current_us;
+
+    if (!active_timers[QEMU_TIMER_REALTIME] &&
+                !active_timers[QEMU_TIMER_VIRTUAL])
+            return;
+
+    nearest_delta_us = qemu_next_deadline();
+
+    /* check whether a timer is already running */
+    if (timer_gettime(host_timer, &timeout)) {
+        perror("gettime");
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
+    current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
+    if (current_us && current_us <= nearest_delta_us)
+        return;
+
+    timeout.it_interval.tv_sec = 0;
+    timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
+    timeout.it_value.tv_sec =  nearest_delta_us / 1000000;
+    timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000;
+    if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
+        perror("settime");
+        fprintf(stderr, "Internal timer error: aborting\n");
+        exit(1);
+    }
+}
+
+#endif /* defined(__linux__) */
+
+static int unix_start_timer(struct qemu_alarm_timer *t)
+{
+    struct sigaction act;
+    struct itimerval itv;
+    int err;
+
+    /* timer signal */
+    sigfillset(&act.sa_mask);
+    act.sa_flags = 0;
+#if defined(TARGET_I386) && defined(USE_CODE_COPY)
+    act.sa_flags |= SA_ONSTACK;
+#endif
+    act.sa_handler = host_alarm_handler;
+
+    sigaction(SIGALRM, &act, NULL);
+
+    itv.it_interval.tv_sec = 0;
+    /* for i386 kernel 2.6 to get 1 ms */
+    itv.it_interval.tv_usec = 999;
+    itv.it_value.tv_sec = 0;
+    itv.it_value.tv_usec = 10 * 1000;
+
+    err = setitimer(ITIMER_REAL, &itv, NULL);
+    if (err)
+        return -1;
+
+    return 0;
+}
+
+static void unix_stop_timer(struct qemu_alarm_timer *t)
+{
+    struct itimerval itv;
+
+    memset(&itv, 0, sizeof(itv));
+    setitimer(ITIMER_REAL, &itv, NULL);
+}
 
 #endif /* !defined(_WIN32) */
 
+#ifdef _WIN32
+
+static int win32_start_timer(struct qemu_alarm_timer *t)
+{
+    TIMECAPS tc;
+    struct qemu_alarm_win32 *data = t->priv;
+    UINT flags;
+
+    data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
+    if (!data->host_alarm) {
+        perror("Failed CreateEvent");
+        return -1;
+    }
+
+    memset(&tc, 0, sizeof(tc));
+    timeGetDevCaps(&tc, sizeof(tc));
+
+    if (data->period < tc.wPeriodMin)
+        data->period = tc.wPeriodMin;
+
+    timeBeginPeriod(data->period);
+
+    flags = TIME_CALLBACK_FUNCTION;
+    if (alarm_has_dynticks(t))
+        flags |= TIME_ONESHOT;
+    else
+        flags |= TIME_PERIODIC;
+
+    data->timerId = timeSetEvent(1,         // interval (ms)
+                        data->period,       // resolution
+                        host_alarm_handler, // function
+                        (DWORD)t,           // parameter
+                        flags);
+
+    if (!data->timerId) {
+        perror("Failed to initialize win32 alarm timer");
+
+        timeEndPeriod(data->period);
+        CloseHandle(data->host_alarm);
+        return -1;
+    }
+
+    qemu_add_wait_object(data->host_alarm, NULL, NULL);
+
+    return 0;
+}
+
+static void win32_stop_timer(struct qemu_alarm_timer *t)
+{
+    struct qemu_alarm_win32 *data = t->priv;
+
+    timeKillEvent(data->timerId);
+    timeEndPeriod(data->period);
+
+    CloseHandle(data->host_alarm);
+}
+
+static void win32_rearm_timer(struct qemu_alarm_timer *t)
+{
+    struct qemu_alarm_win32 *data = t->priv;
+    uint64_t nearest_delta_us;
+
+    if (!active_timers[QEMU_TIMER_REALTIME] &&
+                !active_timers[QEMU_TIMER_VIRTUAL])
+            return;
+
+    nearest_delta_us = qemu_next_deadline();
+    nearest_delta_us /= 1000;
+
+    timeKillEvent(data->timerId);
+
+    data->timerId = timeSetEvent(1,
+                        data->period,
+                        host_alarm_handler,
+                        (DWORD)t,
+                        TIME_ONESHOT | TIME_PERIODIC);
+
+    if (!data->timerId) {
+        perror("Failed to re-arm win32 alarm timer");
+
+        timeEndPeriod(data->period);
+        CloseHandle(data->host_alarm);
+        exit(1);
+    }
+}
+
+#endif /* _WIN32 */
+
 static void init_timer_alarm(void)
 {
-#ifdef _WIN32
-    {
-        int count=0;
-        TIMECAPS tc;
+    struct qemu_alarm_timer *t;
+    int i, err = -1;
 
-        ZeroMemory(&tc, sizeof(TIMECAPS));
-        timeGetDevCaps(&tc, sizeof(TIMECAPS));
-        if (period < tc.wPeriodMin)
-            period = tc.wPeriodMin;
-        timeBeginPeriod(period);
-        timerID = timeSetEvent(1,     // interval (ms)
-                               period,     // resolution
-                               host_alarm_handler, // function
-                               (DWORD)&count,  // user parameter
-                               TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
- 	if( !timerID ) {
-            perror("failed timer alarm");
-            exit(1);
- 	}
-        host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
-        if (!host_alarm) {
-            perror("failed CreateEvent");
-            exit(1);
-        }
-        qemu_add_wait_object(host_alarm, NULL, NULL);
+    for (i = 0; alarm_timers[i].name; i++) {
+        t = &alarm_timers[i];
+
+        err = t->start(t);
+        if (!err)
+            break;
     }
-    pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000;
-#else
-    {
-        struct sigaction act;
-        struct itimerval itv;
-        
-        /* get times() syscall frequency */
-        timer_freq = sysconf(_SC_CLK_TCK);
-        
-        /* timer signal */
-        sigfillset(&act.sa_mask);
-       act.sa_flags = 0;
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
-        act.sa_flags |= SA_ONSTACK;
-#endif
-        act.sa_handler = host_alarm_handler;
-        sigaction(SIGALRM, &act, NULL);
 
-        itv.it_interval.tv_sec = 0;
-        itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */
-        itv.it_value.tv_sec = 0;
-        itv.it_value.tv_usec = 10 * 1000;
-        setitimer(ITIMER_REAL, &itv, NULL);
-        /* we probe the tick duration of the kernel to inform the user if
-           the emulated kernel requested a too high timer frequency */
-        getitimer(ITIMER_REAL, &itv);
-
-#if defined(__linux__)
-        /* XXX: force /dev/rtc usage because even 2.6 kernels may not
-           have timers with 1 ms resolution. The correct solution will
-           be to use the POSIX real time timers available in recent
-           2.6 kernels */
-        if (itv.it_interval.tv_usec > 1000 || 1) {
-            /* try to use /dev/rtc to have a faster timer */
-            if (!use_rtc || (start_rtc_timer() < 0))
-                goto use_itimer;
-            /* disable itimer */
-            itv.it_interval.tv_sec = 0;
-            itv.it_interval.tv_usec = 0;
-            itv.it_value.tv_sec = 0;
-            itv.it_value.tv_usec = 0;
-            setitimer(ITIMER_REAL, &itv, NULL);
-
-            /* use the RTC */
-            sigaction(SIGIO, &act, NULL);
-            fcntl(rtc_fd, F_SETFL, O_ASYNC);
-            fcntl(rtc_fd, F_SETOWN, getpid());
-        } else 
-#endif /* defined(__linux__) */
-        {
-        use_itimer:
-            pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec * 
-                                   PIT_FREQ) / 1000000;
-        }
+    if (err) {
+        fprintf(stderr, "Unable to find any suitable alarm timer.\n");
+        fprintf(stderr, "Terminating\n");
+        exit(1);
     }
-#endif
+
+    alarm_timer = t;
 }
 
 void quit_timers(void)
 {
-#ifdef _WIN32
-    timeKillEvent(timerID);
-    timeEndPeriod(period);
-    if (host_alarm) {
-        CloseHandle(host_alarm);
-        host_alarm = NULL;
-    }
-#endif
+    alarm_timer->stop(alarm_timer);
+    alarm_timer = NULL;
 }
 
 /***********************************************************/
@@ -1197,8 +1619,8 @@
         s->chr_send_event(s, event);
 }
 
-void qemu_chr_add_handlers(CharDriverState *s, 
-                           IOCanRWHandler *fd_can_read, 
+void qemu_chr_add_handlers(CharDriverState *s,
+                           IOCanRWHandler *fd_can_read,
                            IOReadHandler *fd_read,
                            IOEventHandler *fd_event,
                            void *opaque)
@@ -1210,7 +1632,7 @@
     if (s->chr_update_read_handler)
         s->chr_update_read_handler(s);
 }
-             
+
 static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
     return len;
@@ -1227,6 +1649,219 @@
     return chr;
 }
 
+/* MUX driver for serial I/O splitting */
+static int term_timestamps;
+static int64_t term_timestamps_start;
+#define MAX_MUX 4
+typedef struct {
+    IOCanRWHandler *chr_can_read[MAX_MUX];
+    IOReadHandler *chr_read[MAX_MUX];
+    IOEventHandler *chr_event[MAX_MUX];
+    void *ext_opaque[MAX_MUX];
+    CharDriverState *drv;
+    int mux_cnt;
+    int term_got_escape;
+    int max_size;
+} MuxDriver;
+
+
+static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+    MuxDriver *d = chr->opaque;
+    int ret;
+    if (!term_timestamps) {
+        ret = d->drv->chr_write(d->drv, buf, len);
+    } else {
+        int i;
+
+        ret = 0;
+        for(i = 0; i < len; i++) {
+            ret += d->drv->chr_write(d->drv, buf+i, 1);
+            if (buf[i] == '\n') {
+                char buf1[64];
+                int64_t ti;
+                int secs;
+
+                ti = get_clock();
+                if (term_timestamps_start == -1)
+                    term_timestamps_start = ti;
+                ti -= term_timestamps_start;
+                secs = ti / 1000000000;
+                snprintf(buf1, sizeof(buf1),
+                         "[%02d:%02d:%02d.%03d] ",
+                         secs / 3600,
+                         (secs / 60) % 60,
+                         secs % 60,
+                         (int)((ti / 1000000) % 1000));
+                d->drv->chr_write(d->drv, buf1, strlen(buf1));
+            }
+        }
+    }
+    return ret;
+}
+
+static char *mux_help[] = {
+    "% h    print this help\n\r",
+    "% x    exit emulator\n\r",
+    "% s    save disk data back to file (if -snapshot)\n\r",
+    "% t    toggle console timestamps\n\r"
+    "% b    send break (magic sysrq)\n\r",
+    "% c    switch between console and monitor\n\r",
+    "% %  sends %\n\r",
+    NULL
+};
+
+static int term_escape_char = 0x01; /* ctrl-a is used for escape */
+static void mux_print_help(CharDriverState *chr)
+{
+    int i, j;
+    char ebuf[15] = "Escape-Char";
+    char cbuf[50] = "\n\r";
+
+    if (term_escape_char > 0 && term_escape_char < 26) {
+        sprintf(cbuf,"\n\r");
+        sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a');
+    } else {
+        sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", term_escape_char);
+    }
+    chr->chr_write(chr, cbuf, strlen(cbuf));
+    for (i = 0; mux_help[i] != NULL; i++) {
+        for (j=0; mux_help[i][j] != '\0'; j++) {
+            if (mux_help[i][j] == '%')
+                chr->chr_write(chr, ebuf, strlen(ebuf));
+            else
+                chr->chr_write(chr, &mux_help[i][j], 1);
+        }
+    }
+}
+
+static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
+{
+    if (d->term_got_escape) {
+        d->term_got_escape = 0;
+        if (ch == term_escape_char)
+            goto send_char;
+        switch(ch) {
+        case '?':
+        case 'h':
+            mux_print_help(chr);
+            break;
+        case 'x':
+            {
+                 char *term =  "QEMU: Terminated\n\r";
+                 chr->chr_write(chr,term,strlen(term));
+                 exit(0);
+                 break;
+            }
+        case 's':
+            {
+                int i;
+                for (i = 0; i < MAX_DISKS; i++) {
+                    if (bs_table[i])
+                        bdrv_commit(bs_table[i]);
+                }
+                if (mtd_bdrv)
+                    bdrv_commit(mtd_bdrv);
+            }
+            break;
+        case 'b':
+            qemu_chr_event(chr, CHR_EVENT_BREAK);
+            break;
+        case 'c':
+            /* Switch to the next registered device */
+            chr->focus++;
+            if (chr->focus >= d->mux_cnt)
+                chr->focus = 0;
+            break;
+       case 't':
+           term_timestamps = !term_timestamps;
+           term_timestamps_start = -1;
+           break;
+        }
+    } else if (ch == term_escape_char) {
+        d->term_got_escape = 1;
+    } else {
+    send_char:
+        return 1;
+    }
+    return 0;
+}
+
+static int mux_chr_can_read(void *opaque)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    if (d->chr_can_read[chr->focus])
+       return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
+    return 0;
+}
+
+static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int i;
+    for(i = 0; i < size; i++)
+        if (mux_proc_byte(chr, d, buf[i]))
+            d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1);
+}
+
+static void mux_chr_event(void *opaque, int event)
+{
+    CharDriverState *chr = opaque;
+    MuxDriver *d = chr->opaque;
+    int i;
+
+    /* Send the event to all registered listeners */
+    for (i = 0; i < d->mux_cnt; i++)
+        if (d->chr_event[i])
+            d->chr_event[i](d->ext_opaque[i], event);
+}
+
+static void mux_chr_update_read_handler(CharDriverState *chr)
+{
+    MuxDriver *d = chr->opaque;
+
+    if (d->mux_cnt >= MAX_MUX) {
+        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
+        return;
+    }
+    d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
+    d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
+    d->chr_read[d->mux_cnt] = chr->chr_read;
+    d->chr_event[d->mux_cnt] = chr->chr_event;
+    /* Fix up the real driver with mux routines */
+    if (d->mux_cnt == 0) {
+        qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
+                              mux_chr_event, chr);
+    }
+    chr->focus = d->mux_cnt;
+    d->mux_cnt++;
+}
+
+CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+{
+    CharDriverState *chr;
+    MuxDriver *d;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr)
+        return NULL;
+    d = qemu_mallocz(sizeof(MuxDriver));
+    if (!d) {
+        free(chr);
+        return NULL;
+    }
+
+    chr->opaque = d;
+    d->drv = drv;
+    chr->focus = -1;
+    chr->chr_write = mux_chr_write;
+    chr->chr_update_read_handler = mux_chr_update_read_handler;
+    return chr;
+}
+
+
 #ifdef _WIN32
 
 static void socket_cleanup(void)
@@ -1252,7 +1887,7 @@
 static int send_all(int fd, const uint8_t *buf, int len1)
 {
     int ret, len;
-    
+
     len = len1;
     while (len > 0) {
         ret = send(fd, buf, len, 0);
@@ -1318,10 +1953,8 @@
     int max_size;
 } FDCharDriver;
 
-#define STDIO_MAX_CLIENTS 2
-
-static int stdio_nb_clients;
-static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients = 0;
 
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
 {
@@ -1344,7 +1977,7 @@
     FDCharDriver *s = chr->opaque;
     int size, len;
     uint8_t buf[1024];
-    
+
     len = sizeof(buf);
     if (len > s->max_size)
         len = s->max_size;
@@ -1368,7 +2001,7 @@
     if (s->fd_in >= 0) {
         if (nographic && s->fd_in == 0) {
         } else {
-            qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, 
+            qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
                                  fd_chr_read, NULL, chr);
         }
     }
@@ -1403,7 +2036,7 @@
 {
     int fd_out;
 
-    fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666);
+    TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
     if (fd_out < 0)
         return NULL;
     return qemu_chr_open_fd(-1, fd_out);
@@ -1416,14 +2049,14 @@
 
     snprintf(filename_in, 256, "%s.in", filename);
     snprintf(filename_out, 256, "%s.out", filename);
-    fd_in = open(filename_in, O_RDWR | O_BINARY);
-    fd_out = open(filename_out, O_RDWR | O_BINARY);
+    TFR(fd_in = open(filename_in, O_RDWR | O_BINARY));
+    TFR(fd_out = open(filename_out, O_RDWR | O_BINARY));
     if (fd_in < 0 || fd_out < 0) {
 	if (fd_in >= 0)
 	    close(fd_in);
 	if (fd_out >= 0)
 	    close(fd_out);
-        fd_in = fd_out = open(filename, O_RDWR | O_BINARY);
+        TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
         if (fd_in < 0)
             return NULL;
     }
@@ -1434,162 +2067,45 @@
 /* for STDIO, we handle the case where several clients use it
    (nographic mode) */
 
-#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
-
 #define TERM_FIFO_MAX_SIZE 1
 
-static int term_got_escape, client_index;
 static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
 static int term_fifo_size;
-static int term_timestamps;
-static int64_t term_timestamps_start;
-
-void term_print_help(void)
-{
-    printf("\n"
-           "C-a h    print this help\n"
-           "C-a x    exit emulator\n"
-           "C-a s    save disk data back to file (if -snapshot)\n"
-           "C-a b    send break (magic sysrq)\n"
-           "C-a t    toggle console timestamps\n"
-           "C-a c    switch between console and monitor\n"
-           "C-a C-a  send C-a\n"
-           );
-}
-
-/* called when a char is received */
-static void stdio_received_byte(int ch)
-{
-    if (term_got_escape) {
-        term_got_escape = 0;
-        switch(ch) {
-        case 'h':
-            term_print_help();
-            break;
-        case 'x':
-            exit(0);
-            break;
-        case 's': 
-            {
-                int i;
-                for (i = 0; i < MAX_DISKS; i++) {
-                    if (bs_table[i])
-                        bdrv_commit(bs_table[i]);
-                }
-            }
-            break;
-        case 'b':
-            if (client_index < stdio_nb_clients) {
-                CharDriverState *chr;
-                FDCharDriver *s;
-
-                chr = stdio_clients[client_index];
-                s = chr->opaque;
-                qemu_chr_event(chr, CHR_EVENT_BREAK);
-            }
-            break;
-        case 'c':
-            client_index++;
-            if (client_index >= stdio_nb_clients)
-                client_index = 0;
-            if (client_index == 0) {
-                /* send a new line in the monitor to get the prompt */
-                ch = '\r';
-                goto send_char;
-            }
-            break;
-        case 't':
-            term_timestamps = !term_timestamps;
-            term_timestamps_start = -1;
-            break;
-        case TERM_ESCAPE:
-            goto send_char;
-        }
-    } else if (ch == TERM_ESCAPE) {
-        term_got_escape = 1;
-    } else {
-    send_char:
-        if (client_index < stdio_nb_clients) {
-            uint8_t buf[1];
-            CharDriverState *chr;
-            
-            chr = stdio_clients[client_index];
-            if (qemu_chr_can_read(chr) > 0) {
-                buf[0] = ch;
-                qemu_chr_read(chr, buf, 1);
-            } else if (term_fifo_size == 0) {
-                term_fifo[term_fifo_size++] = ch;
-            }
-        }
-    }
-}
 
 static int stdio_read_poll(void *opaque)
 {
-    CharDriverState *chr;
+    CharDriverState *chr = opaque;
 
-    if (client_index < stdio_nb_clients) {
-        chr = stdio_clients[client_index];
-        /* try to flush the queue if needed */
-        if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
-            qemu_chr_read(chr, term_fifo, 1);
-            term_fifo_size = 0;
-        }
-        /* see if we can absorb more chars */
-        if (term_fifo_size == 0)
-            return 1;
-        else
-            return 0;
-    } else {
-        return 1;
+    /* try to flush the queue if needed */
+    if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
+        qemu_chr_read(chr, term_fifo, 1);
+        term_fifo_size = 0;
     }
+    /* see if we can absorb more chars */
+    if (term_fifo_size == 0)
+        return 1;
+    else
+        return 0;
 }
 
 static void stdio_read(void *opaque)
 {
     int size;
     uint8_t buf[1];
-    
+    CharDriverState *chr = opaque;
+
     size = read(0, buf, 1);
     if (size == 0) {
         /* stdin has been closed. Remove it from the active list.  */
         qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
         return;
     }
-    if (size > 0)
-        stdio_received_byte(buf[0]);
-}
-
-static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
-    FDCharDriver *s = chr->opaque;
-    if (!term_timestamps) {
-        return unix_write(s->fd_out, buf, len);
-    } else {
-        int i;
-        char buf1[64];
-
-        for(i = 0; i < len; i++) {
-            unix_write(s->fd_out, buf + i, 1);
-            if (buf[i] == '\n') {
-                int64_t ti;
-                int secs;
-
-                ti = get_clock();
-                if (term_timestamps_start == -1)
-                    term_timestamps_start = ti;
-                ti -= term_timestamps_start;
-                secs = ti / 1000000000;
-                snprintf(buf1, sizeof(buf1), 
-                         "[%02d:%02d:%02d.%03d] ",
-                         secs / 3600,
-                         (secs / 60) % 60,
-                         secs % 60,
-                         (int)((ti / 1000000) % 1000));
-                unix_write(s->fd_out, buf1, strlen(buf1));
-            }
+    if (size > 0) {
+        if (qemu_chr_can_read(chr) > 0) {
+            qemu_chr_read(chr, buf, 1);
+        } else if (term_fifo_size == 0) {
+            term_fifo[term_fifo_size++] = buf[0];
         }
-        return len;
     }
 }
 
@@ -1622,7 +2138,7 @@
     tty.c_cflag |= CS8;
     tty.c_cc[VMIN] = 1;
     tty.c_cc[VTIME] = 0;
-    
+
     tcsetattr (0, TCSANOW, &tty);
 
     atexit(term_exit);
@@ -1634,39 +2150,30 @@
 {
     CharDriverState *chr;
 
-    if (nographic) {
-        if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
-            return NULL;
-        chr = qemu_chr_open_fd(0, 1);
-        chr->chr_write = stdio_write;
-        if (stdio_nb_clients == 0)
-            qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL);
-        client_index = stdio_nb_clients;
-    } else {
-        if (stdio_nb_clients != 0)
-            return NULL;
-        chr = qemu_chr_open_fd(0, 1);
-    }
-    stdio_clients[stdio_nb_clients++] = chr;
-    if (stdio_nb_clients == 1) {
-        /* set the terminal in raw mode */
-        term_init();
-    }
+    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
+        return NULL;
+    chr = qemu_chr_open_fd(0, 1);
+    qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
+    stdio_nb_clients++;
+    term_init();
+
     return chr;
 }
 
-#if defined(__linux__)
+#if defined(__linux__) || defined(__sun__)
 static CharDriverState *qemu_chr_open_pty(void)
 {
     struct termios tty;
     char slave_name[1024];
     int master_fd, slave_fd;
-    
+
+#if defined(__linux__)
     /* Not satisfying */
     if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) {
         return NULL;
     }
-    
+#endif
+
     /* Disabling local echo and line-buffered output */
     tcgetattr (master_fd, &tty);
     tty.c_lflag &= ~(ECHO|ICANON|ISIG);
@@ -1678,14 +2185,14 @@
     return qemu_chr_open_fd(master_fd, master_fd);
 }
 
-static void tty_serial_init(int fd, int speed, 
+static void tty_serial_init(int fd, int speed,
                             int parity, int data_bits, int stop_bits)
 {
     struct termios tty;
     speed_t spd;
 
 #if 0
-    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", 
+    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
            speed, parity, data_bits, stop_bits);
 #endif
     tcgetattr (fd, &tty);
@@ -1766,19 +2273,19 @@
     }
     if (stop_bits == 2)
         tty.c_cflag |= CSTOPB;
-    
+
     tcsetattr (fd, TCSANOW, &tty);
 }
 
 static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
     FDCharDriver *s = chr->opaque;
-    
+
     switch(cmd) {
     case CHR_IOCTL_SERIAL_SET_PARAMS:
         {
             QEMUSerialSetParams *ssp = arg;
-            tty_serial_init(s->fd_in, ssp->speed, ssp->parity, 
+            tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
                             ssp->data_bits, ssp->stop_bits);
         }
         break;
@@ -1800,22 +2307,46 @@
     CharDriverState *chr;
     int fd;
 
-    fd = open(filename, O_RDWR | O_NONBLOCK);
-    if (fd < 0)
-        return NULL;
+    TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
     fcntl(fd, F_SETFL, O_NONBLOCK);
     tty_serial_init(fd, 115200, 'N', 8, 1);
     chr = qemu_chr_open_fd(fd, fd);
-    if (!chr)
+    if (!chr) {
+        close(fd);
         return NULL;
+    }
     chr->chr_ioctl = tty_serial_ioctl;
     qemu_chr_reset(chr);
     return chr;
 }
+#else  /* ! __linux__ && ! __sun__ */
+static CharDriverState *qemu_chr_open_pty(void)
+{
+    return NULL;
+}
+#endif /* __linux__ || __sun__ */
+
+#if defined(__linux__)
+typedef struct {
+    int fd;
+    int mode;
+} ParallelCharDriver;
+
+static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
+{
+    if (s->mode != mode) {
+	int m = mode;
+        if (ioctl(s->fd, PPSETMODE, &m) < 0)
+            return 0;
+	s->mode = mode;
+    }
+    return 1;
+}
 
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
-    int fd = (int)chr->opaque;
+    ParallelCharDriver *drv = chr->opaque;
+    int fd = drv->fd;
     uint8_t b;
 
     switch(cmd) {
@@ -1832,7 +2363,10 @@
     case CHR_IOCTL_PP_READ_CONTROL:
         if (ioctl(fd, PPRCONTROL, &b) < 0)
             return -ENOTSUP;
-        *(uint8_t *)arg = b;
+	/* Linux gives only the lowest bits, and no way to know data
+	   direction! For better compatibility set the fixed upper
+	   bits. */
+        *(uint8_t *)arg = b | 0xc0;
         break;
     case CHR_IOCTL_PP_WRITE_CONTROL:
         b = *(uint8_t *)arg;
@@ -1844,18 +2378,66 @@
             return -ENOTSUP;
         *(uint8_t *)arg = b;
         break;
+    case CHR_IOCTL_PP_EPP_READ_ADDR:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = read(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_READ:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = read(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = write(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
+    case CHR_IOCTL_PP_EPP_WRITE:
+	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+	    struct ParallelIOArg *parg = arg;
+	    int n = write(fd, parg->buffer, parg->count);
+	    if (n != parg->count) {
+		return -EIO;
+	    }
+	}
+        break;
     default:
         return -ENOTSUP;
     }
     return 0;
 }
 
+static void pp_close(CharDriverState *chr)
+{
+    ParallelCharDriver *drv = chr->opaque;
+    int fd = drv->fd;
+
+    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
+    ioctl(fd, PPRELEASE);
+    close(fd);
+    qemu_free(drv);
+}
+
 static CharDriverState *qemu_chr_open_pp(const char *filename)
 {
     CharDriverState *chr;
+    ParallelCharDriver *drv;
     int fd;
 
-    fd = open(filename, O_RDWR);
+    TFR(fd = open(filename, O_RDWR));
     if (fd < 0)
         return NULL;
 
@@ -1864,32 +2446,34 @@
         return NULL;
     }
 
-    chr = qemu_mallocz(sizeof(CharDriverState));
-    if (!chr) {
+    drv = qemu_mallocz(sizeof(ParallelCharDriver));
+    if (!drv) {
         close(fd);
         return NULL;
     }
-    chr->opaque = (void *)fd;
+    drv->fd = fd;
+    drv->mode = IEEE1284_MODE_COMPAT;
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr) {
+	qemu_free(drv);
+        close(fd);
+        return NULL;
+    }
     chr->chr_write = null_chr_write;
     chr->chr_ioctl = pp_ioctl;
+    chr->chr_close = pp_close;
+    chr->opaque = drv;
 
     qemu_chr_reset(chr);
 
     return chr;
 }
+#endif /* __linux__ */
 
-#else
-static CharDriverState *qemu_chr_open_pty(void)
-{
-    return NULL;
-}
-#endif
+#else /* _WIN32 */
 
-#endif /* !defined(_WIN32) */
-
-#ifdef _WIN32
 typedef struct {
-    CharDriverState *chr;
     int max_size;
     HANDLE hcom, hrecv, hsend;
     OVERLAPPED orecv, osend;
@@ -1905,8 +2489,10 @@
 static int win_chr_poll(void *opaque);
 static int win_chr_pipe_poll(void *opaque);
 
-static void win_chr_close2(WinCharState *s)
+static void win_chr_close(CharDriverState *chr)
 {
+    WinCharState *s = chr->opaque;
+
     if (s->hsend) {
         CloseHandle(s->hsend);
         s->hsend = NULL;
@@ -1920,25 +2506,20 @@
         s->hcom = NULL;
     }
     if (s->fpipe)
-        qemu_del_polling_cb(win_chr_pipe_poll, s);
+        qemu_del_polling_cb(win_chr_pipe_poll, chr);
     else
-        qemu_del_polling_cb(win_chr_poll, s);
+        qemu_del_polling_cb(win_chr_poll, chr);
 }
 
-static void win_chr_close(CharDriverState *chr)
+static int win_chr_init(CharDriverState *chr, const char *filename)
 {
     WinCharState *s = chr->opaque;
-    win_chr_close2(s);
-}
-
-static int win_chr_init(WinCharState *s, CharDriverState *chr, const char *filename)
-{
     COMMCONFIG comcfg;
     COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
     COMSTAT comstat;
     DWORD size;
     DWORD err;
-    
+
     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!s->hsend) {
         fprintf(stderr, "Failed CreateEvent\n");
@@ -1957,12 +2538,12 @@
         s->hcom = NULL;
         goto fail;
     }
-    
+
     if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
         fprintf(stderr, "Failed SetupComm\n");
         goto fail;
     }
-    
+
     ZeroMemory(&comcfg, sizeof(COMMCONFIG));
     size = sizeof(COMMCONFIG);
     GetDefaultCommConfig(filename, &comcfg, &size);
@@ -1984,17 +2565,16 @@
         fprintf(stderr, "Failed SetCommTimeouts\n");
         goto fail;
     }
-    
+
     if (!ClearCommError(s->hcom, &err, &comstat)) {
         fprintf(stderr, "Failed ClearCommError\n");
         goto fail;
     }
-    s->chr = chr;
-    qemu_add_polling_cb(win_chr_poll, s);
+    qemu_add_polling_cb(win_chr_poll, chr);
     return 0;
 
  fail:
-    win_chr_close2(s);
+    win_chr_close(chr);
     return -1;
 }
 
@@ -2032,18 +2612,21 @@
     return len1 - len;
 }
 
-static int win_chr_read_poll(WinCharState *s)
+static int win_chr_read_poll(CharDriverState *chr)
 {
-    s->max_size = qemu_chr_can_read(s->chr);
+    WinCharState *s = chr->opaque;
+
+    s->max_size = qemu_chr_can_read(chr);
     return s->max_size;
 }
 
-static void win_chr_readfile(WinCharState *s)
+static void win_chr_readfile(CharDriverState *chr)
 {
+    WinCharState *s = chr->opaque;
     int ret, err;
     uint8_t buf[1024];
     DWORD size;
-    
+
     ZeroMemory(&s->orecv, sizeof(s->orecv));
     s->orecv.hEvent = s->hrecv;
     ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
@@ -2055,31 +2638,34 @@
     }
 
     if (size > 0) {
-        qemu_chr_read(s->chr, buf, size);
+        qemu_chr_read(chr, buf, size);
     }
 }
 
-static void win_chr_read(WinCharState *s)
+static void win_chr_read(CharDriverState *chr)
 {
+    WinCharState *s = chr->opaque;
+
     if (s->len > s->max_size)
         s->len = s->max_size;
     if (s->len == 0)
         return;
-    
-    win_chr_readfile(s);
+
+    win_chr_readfile(chr);
 }
 
 static int win_chr_poll(void *opaque)
 {
-    WinCharState *s = opaque;
+    CharDriverState *chr = opaque;
+    WinCharState *s = chr->opaque;
     COMSTAT status;
     DWORD comerr;
-    
+
     ClearCommError(s->hcom, &comerr, &status);
     if (status.cbInQue > 0) {
         s->len = status.cbInQue;
-        win_chr_read_poll(s);
-        win_chr_read(s);
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
         return 1;
     }
     return 0;
@@ -2089,7 +2675,7 @@
 {
     CharDriverState *chr;
     WinCharState *s;
-    
+
     chr = qemu_mallocz(sizeof(CharDriverState));
     if (!chr)
         return NULL;
@@ -2102,7 +2688,7 @@
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
 
-    if (win_chr_init(s, chr, filename) < 0) {
+    if (win_chr_init(chr, filename) < 0) {
         free(s);
         free(chr);
         return NULL;
@@ -2113,26 +2699,28 @@
 
 static int win_chr_pipe_poll(void *opaque)
 {
-    WinCharState *s = opaque;
+    CharDriverState *chr = opaque;
+    WinCharState *s = chr->opaque;
     DWORD size;
 
     PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
     if (size > 0) {
         s->len = size;
-        win_chr_read_poll(s);
-        win_chr_read(s);
+        win_chr_read_poll(chr);
+        win_chr_read(chr);
         return 1;
     }
     return 0;
 }
 
-static int win_chr_pipe_init(WinCharState *s, const char *filename)
+static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
 {
+    WinCharState *s = chr->opaque;
     OVERLAPPED ov;
     int ret;
     DWORD size;
     char openname[256];
-    
+
     s->fpipe = TRUE;
 
     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -2145,7 +2733,7 @@
         fprintf(stderr, "Failed CreateEvent\n");
         goto fail;
     }
-    
+
     snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
     s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
                               PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
@@ -2179,11 +2767,11 @@
         CloseHandle(ov.hEvent);
         ov.hEvent = NULL;
     }
-    qemu_add_polling_cb(win_chr_pipe_poll, s);
+    qemu_add_polling_cb(win_chr_pipe_poll, chr);
     return 0;
 
  fail:
-    win_chr_close2(s);
+    win_chr_close(chr);
     return -1;
 }
 
@@ -2204,8 +2792,8 @@
     chr->opaque = s;
     chr->chr_write = win_chr_write;
     chr->chr_close = win_chr_close;
-    
-    if (win_chr_pipe_init(s, filename) < 0) {
+
+    if (win_chr_pipe_init(chr, filename) < 0) {
         free(s);
         free(chr);
         return NULL;
@@ -2233,11 +2821,16 @@
     qemu_chr_reset(chr);
     return chr;
 }
-    
+
+static CharDriverState *qemu_chr_open_win_con(const char *filename)
+{
+    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
+}
+
 static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
 {
     HANDLE fd_out;
-    
+
     fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
                         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
     if (fd_out == INVALID_HANDLE_VALUE)
@@ -2245,7 +2838,7 @@
 
     return qemu_chr_open_win_file(fd_out);
 }
-#endif
+#endif /* !_WIN32 */
 
 /***********************************************************/
 /* UDP Net console */
@@ -2568,7 +3161,7 @@
     qemu_free(s);
 }
 
-static CharDriverState *qemu_chr_open_tcp(const char *host_str, 
+static CharDriverState *qemu_chr_open_tcp(const char *host_str,
                                           int is_telnet,
 					  int is_unix)
 {
@@ -2631,8 +3224,8 @@
     else
 #endif
 	fd = socket(PF_INET, SOCK_STREAM, 0);
-	
-    if (fd < 0) 
+
+    if (fd < 0)
         goto fail;
 
     if (!is_waitconnect)
@@ -2662,7 +3255,7 @@
 	    val = 1;
 	    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
 	}
-        
+
         ret = bind(fd, addr, addrlen);
         if (ret < 0)
             goto fail;
@@ -2683,6 +3276,10 @@
                 if (err == EINTR || err == EWOULDBLOCK) {
                 } else if (err == EINPROGRESS) {
                     break;
+#ifdef _WIN32
+                } else if (err == WSAEALREADY) {
+                    break;
+#endif
                 } else {
                     goto fail;
                 }
@@ -2698,7 +3295,7 @@
         else
             qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
     }
-    
+
     if (is_listen && is_waitconnect) {
         printf("QEMU waiting for connection on: %s\n", host_str);
         tcp_chr_accept(chr);
@@ -2719,10 +3316,12 @@
     const char *p;
 
     if (!strcmp(filename, "vc")) {
-        return text_console_init(&display_state);
+        return text_console_init(&display_state, 0);
+    } else if (strstart(filename, "vc:", &p)) {
+        return text_console_init(&display_state, p);
     } else if (!strcmp(filename, "null")) {
         return qemu_chr_open_null();
-    } else 
+    } else
     if (strstart(filename, "tcp:", &p)) {
         return qemu_chr_open_tcp(p, 0, 0);
     } else
@@ -2732,6 +3331,16 @@
     if (strstart(filename, "udp:", &p)) {
         return qemu_chr_open_udp(p);
     } else
+    if (strstart(filename, "mon:", &p)) {
+        CharDriverState *drv = qemu_chr_open(p);
+        if (drv) {
+            drv = qemu_chr_open_mux(drv);
+            monitor_init(drv, !nographic);
+            return drv;
+        }
+        printf("Unable to open driver: %s\n", p);
+        return 0;
+    } else
 #ifndef _WIN32
     if (strstart(filename, "unix:", &p)) {
 	return qemu_chr_open_tcp(p, 0, 1);
@@ -2743,23 +3352,27 @@
         return qemu_chr_open_pty();
     } else if (!strcmp(filename, "stdio")) {
         return qemu_chr_open_stdio();
-    } else 
-#endif
+    } else
 #if defined(__linux__)
     if (strstart(filename, "/dev/parport", NULL)) {
         return qemu_chr_open_pp(filename);
-    } else 
+    } else
+#endif
+#if defined(__linux__) || defined(__sun__)
     if (strstart(filename, "/dev/", NULL)) {
         return qemu_chr_open_tty(filename);
-    } else 
+    } else
 #endif
-#ifdef _WIN32
+#else /* !_WIN32 */
     if (strstart(filename, "COM", NULL)) {
         return qemu_chr_open_win(filename);
     } else
     if (strstart(filename, "pipe:", &p)) {
         return qemu_chr_open_win_pipe(p);
     } else
+    if (strstart(filename, "con:", NULL)) {
+        return qemu_chr_open_win_con(filename);
+    } else
     if (strstart(filename, "file:", &p)) {
         return qemu_chr_open_win_file_out(p);
     }
@@ -2810,10 +3423,10 @@
     for(i = 0; i < 6; i++) {
         macaddr[i] = strtol(p, (char **)&p, 16);
         if (i == 5) {
-            if (*p != '\0') 
+            if (*p != '\0')
                 return -1;
         } else {
-            if (*p != ':') 
+            if (*p != ':')
                 return -1;
             p++;
         }
@@ -2979,11 +3592,11 @@
 
     for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
         if (vc != vc1) {
-            if (vc->fd_can_read && !vc->fd_can_read(vc->opaque))
-                return 0;
+            if (vc->fd_can_read && vc->fd_can_read(vc->opaque))
+                return 1;
         }
     }
-    return 1;
+    return 0;
 }
 
 void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
@@ -3040,7 +3653,7 @@
         slirp_inited = 1;
         slirp_init();
     }
-    slirp_vc = qemu_new_vlan_client(vlan, 
+    slirp_vc = qemu_new_vlan_client(vlan,
                                     slirp_receive, NULL, NULL);
     snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector");
     return 0;
@@ -3053,7 +3666,7 @@
     const char *p;
     struct in_addr guest_addr;
     int host_port, guest_port;
-    
+
     if (!slirp_inited) {
         slirp_inited = 1;
         slirp_init();
@@ -3083,11 +3696,11 @@
     }
     if (!inet_aton(buf, &guest_addr))
         goto fail;
-    
+
     guest_port = strtol(p, &r, 0);
     if (r == p)
         goto fail;
-    
+
     if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) {
         fprintf(stderr, "qemu: could not set up redirection\n");
         exit(1);
@@ -3097,7 +3710,7 @@
     fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n");
     exit(1);
 }
-    
+
 #ifndef _WIN32
 
 char smb_dir[1024];
@@ -3116,7 +3729,7 @@
             break;
         if (strcmp(de->d_name, ".") != 0 &&
             strcmp(de->d_name, "..") != 0) {
-            snprintf(filename, sizeof(filename), "%s/%s", 
+            snprintf(filename, sizeof(filename), "%s/%s",
                      smb_dir, de->d_name);
             unlink(filename);
         }
@@ -3144,13 +3757,13 @@
         exit(1);
     }
     snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf");
-    
+
     f = fopen(smb_conf, "w");
     if (!f) {
         fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf);
         exit(1);
     }
-    fprintf(f, 
+    fprintf(f,
             "[global]\n"
             "private dir=%s\n"
             "smb ports=0\n"
@@ -3176,7 +3789,7 @@
 
     snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
              SMBD_COMMAND, smb_conf);
-    
+
     slirp_add_exec(0, smb_cmdline, 4, 139);
 }
 
@@ -3210,7 +3823,15 @@
     uint8_t buf[4096];
     int size;
 
+#ifdef __sun__
+    struct strbuf sbuf;
+    int f = 0;
+    sbuf.maxlen = sizeof(buf);
+    sbuf.buf = buf;
+    size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
+#else
     size = read(s->fd, buf, sizeof(buf));
+#endif
     if (size > 0) {
         qemu_send_packet(s->vc, buf, size);
     }
@@ -3232,14 +3853,14 @@
     return s;
 }
 
-#ifdef _BSD
+#if defined (_BSD) || defined (__FreeBSD_kernel__)
 static int tap_open(char *ifname, int ifname_size)
 {
     int fd;
     char *dev;
     struct stat s;
 
-    fd = open("/dev/tap", O_RDWR);
+    TFR(fd = open("/dev/tap", O_RDWR));
     if (fd < 0) {
         fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
         return -1;
@@ -3253,18 +3874,147 @@
     return fd;
 }
 #elif defined(__sun__)
+#define TUNNEWPPA       (('T'<<16) | 0x0001)
+/*
+ * Allocate TAP device, returns opened fd.
+ * Stores dev name in the first arg(must be large enough).
+ */
+int tap_alloc(char *dev)
+{
+    int tap_fd, if_fd, ppa = -1;
+    static int ip_fd = 0;
+    char *ptr;
+
+    static int arp_fd = 0;
+    int ip_muxid, arp_muxid;
+    struct strioctl  strioc_if, strioc_ppa;
+    int link_type = I_PLINK;;
+    struct lifreq ifr;
+    char actual_name[32] = "";
+
+    memset(&ifr, 0x0, sizeof(ifr));
+
+    if( *dev ){
+       ptr = dev;
+       while( *ptr && !isdigit((int)*ptr) ) ptr++;
+       ppa = atoi(ptr);
+    }
+
+    /* Check if IP device was opened */
+    if( ip_fd )
+       close(ip_fd);
+
+    TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
+    if (ip_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
+       return -1;
+    }
+
+    TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
+    if (tap_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/tap");
+       return -1;
+    }
+
+    /* Assign a new PPA and get its unit number. */
+    strioc_ppa.ic_cmd = TUNNEWPPA;
+    strioc_ppa.ic_timout = 0;
+    strioc_ppa.ic_len = sizeof(ppa);
+    strioc_ppa.ic_dp = (char *)&ppa;
+    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
+       syslog (LOG_ERR, "Can't assign new interface");
+
+    TFR(if_fd = open("/dev/tap", O_RDWR, 0));
+    if (if_fd < 0) {
+       syslog(LOG_ERR, "Can't open /dev/tap (2)");
+       return -1;
+    }
+    if(ioctl(if_fd, I_PUSH, "ip") < 0){
+       syslog(LOG_ERR, "Can't push IP module");
+       return -1;
+    }
+
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+	syslog(LOG_ERR, "Can't get flags\n");
+
+    snprintf (actual_name, 32, "tap%d", ppa);
+    strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));
+
+    ifr.lifr_ppa = ppa;
+    /* Assign ppa according to the unit number returned by tun device */
+
+    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
+        syslog (LOG_ERR, "Can't set PPA %d", ppa);
+    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+        syslog (LOG_ERR, "Can't get flags\n");
+    /* Push arp module to if_fd */
+    if (ioctl (if_fd, I_PUSH, "arp") < 0)
+        syslog (LOG_ERR, "Can't push ARP module (2)");
+
+    /* Push arp module to ip_fd */
+    if (ioctl (ip_fd, I_POP, NULL) < 0)
+        syslog (LOG_ERR, "I_POP failed\n");
+    if (ioctl (ip_fd, I_PUSH, "arp") < 0)
+        syslog (LOG_ERR, "Can't push ARP module (3)\n");
+    /* Open arp_fd */
+    TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
+    if (arp_fd < 0)
+       syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
+
+    /* Set ifname to arp */
+    strioc_if.ic_cmd = SIOCSLIFNAME;
+    strioc_if.ic_timout = 0;
+    strioc_if.ic_len = sizeof(ifr);
+    strioc_if.ic_dp = (char *)&ifr;
+    if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
+        syslog (LOG_ERR, "Can't set ifname to arp\n");
+    }
+
+    if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
+       syslog(LOG_ERR, "Can't link TAP device to IP");
+       return -1;
+    }
+
+    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
+        syslog (LOG_ERR, "Can't link TAP device to ARP");
+
+    close (if_fd);
+
+    memset(&ifr, 0x0, sizeof(ifr));
+    strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));
+    ifr.lifr_ip_muxid  = ip_muxid;
+    ifr.lifr_arp_muxid = arp_muxid;
+
+    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
+    {
+      ioctl (ip_fd, I_PUNLINK , arp_muxid);
+      ioctl (ip_fd, I_PUNLINK, ip_muxid);
+      syslog (LOG_ERR, "Can't set multiplexor id");
+    }
+
+    sprintf(dev, "tap%d", ppa);
+    return tap_fd;
+}
+
 static int tap_open(char *ifname, int ifname_size)
 {
-    fprintf(stderr, "warning: tap_open not yet implemented\n");
-    return -1;
+    char  dev[10]="";
+    int fd;
+    if( (fd = tap_alloc(dev)) < 0 ){
+       fprintf(stderr, "Cannot allocate TAP device\n");
+       return -1;
+    }
+    pstrcpy(ifname, ifname_size, dev);
+    fcntl(fd, F_SETFL, O_NONBLOCK);
+    return fd;
 }
 #else
 static int tap_open(char *ifname, int ifname_size)
 {
     struct ifreq ifr;
     int fd, ret;
-    
-    fd = open("/dev/net/tun", O_RDWR);
+
+    TFR(fd = open("/dev/net/tun", O_RDWR));
     if (fd < 0) {
         fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
         return -1;
@@ -3300,7 +4050,7 @@
         pstrcpy(ifname, sizeof(ifname), ifname1);
     else
         ifname[0] = '\0';
-    fd = tap_open(ifname, sizeof(ifname));
+    TFR(fd = tap_open(ifname, sizeof(ifname)));
     if (fd < 0)
         return -1;
 
@@ -3311,6 +4061,14 @@
         pid = fork();
         if (pid >= 0) {
             if (pid == 0) {
+                int open_max = sysconf (_SC_OPEN_MAX), i;
+                for (i = 0; i < open_max; i++)
+                    if (i != STDIN_FILENO &&
+                        i != STDOUT_FILENO &&
+                        i != STDERR_FILENO &&
+                        i != fd)
+                        close(i);
+
                 parg = args;
                 *parg++ = (char *)setup_script;
                 *parg++ = ifname;
@@ -3330,7 +4088,7 @@
     s = net_tap_fd_init(vlan, fd);
     if (!s)
         return -1;
-    snprintf(s->vc->info_str, sizeof(s->vc->info_str), 
+    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "tap: ifname=%s setup_script=%s", ifname, setup_script);
     return 0;
 }
@@ -3367,7 +4125,7 @@
 static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
 {
     NetSocketState *s = opaque;
-    sendto(s->fd, buf, size, 0, 
+    sendto(s->fd, buf, size, 0,
            (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
 }
 
@@ -3381,7 +4139,7 @@
     size = recv(s->fd, buf1, sizeof(buf1), 0);
     if (size < 0) {
         err = socket_error();
-        if (err != EWOULDBLOCK) 
+        if (err != EWOULDBLOCK)
             goto eoc;
     } else if (size == 0) {
         /* end of connection */
@@ -3433,7 +4191,7 @@
     int size;
 
     size = recv(s->fd, s->buf, sizeof(s->buf), 0);
-    if (size < 0) 
+    if (size < 0)
         return;
     if (size == 0) {
         /* end of connection */
@@ -3450,7 +4208,7 @@
     int val, ret;
     if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
 	fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
-		inet_ntoa(mcastaddr->sin_addr), 
+		inet_ntoa(mcastaddr->sin_addr),
                 (int)ntohl(mcastaddr->sin_addr.s_addr));
 	return -1;
 
@@ -3462,7 +4220,7 @@
     }
 
     val = 1;
-    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, 
+    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                    (const char *)&val, sizeof(val));
     if (ret < 0) {
 	perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
@@ -3474,12 +4232,12 @@
         perror("bind");
         goto fail;
     }
-    
+
     /* Add host to multicast group */
     imr.imr_multiaddr = mcastaddr->sin_addr;
     imr.imr_interface.s_addr = htonl(INADDR_ANY);
 
-    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
+    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                      (const char *)&imr, sizeof(struct ip_mreq));
     if (ret < 0) {
 	perror("setsockopt(IP_ADD_MEMBERSHIP)");
@@ -3488,7 +4246,7 @@
 
     /* Force mcast msgs to loopback (eg. several QEMUs in same host */
     val = 1;
-    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, 
+    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
                    (const char *)&val, sizeof(val));
     if (ret < 0) {
 	perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
@@ -3498,12 +4256,12 @@
     socket_set_nonblock(fd);
     return fd;
 fail:
-    if (fd >= 0) 
+    if (fd >= 0)
         closesocket(fd);
     return -1;
 }
 
-static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd, 
+static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
                                           int is_connected)
 {
     struct sockaddr_in saddr;
@@ -3512,7 +4270,7 @@
     NetSocketState *s;
 
     /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
-     * Because this may be "shared" socket from a "master" process, datagrams would be recv() 
+     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
      * by ONLY ONE process: we must "clone" this dgram socket --jjo
      */
 
@@ -3534,7 +4292,7 @@
 	    /* clone newfd to fd, close newfd */
 	    dup2(newfd, fd);
 	    close(newfd);
-	
+
 	} else {
 	    fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
 		    fd, strerror(errno));
@@ -3554,7 +4312,7 @@
     if (is_connected) s->dgram_dst=saddr;
 
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-	    "socket: fd=%d (%s mcast=%s:%d)", 
+	    "socket: fd=%d (%s mcast=%s:%d)",
 	    fd, is_connected? "cloned" : "",
 	    inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
     return s;
@@ -3566,7 +4324,7 @@
     qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
 }
 
-static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd, 
+static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
                                           int is_connected)
 {
     NetSocketState *s;
@@ -3574,7 +4332,7 @@
     if (!s)
         return NULL;
     s->fd = fd;
-    s->vc = qemu_new_vlan_client(vlan, 
+    s->vc = qemu_new_vlan_client(vlan,
                                  net_socket_receive, NULL, s);
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
              "socket: fd=%d", fd);
@@ -3586,13 +4344,13 @@
     return s;
 }
 
-static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, 
+static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
                                           int is_connected)
 {
     int so_type=-1, optlen=sizeof(so_type);
 
     if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, &optlen)< 0) {
-	fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd);
+	fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
 	return NULL;
     }
     switch(so_type) {
@@ -3610,7 +4368,7 @@
 
 static void net_socket_accept(void *opaque)
 {
-    NetSocketListenState *s = opaque;    
+    NetSocketListenState *s = opaque;
     NetSocketState *s1;
     struct sockaddr_in saddr;
     socklen_t len;
@@ -3625,12 +4383,12 @@
             break;
         }
     }
-    s1 = net_socket_fd_init(s->vlan, fd, 1); 
+    s1 = net_socket_fd_init(s->vlan, fd, 1);
     if (!s1) {
         closesocket(fd);
     } else {
         snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
-                 "socket: connection from %s:%d", 
+                 "socket: connection from %s:%d",
                  inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
     }
 }
@@ -3643,7 +4401,7 @@
 
     if (parse_host_port(&saddr, host_str) < 0)
         return -1;
-    
+
     s = qemu_mallocz(sizeof(NetSocketListenState));
     if (!s)
         return -1;
@@ -3658,7 +4416,7 @@
     /* allow fast reuse */
     val = 1;
     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
-    
+
     ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
     if (ret < 0) {
         perror("bind");
@@ -3699,6 +4457,10 @@
             if (err == EINTR || err == EWOULDBLOCK) {
             } else if (err == EINPROGRESS) {
                 break;
+#ifdef _WIN32
+            } else if (err == WSAEALREADY) {
+                break;
+#endif
             } else {
                 perror("connect");
                 closesocket(fd);
@@ -3713,7 +4475,7 @@
     if (!s)
         return -1;
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-             "socket: connect to %s:%d", 
+             "socket: connect to %s:%d",
              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
     return 0;
 }
@@ -3737,9 +4499,9 @@
         return -1;
 
     s->dgram_dst = saddr;
-    
+
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),
-             "socket: mcast=%s:%d", 
+             "socket: mcast=%s:%d",
              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
     return 0;
 
@@ -3841,6 +4603,7 @@
         }
         nd->vlan = vlan;
         nb_nics++;
+        vlan->nb_guest_devs++;
         ret = 0;
     } else
     if (!strcmp(device, "none")) {
@@ -3853,6 +4616,7 @@
         if (get_param_value(buf, sizeof(buf), "hostname", p)) {
             pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf);
         }
+        vlan->nb_host_devs++;
         ret = net_slirp_init(vlan);
     } else
 #endif
@@ -3863,6 +4627,7 @@
             fprintf(stderr, "tap: no interface name\n");
             return -1;
         }
+        vlan->nb_host_devs++;
         ret = tap_win32_init(vlan, ifname);
     } else
 #else
@@ -3870,6 +4635,7 @@
         char ifname[64];
         char setup_script[1024];
         int fd;
+        vlan->nb_host_devs++;
         if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
             fd = strtol(buf, NULL, 0);
             ret = -1;
@@ -3903,6 +4669,7 @@
             fprintf(stderr, "Unknown socket options: %s\n", p);
             return -1;
         }
+        vlan->nb_host_devs++;
     } else
     {
         fprintf(stderr, "Unknown network device: %s\n", device);
@@ -3911,7 +4678,7 @@
     if (ret < 0) {
         fprintf(stderr, "Could not initialize device '%s'\n", device);
     }
-    
+
     return ret;
 }
 
@@ -3958,9 +4725,13 @@
     } else if (!strcmp(devname, "mouse")) {
         dev = usb_mouse_init();
     } else if (!strcmp(devname, "tablet")) {
-	dev = usb_tablet_init();
+        dev = usb_tablet_init();
+    } else if (!strcmp(devname, "keyboard")) {
+        dev = usb_keyboard_init();
     } else if (strstart(devname, "disk:", &p)) {
         dev = usb_msd_init(p);
+    } else if (!strcmp(devname, "wacom-tablet")) {
+        dev = usb_wacom_init();
     } else {
         return -1;
     }
@@ -4001,7 +4772,7 @@
         return -1;
 
     p = strchr(devname, '.');
-    if (!p) 
+    if (!p)
         return -1;
     bus_num = strtoul(devname, NULL, 0);
     addr = strtoul(p + 1, NULL, 0);
@@ -4031,7 +4802,7 @@
 {
     int ret;
     ret = usb_device_add(devname);
-    if (ret < 0) 
+    if (ret < 0)
         term_printf("Could not add USB device '%s'\n", devname);
 }
 
@@ -4039,7 +4810,7 @@
 {
     int ret;
     ret = usb_device_del(devname);
-    if (ret < 0) 
+    if (ret < 0)
         term_printf("Could not remove USB device '%s'\n", devname);
 }
 
@@ -4059,62 +4830,64 @@
         if (!dev)
             continue;
         switch(dev->speed) {
-        case USB_SPEED_LOW: 
-            speed_str = "1.5"; 
+        case USB_SPEED_LOW:
+            speed_str = "1.5";
             break;
-        case USB_SPEED_FULL: 
-            speed_str = "12"; 
+        case USB_SPEED_FULL:
+            speed_str = "12";
             break;
-        case USB_SPEED_HIGH: 
-            speed_str = "480"; 
+        case USB_SPEED_HIGH:
+            speed_str = "480";
             break;
         default:
-            speed_str = "?"; 
+            speed_str = "?";
             break;
         }
-        term_printf("  Device %d.%d, Speed %s Mb/s, Product %s\n", 
+        term_printf("  Device %d.%d, Speed %s Mb/s, Product %s\n",
                     0, dev->addr, speed_str, dev->devname);
     }
 }
 
 /***********************************************************/
-/* pid file */
+/* PCMCIA/Cardbus */
 
-static char *pid_filename;
+static struct pcmcia_socket_entry_s {
+    struct pcmcia_socket_s *socket;
+    struct pcmcia_socket_entry_s *next;
+} *pcmcia_sockets = 0;
 
-/* Remove PID file. Called on normal exit */
-
-static void remove_pidfile(void) 
+void pcmcia_socket_register(struct pcmcia_socket_s *socket)
 {
-    unlink (pid_filename);
+    struct pcmcia_socket_entry_s *entry;
+
+    entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s));
+    entry->socket = socket;
+    entry->next = pcmcia_sockets;
+    pcmcia_sockets = entry;
 }
 
-static void create_pidfile(const char *filename)
+void pcmcia_socket_unregister(struct pcmcia_socket_s *socket)
 {
-    struct stat pidstat;
-    FILE *f;
+    struct pcmcia_socket_entry_s *entry, **ptr;
 
-    /* Try to write our PID to the named file */
-    if (stat(filename, &pidstat) < 0) {
-        if (errno == ENOENT) {
-            if ((f = fopen (filename, "w")) == NULL) {
-                perror("Opening pidfile");
-                exit(1);
-            }
-            fprintf(f, "%d\n", getpid());
-            fclose(f);
-            pid_filename = qemu_strdup(filename);
-            if (!pid_filename) {
-                fprintf(stderr, "Could not save PID filename");
-                exit(1);
-            }
-            atexit(remove_pidfile);
+    ptr = &pcmcia_sockets;
+    for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr)
+        if (entry->socket == socket) {
+            *ptr = entry->next;
+            qemu_free(entry);
         }
-    } else {
-        fprintf(stderr, "%s already exists. Remove it and try again.\n", 
-                filename);
-        exit(1);
-    }
+}
+
+void pcmcia_info(void)
+{
+    struct pcmcia_socket_entry_s *iter;
+    if (!pcmcia_sockets)
+        term_printf("No PCMCIA sockets\n");
+
+    for (iter = pcmcia_sockets; iter; iter = iter->next)
+        term_printf("%s: %s\n", iter->socket->slot_string,
+                    iter->socket->attached ? iter->socket->card_string :
+                    "Empty");
 }
 
 /***********************************************************/
@@ -4130,10 +4903,12 @@
 
 static void dumb_refresh(DisplayState *ds)
 {
+#if defined(CONFIG_SDL)
     vga_hw_update();
+#endif
 }
 
-void dumb_display_init(DisplayState *ds)
+static void dumb_display_init(DisplayState *ds)
 {
     ds->data = NULL;
     ds->linesize = 0;
@@ -4164,10 +4939,10 @@
 
 /* XXX: fd_read_poll should be suppressed, but an API change is
    necessary in the character devices to suppress fd_can_read(). */
-int qemu_set_fd_handler2(int fd, 
-                         IOCanRWHandler *fd_read_poll, 
-                         IOHandler *fd_read, 
-                         IOHandler *fd_write, 
+int qemu_set_fd_handler2(int fd,
+                         IOCanRWHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
                          void *opaque)
 {
     IOHandlerRecord **pioh, *ioh;
@@ -4205,9 +4980,9 @@
     return 0;
 }
 
-int qemu_set_fd_handler(int fd, 
-                        IOHandler *fd_read, 
-                        IOHandler *fd_write, 
+int qemu_set_fd_handler(int fd,
+                        IOHandler *fd_read,
+                        IOHandler *fd_write,
                         void *opaque)
 {
     return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
@@ -4261,7 +5036,7 @@
 } WaitObjects;
 
 static WaitObjects wait_objects = {0};
-    
+
 int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
 {
     WaitObjects *w = &wait_objects;
@@ -4288,7 +5063,7 @@
             w->events[i] = w->events[i + 1];
             w->func[i] = w->func[i + 1];
             w->opaque[i] = w->opaque[i + 1];
-        }            
+        }
     }
     if (found)
         w->num--;
@@ -4658,8 +5433,8 @@
 
 static SaveStateEntry *first_se;
 
-int register_savevm(const char *idstr, 
-                    int instance_id, 
+int register_savevm(const char *idstr,
+                    int instance_id,
                     int version_id,
                     SaveStateHandler *save_state,
                     LoadStateHandler *load_state,
@@ -4712,7 +5487,7 @@
         /* record size: filled later */
         len_pos = qemu_ftell(f);
         qemu_put_be32(f, 0);
-        
+
         se->save_state(f, se->opaque);
 
         /* fill record size */
@@ -4736,7 +5511,7 @@
     SaveStateEntry *se;
 
     for(se = first_se; se != NULL; se = se->next) {
-        if (!strcmp(se->idstr, idstr) && 
+        if (!strcmp(se->idstr, idstr) &&
             instance_id == se->instance_id)
             return se;
     }
@@ -4750,7 +5525,7 @@
     int64_t total_len, end_pos, cur_pos;
     unsigned int v;
     char idstr[256];
-    
+
     v = qemu_get_be32(f);
     if (v != QEMU_VM_FILE_MAGIC)
         goto fail;
@@ -4772,18 +5547,18 @@
         version_id = qemu_get_be32(f);
         record_len = qemu_get_be32(f);
 #if 0
-        printf("idstr=%s instance=0x%x version=%d len=%d\n", 
+        printf("idstr=%s instance=0x%x version=%d len=%d\n",
                idstr, instance_id, version_id, record_len);
 #endif
         cur_pos = qemu_ftell(f);
         se = find_se(idstr, instance_id);
         if (!se) {
-            fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n", 
+            fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
                     instance_id, idstr);
         } else {
             ret = se->load_state(f, se->opaque, version_id);
             if (ret < 0) {
-                fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n", 
+                fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
                         instance_id, idstr);
                 goto the_end;
             }
@@ -4912,7 +5687,7 @@
 {
     QEMUSnapshotInfo *sn_tab, *sn;
     int nb_sns, i, ret;
-    
+
     ret = -ENOENT;
     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
     if (nb_sns < 0)
@@ -4954,7 +5729,7 @@
 
     saved_vm_running = vm_running;
     vm_stop(0);
-    
+
     must_delete = 0;
     if (name) {
         ret = bdrv_snapshot_find(bs, old_sn, name);
@@ -4982,13 +5757,13 @@
     sn->date_nsec = tv.tv_usec * 1000;
 #endif
     sn->vm_clock_nsec = qemu_get_clock(vm_clock);
-    
+
     if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
         term_printf("Device %s does not support VM state snapshots\n",
                     bdrv_get_device_name(bs));
         goto the_end;
     }
-    
+
     /* save the VM state */
     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1);
     if (!f) {
@@ -5002,7 +5777,7 @@
         term_printf("Error %d while writing VM\n", ret);
         goto the_end;
     }
-    
+
     /* create the snapshots */
 
     for(i = 0; i < MAX_DISKS; i++) {
@@ -5041,7 +5816,7 @@
         term_printf("No block device supports snapshots\n");
         return;
     }
-    
+
     /* Flush all IO requests so they don't interfere with the new state.  */
     qemu_aio_flush();
 
@@ -5081,7 +5856,7 @@
                     bdrv_get_device_name(bs));
         return;
     }
-    
+
     /* restore the VM state */
     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);
     if (!f) {
@@ -5108,7 +5883,7 @@
         term_printf("No block device supports snapshots\n");
         return;
     }
-    
+
     for(i = 0; i <= MAX_DISKS; i++) {
         bs1 = bs_table[i];
         if (bdrv_has_snapshot(bs1)) {
@@ -5192,7 +5967,7 @@
 #ifdef USE_KVM
     if (kvm_allowed)
         kvm_save_registers(env);
-#endif    
+#endif
 
     for(i = 0; i < CPU_NB_REGS; i++)
         qemu_put_betls(f, &env->regs[i]);
@@ -5200,7 +5975,7 @@
     qemu_put_betls(f, &env->eflags);
     hflags = env->hflags; /* XXX: suppress most of the redundant hflags */
     qemu_put_be32s(f, &hflags);
-    
+
     /* FPU */
     fpuc = env->fpuc;
     fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
@@ -5208,7 +5983,7 @@
     for(i = 0; i < 8; i++) {
         fptag |= ((!env->fptags[i]) << i);
     }
-    
+
     qemu_put_be16s(f, &fpuc);
     qemu_put_be16s(f, &fpus);
     qemu_put_be16s(f, &fptag);
@@ -5219,7 +5994,7 @@
     fpregs_format = 1;
 #endif
     qemu_put_be16s(f, &fpregs_format);
-    
+
     for(i = 0; i < 8; i++) {
 #ifdef USE_X86LDOUBLE
         {
@@ -5246,16 +6021,16 @@
     cpu_put_seg(f, &env->tr);
     cpu_put_seg(f, &env->gdt);
     cpu_put_seg(f, &env->idt);
-    
+
     qemu_put_be32s(f, &env->sysenter_cs);
     qemu_put_be32s(f, &env->sysenter_esp);
     qemu_put_be32s(f, &env->sysenter_eip);
-    
+
     qemu_put_betls(f, &env->cr[0]);
     qemu_put_betls(f, &env->cr[2]);
     qemu_put_betls(f, &env->cr[3]);
     qemu_put_betls(f, &env->cr[4]);
-    
+
     for(i = 0; i < 8; i++)
         qemu_put_betls(f, &env->dr[i]);
 
@@ -5333,7 +6108,7 @@
     qemu_get_be16s(f, &fpus);
     qemu_get_be16s(f, &fptag);
     qemu_get_be16s(f, &fpregs_format);
-    
+
     /* NOTE: we cannot always restore the FPU state if the image come
        from a host with a different 'USE_X86LDOUBLE' define. We guess
        if we are in an MMX state to restore correctly in that case. */
@@ -5341,7 +6116,7 @@
     for(i = 0; i < 8; i++) {
         uint64_t mant;
         uint16_t exp;
-        
+
         switch(fpregs_format) {
         case 0:
             mant = qemu_get_be64(f);
@@ -5372,7 +6147,7 @@
             }
 #else
             env->fpregs[i].mmx.MMX_Q(0) = mant;
-#endif            
+#endif
             break;
         default:
             return -EINVAL;
@@ -5387,23 +6162,23 @@
     for(i = 0; i < 8; i++) {
         env->fptags[i] = (fptag >> i) & 1;
     }
-    
+
     for(i = 0; i < 6; i++)
         cpu_get_seg(f, &env->segs[i]);
     cpu_get_seg(f, &env->ldt);
     cpu_get_seg(f, &env->tr);
     cpu_get_seg(f, &env->gdt);
     cpu_get_seg(f, &env->idt);
-    
+
     qemu_get_be32s(f, &env->sysenter_cs);
     qemu_get_be32s(f, &env->sysenter_esp);
     qemu_get_be32s(f, &env->sysenter_eip);
-    
+
     qemu_get_betls(f, &env->cr[0]);
     qemu_get_betls(f, &env->cr[2]);
     qemu_get_betls(f, &env->cr[3]);
     qemu_get_betls(f, &env->cr[4]);
-    
+
     for(i = 0; i < 8; i++)
         qemu_get_betls(f, &env->dr[i]);
 
@@ -5424,7 +6199,7 @@
     qemu_get_be64s(f, &env->fmask);
     qemu_get_be64s(f, &env->kernelgsbase);
 #endif
-    if (version_id >= 4) 
+    if (version_id >= 4)
         qemu_get_be32s(f, &env->smbase);
 
     /* XXX: compute hflags from scratch, except for CPL and IIF */
@@ -5544,13 +6319,146 @@
 
 #elif defined(TARGET_ARM)
 
-/* ??? Need to implement these.  */
 void cpu_save(QEMUFile *f, void *opaque)
 {
+    int i;
+    CPUARMState *env = (CPUARMState *)opaque;
+
+    for (i = 0; i < 16; i++) {
+        qemu_put_be32(f, env->regs[i]);
+    }
+    qemu_put_be32(f, cpsr_read(env));
+    qemu_put_be32(f, env->spsr);
+    for (i = 0; i < 6; i++) {
+        qemu_put_be32(f, env->banked_spsr[i]);
+        qemu_put_be32(f, env->banked_r13[i]);
+        qemu_put_be32(f, env->banked_r14[i]);
+    }
+    for (i = 0; i < 5; i++) {
+        qemu_put_be32(f, env->usr_regs[i]);
+        qemu_put_be32(f, env->fiq_regs[i]);
+    }
+    qemu_put_be32(f, env->cp15.c0_cpuid);
+    qemu_put_be32(f, env->cp15.c0_cachetype);
+    qemu_put_be32(f, env->cp15.c1_sys);
+    qemu_put_be32(f, env->cp15.c1_coproc);
+    qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
+    qemu_put_be32(f, env->cp15.c2_base);
+    qemu_put_be32(f, env->cp15.c2_data);
+    qemu_put_be32(f, env->cp15.c2_insn);
+    qemu_put_be32(f, env->cp15.c3);
+    qemu_put_be32(f, env->cp15.c5_insn);
+    qemu_put_be32(f, env->cp15.c5_data);
+    for (i = 0; i < 8; i++) {
+        qemu_put_be32(f, env->cp15.c6_region[i]);
+    }
+    qemu_put_be32(f, env->cp15.c6_insn);
+    qemu_put_be32(f, env->cp15.c6_data);
+    qemu_put_be32(f, env->cp15.c9_insn);
+    qemu_put_be32(f, env->cp15.c9_data);
+    qemu_put_be32(f, env->cp15.c13_fcse);
+    qemu_put_be32(f, env->cp15.c13_context);
+    qemu_put_be32(f, env->cp15.c15_cpar);
+
+    qemu_put_be32(f, env->features);
+
+    if (arm_feature(env, ARM_FEATURE_VFP)) {
+        for (i = 0;  i < 16; i++) {
+            CPU_DoubleU u;
+            u.d = env->vfp.regs[i];
+            qemu_put_be32(f, u.l.upper);
+            qemu_put_be32(f, u.l.lower);
+        }
+        for (i = 0; i < 16; i++) {
+            qemu_put_be32(f, env->vfp.xregs[i]);
+        }
+
+        /* TODO: Should use proper FPSCR access functions.  */
+        qemu_put_be32(f, env->vfp.vec_len);
+        qemu_put_be32(f, env->vfp.vec_stride);
+    }
+
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        for (i = 0; i < 16; i++) {
+            qemu_put_be64(f, env->iwmmxt.regs[i]);
+        }
+        for (i = 0; i < 16; i++) {
+            qemu_put_be32(f, env->iwmmxt.cregs[i]);
+        }
+    }
 }
 
 int cpu_load(QEMUFile *f, void *opaque, int version_id)
 {
+    CPUARMState *env = (CPUARMState *)opaque;
+    int i;
+
+    if (version_id != 0)
+        return -EINVAL;
+
+    for (i = 0; i < 16; i++) {
+        env->regs[i] = qemu_get_be32(f);
+    }
+    cpsr_write(env, qemu_get_be32(f), 0xffffffff);
+    env->spsr = qemu_get_be32(f);
+    for (i = 0; i < 6; i++) {
+        env->banked_spsr[i] = qemu_get_be32(f);
+        env->banked_r13[i] = qemu_get_be32(f);
+        env->banked_r14[i] = qemu_get_be32(f);
+    }
+    for (i = 0; i < 5; i++) {
+        env->usr_regs[i] = qemu_get_be32(f);
+        env->fiq_regs[i] = qemu_get_be32(f);
+    }
+    env->cp15.c0_cpuid = qemu_get_be32(f);
+    env->cp15.c0_cachetype = qemu_get_be32(f);
+    env->cp15.c1_sys = qemu_get_be32(f);
+    env->cp15.c1_coproc = qemu_get_be32(f);
+    env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
+    env->cp15.c2_base = qemu_get_be32(f);
+    env->cp15.c2_data = qemu_get_be32(f);
+    env->cp15.c2_insn = qemu_get_be32(f);
+    env->cp15.c3 = qemu_get_be32(f);
+    env->cp15.c5_insn = qemu_get_be32(f);
+    env->cp15.c5_data = qemu_get_be32(f);
+    for (i = 0; i < 8; i++) {
+        env->cp15.c6_region[i] = qemu_get_be32(f);
+    }
+    env->cp15.c6_insn = qemu_get_be32(f);
+    env->cp15.c6_data = qemu_get_be32(f);
+    env->cp15.c9_insn = qemu_get_be32(f);
+    env->cp15.c9_data = qemu_get_be32(f);
+    env->cp15.c13_fcse = qemu_get_be32(f);
+    env->cp15.c13_context = qemu_get_be32(f);
+    env->cp15.c15_cpar = qemu_get_be32(f);
+
+    env->features = qemu_get_be32(f);
+
+    if (arm_feature(env, ARM_FEATURE_VFP)) {
+        for (i = 0;  i < 16; i++) {
+            CPU_DoubleU u;
+            u.l.upper = qemu_get_be32(f);
+            u.l.lower = qemu_get_be32(f);
+            env->vfp.regs[i] = u.d;
+        }
+        for (i = 0; i < 16; i++) {
+            env->vfp.xregs[i] = qemu_get_be32(f);
+        }
+
+        /* TODO: Should use proper FPSCR access functions.  */
+        env->vfp.vec_len = qemu_get_be32(f);
+        env->vfp.vec_stride = qemu_get_be32(f);
+    }
+
+    if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+        for (i = 0; i < 16; i++) {
+            env->iwmmxt.regs[i] = qemu_get_be64(f);
+        }
+        for (i = 0; i < 16; i++) {
+            env->iwmmxt.cregs[i] = qemu_get_be32(f);
+        }
+    }
+
     return 0;
 }
 
@@ -5617,7 +6525,7 @@
     memset(s, 0, sizeof(*s));
     s->f = f;
     ret = deflateInit2(&s->zstream, 1,
-                       Z_DEFLATED, 15, 
+                       Z_DEFLATED, 15,
                        9, Z_DEFAULT_STRATEGY);
     if (ret != Z_OK)
         return -1;
@@ -5745,7 +6653,7 @@
     int i;
     RamCompressState s1, *s = &s1;
     uint8_t buf[10];
-    
+
     qemu_put_be32(f, phys_ram_size);
     if (ram_compress_open(s, f) < 0)
         return;
@@ -5764,7 +6672,7 @@
             sector_num = -1;
             for(j = 0; j < MAX_DISKS; j++) {
                 if (bs_table[j]) {
-                    sector_num = bdrv_hash_find(bs_table[j], 
+                    sector_num = bdrv_hash_find(bs_table[j],
                                                 phys_ram_base + i, BDRV_HASH_BLOCK_SIZE);
                     if (sector_num >= 0)
                         break;
@@ -5776,7 +6684,7 @@
             buf[1] = j;
             cpu_to_be64wu((uint64_t *)(buf + 2), sector_num);
             ram_compress_buf(s, buf, 10);
-        } else 
+        } else
 #endif
         {
             //        normal_compress:
@@ -5839,7 +6747,7 @@
                 fprintf(stderr, "Error while reading ram block address=0x%08x", i);
                 goto error;
             }
-        } else 
+        } else
 #if 0
         if (buf[0] == 1) {
             int bs_index;
@@ -5852,13 +6760,13 @@
                 fprintf(stderr, "Invalid block device index %d\n", bs_index);
                 goto error;
             }
-            if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i, 
+            if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i,
                           BDRV_HASH_BLOCK_SIZE / 512) < 0) {
-                fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n", 
+                fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n",
                         bs_index, sector_num);
                 goto error;
             }
-        } else 
+        } else
 #endif
         {
         error:
@@ -6001,8 +6909,9 @@
 
 void gui_update(void *opaque)
 {
-    display_state.dpy_refresh(&display_state);
-    qemu_mod_timer(gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock));
+    DisplayState *ds = opaque;
+    ds->dpy_refresh(ds);
+    qemu_mod_timer(ds->gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock));
 }
 
 struct vm_change_state_entry {
@@ -6065,10 +6974,11 @@
         cpu_enable_ticks();
         vm_running = 1;
         vm_state_notify(1);
+        qemu_rearm_alarm_timer(alarm_timer);
     }
 }
 
-void vm_stop(int reason) 
+void vm_stop(int reason)
 {
     if (vm_running) {
         cpu_disable_ticks();
@@ -6170,6 +7080,9 @@
     IOHandlerRecord *ioh;
     fd_set rfds, wfds, xfds;
     int ret, nfds;
+#ifdef _WIN32
+    int ret2, i;
+#endif
     struct timeval tv;
     PollingEntry *pe;
 
@@ -6180,18 +7093,33 @@
         ret |= pe->func(pe->opaque);
     }
 #ifdef _WIN32
-    if (ret == 0 && timeout > 0) {
+    if (ret == 0) {
         int err;
         WaitObjects *w = &wait_objects;
-        
+
         ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
         if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
             if (w->func[ret - WAIT_OBJECT_0])
                 w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+
+            /* Check for additional signaled events */
+            for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+
+                /* Check if event is signaled */
+                ret2 = WaitForSingleObject(w->events[i], 0);
+                if(ret2 == WAIT_OBJECT_0) {
+                    if (w->func[i])
+                        w->func[i](w->opaque[i]);
+                } else if (ret2 == WAIT_TIMEOUT) {
+                } else {
+                    err = GetLastError();
+                    fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+                }
+            }
         } else if (ret == WAIT_TIMEOUT) {
         } else {
             err = GetLastError();
-            fprintf(stderr, "Wait error %d %d\n", ret, err);
+            fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
         }
     }
 #endif
@@ -6217,7 +7145,7 @@
                 nfds = ioh->fd;
         }
     }
-    
+
     tv.tv_sec = 0;
 #ifdef _WIN32
     tv.tv_usec = 0;
@@ -6234,12 +7162,10 @@
         IOHandlerRecord **pioh;
 
         for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
-            if (ioh->deleted)
-                continue;
-            if (FD_ISSET(ioh->fd, &rfds)) {
+            if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
                 ioh->fd_read(ioh->opaque);
             }
-            if (FD_ISSET(ioh->fd, &wfds)) {
+            if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
                 ioh->fd_write(ioh->opaque);
             }
         }
@@ -6251,7 +7177,7 @@
             if (ioh->deleted) {
                 *pioh = ioh->next;
                 qemu_free(ioh);
-            } else 
+            } else
                 pioh = &ioh->next;
         }
     }
@@ -6266,18 +7192,22 @@
     }
 #endif
     qemu_aio_poll();
-    qemu_bh_poll();
 
     if (vm_running) {
-        qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], 
+        qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
                         qemu_get_clock(vm_clock));
         /* run dma transfers, if any */
         DMA_run();
     }
-    
+
     /* real time timers */
-    qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], 
+    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;
@@ -6315,13 +7245,16 @@
 #ifdef CONFIG_PROFILER
                 qemu_time += profile_getclock() - ti;
 #endif
+                if (ret == EXCP_HLT) {
+                    /* Give the next CPU a chance to run.  */
+                    cur_cpu = env;
+                    continue;
+                }
                 if (ret != EXCP_HALTED)
                     break;
                 /* all CPUs are halted ? */
-                if (env == cur_cpu) {
-                    ret = EXCP_HLT;
+                if (env == cur_cpu)
                     break;
-                }
             }
             cur_cpu = env;
 
@@ -6346,9 +7279,9 @@
             if (ret == EXCP_DEBUG) {
                 vm_stop(EXCP_DEBUG);
             }
-            /* if hlt instruction, we wait until the next IRQ */
+            /* If all cpus are halted then wait until the next IRQ */
             /* XXX: use timeout computed from timers */
-            if (ret == EXCP_HLT)
+            if (ret == EXCP_HALTED)
                 timeout = 10;
             else
                 timeout = 0;
@@ -6367,7 +7300,7 @@
     return ret;
 }
 
-void help(void)
+static void help(int exitcode)
 {
     printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
            "usage: %s [options] [disk_image]\n"
@@ -6376,13 +7309,19 @@
            "\n"
            "Standard options:\n"
            "-M machine      select emulated machine (-M ? for list)\n"
+           "-cpu cpu        select CPU (-cpu ? for list)\n"
            "-fda/-fdb file  use 'file' as floppy disk 0/1 image\n"
            "-hda/-hdb file  use 'file' as IDE hard disk 0/1 image\n"
            "-hdc/-hdd file  use 'file' as IDE hard disk 2/3 image\n"
            "-cdrom file     use 'file' as IDE cdrom image (cdrom is ide1 master)\n"
+           "-mtdblock file  use 'file' as on-board Flash memory image\n"
+           "-sd file        use 'file' as SecureDigital card image\n"
+           "-pflash file    use 'file' as a parallel flash image\n"
            "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n"
            "-snapshot       write to temporary files instead of disk image files\n"
 #ifdef CONFIG_SDL
+           "-no-frame       open SDL window without a frame and window decorations\n"
+           "-alt-grab       use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n"
            "-no-quit        disable SDL window close capability\n"
 #endif
 #ifdef TARGET_I386
@@ -6391,6 +7330,7 @@
            "-m megs         set virtual RAM size to megs MB [default=%d]\n"
            "-smp n          set the number of CPUs to 'n' [default=1]\n"
            "-nographic      disable graphical output and redirect serial I/Os to console\n"
+           "-portrait       rotate graphical output 90 deg left (only PXA LCD)\n"
 #ifndef _WIN32
            "-k language     use keyboard layout (for example \"fr\" for French)\n"
 #endif
@@ -6411,6 +7351,7 @@
 #if defined(TARGET_PPC) || defined(TARGET_SPARC)
            "-g WxH[xDEPTH]  Set the initial graphical resolution and depth\n"
 #endif
+           "-name string    set the name of the guest\n"
            "\n"
            "Network options:\n"
            "-net nic[,vlan=n][,macaddr=addr][,model=type]\n"
@@ -6438,7 +7379,8 @@
            "                is provided, the default is '-net nic -net user'\n"
            "\n"
 #ifdef CONFIG_SLIRP
-           "-tftp prefix    allow tftp access to files starting with prefix [-net user]\n"
+           "-tftp dir       allow tftp access to files in dir [-net user]\n"
+           "-bootp file     advertise file in BOOTP replies\n"
 #ifndef _WIN32
            "-smb dir        allow SMB access to files in 'dir' [-net user]\n"
 #endif
@@ -6459,8 +7401,8 @@
            "-parallel dev   redirect the parallel port to char device 'dev'\n"
            "-pidfile file   Write PID to 'file'\n"
            "-S              freeze CPU at startup (use 'c' to start execution)\n"
-           "-s              wait gdb connection to port %d\n"
-           "-p port         change gdb connection port\n"
+           "-s              wait gdb connection to port\n"
+           "-p port         set gdb connection port [default=%s]\n"
            "-d item1,...    output log to %s (use -d ? for a list of log items)\n"
            "-hdachs c,h,s[,t]  force hard disk 0 physical geometry and the optional BIOS\n"
            "                translation (t=none or lba) (usually qemu can guess them)\n"
@@ -6488,10 +7430,12 @@
 	   "-daemonize      daemonize QEMU after initializing\n"
 #endif
            "-tdf            inject timer interrupts that got lost\n"
-#if defined(__linux__)
-           "-no-rtc         don't use /dev/rtc for timer alarm (do use gettimeofday)\n"
-#endif
 	   "-option-rom rom load a file, rom, into the option ROM space\n"
+#ifdef TARGET_SPARC
+           "-prom-env variable=value  set OpenBIOS nvram variables\n"
+#endif
+           "-clock          force the use of the given methods for timer alarm.\n"
+           "                To see what timers are available use -clock help\n"
            "\n"
            "During emulation, the following keys are useful:\n"
            "ctrl-alt-f      toggle full screen\n"
@@ -6507,7 +7451,7 @@
 #endif
            DEFAULT_GDBSTUB_PORT,
            "/tmp/qemu.log");
-    exit(1);
+    exit(exitcode);
 }
 
 #define HAS_ARG 0x0001
@@ -6516,6 +7460,7 @@
     QEMU_OPTION_h,
 
     QEMU_OPTION_M,
+    QEMU_OPTION_cpu,
     QEMU_OPTION_fda,
     QEMU_OPTION_fdb,
     QEMU_OPTION_hda,
@@ -6523,6 +7468,9 @@
     QEMU_OPTION_hdc,
     QEMU_OPTION_hdd,
     QEMU_OPTION_cdrom,
+    QEMU_OPTION_mtdblock,
+    QEMU_OPTION_sd,
+    QEMU_OPTION_pflash,
     QEMU_OPTION_boot,
     QEMU_OPTION_snapshot,
 #ifdef TARGET_I386
@@ -6530,6 +7478,7 @@
 #endif
     QEMU_OPTION_m,
     QEMU_OPTION_nographic,
+    QEMU_OPTION_portrait,
 #ifdef HAS_AUDIO
     QEMU_OPTION_audio_help,
     QEMU_OPTION_soundhw,
@@ -6537,6 +7486,7 @@
 
     QEMU_OPTION_net,
     QEMU_OPTION_tftp,
+    QEMU_OPTION_bootp,
     QEMU_OPTION_smb,
     QEMU_OPTION_redir,
 
@@ -6554,8 +7504,10 @@
     QEMU_OPTION_k,
     QEMU_OPTION_localtime,
     QEMU_OPTION_cirrusvga,
+    QEMU_OPTION_vmsvga,
     QEMU_OPTION_g,
     QEMU_OPTION_std_vga,
+    QEMU_OPTION_echr,
     QEMU_OPTION_monitor,
     QEMU_OPTION_balloon,
     QEMU_OPTION_vmchannel,
@@ -6563,6 +7515,8 @@
     QEMU_OPTION_parallel,
     QEMU_OPTION_loadvm,
     QEMU_OPTION_full_screen,
+    QEMU_OPTION_no_frame,
+    QEMU_OPTION_alt_grab,
     QEMU_OPTION_no_quit,
     QEMU_OPTION_pidfile,
     QEMU_OPTION_no_kqemu,
@@ -6576,15 +7530,17 @@
     QEMU_OPTION_no_kvm,
     QEMU_OPTION_no_kvm_irqchip,
     QEMU_OPTION_no_reboot,
+    QEMU_OPTION_show_cursor,
     QEMU_OPTION_daemonize,
     QEMU_OPTION_option_rom,
     QEMU_OPTION_semihosting,
+    QEMU_OPTION_cpu_vendor,
+    QEMU_OPTION_name,
+    QEMU_OPTION_prom_env,
+    QEMU_OPTION_old_param,
+    QEMU_OPTION_clock,
     QEMU_OPTION_incoming,
     QEMU_OPTION_tdf,
-#if defined(__linux__)
-    QEMU_OPTION_no_rtc,
-#endif
-    QEMU_OPTION_cpu_vendor,
 };
 
 typedef struct QEMUOption {
@@ -6598,6 +7554,7 @@
     { "help", 0, QEMU_OPTION_h },
 
     { "M", HAS_ARG, QEMU_OPTION_M },
+    { "cpu", HAS_ARG, QEMU_OPTION_cpu },
     { "fda", HAS_ARG, QEMU_OPTION_fda },
     { "fdb", HAS_ARG, QEMU_OPTION_fdb },
     { "hda", HAS_ARG, QEMU_OPTION_hda },
@@ -6605,6 +7562,9 @@
     { "hdc", HAS_ARG, QEMU_OPTION_hdc },
     { "hdd", HAS_ARG, QEMU_OPTION_hdd },
     { "cdrom", HAS_ARG, QEMU_OPTION_cdrom },
+    { "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock },
+    { "sd", HAS_ARG, QEMU_OPTION_sd },
+    { "pflash", HAS_ARG, QEMU_OPTION_pflash },
     { "boot", HAS_ARG, QEMU_OPTION_boot },
     { "snapshot", 0, QEMU_OPTION_snapshot },
 #ifdef TARGET_I386
@@ -6612,6 +7572,7 @@
 #endif
     { "m", HAS_ARG, QEMU_OPTION_m },
     { "nographic", 0, QEMU_OPTION_nographic },
+    { "portrait", 0, QEMU_OPTION_portrait },
     { "k", HAS_ARG, QEMU_OPTION_k },
 #ifdef HAS_AUDIO
     { "audio-help", 0, QEMU_OPTION_audio_help },
@@ -6621,6 +7582,7 @@
     { "net", HAS_ARG, QEMU_OPTION_net},
 #ifdef CONFIG_SLIRP
     { "tftp", HAS_ARG, QEMU_OPTION_tftp },
+    { "bootp", HAS_ARG, QEMU_OPTION_bootp },
 #ifndef _WIN32
     { "smb", HAS_ARG, QEMU_OPTION_smb },
 #endif
@@ -6654,12 +7616,16 @@
     { "monitor", 1, QEMU_OPTION_monitor },
     { "balloon", 1, QEMU_OPTION_balloon },
     { "vmchannel", 1, QEMU_OPTION_vmchannel },
-    { "serial", 1, QEMU_OPTION_serial },
-    { "parallel", 1, QEMU_OPTION_parallel },
+    { "echr", HAS_ARG, QEMU_OPTION_echr },
+    { "monitor", HAS_ARG, QEMU_OPTION_monitor },
+    { "serial", HAS_ARG, QEMU_OPTION_serial },
+    { "parallel", HAS_ARG, QEMU_OPTION_parallel },
     { "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
     { "incoming", 1, QEMU_OPTION_incoming },
     { "full-screen", 0, QEMU_OPTION_full_screen },
 #ifdef CONFIG_SDL
+    { "no-frame", 0, QEMU_OPTION_no_frame },
+    { "alt-grab", 0, QEMU_OPTION_alt_grab },
     { "no-quit", 0, QEMU_OPTION_no_quit },
 #endif
     { "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
@@ -6671,18 +7637,25 @@
     /* temporary options */
     { "usb", 0, QEMU_OPTION_usb },
     { "cirrusvga", 0, QEMU_OPTION_cirrusvga },
+    { "vmwarevga", 0, QEMU_OPTION_vmsvga },
     { "no-acpi", 0, QEMU_OPTION_no_acpi },
     { "no-reboot", 0, QEMU_OPTION_no_reboot },
+    { "show-cursor", 0, QEMU_OPTION_show_cursor },
     { "daemonize", 0, QEMU_OPTION_daemonize },
     { "option-rom", HAS_ARG, QEMU_OPTION_option_rom },
-#if defined(TARGET_ARM)
+#if defined(TARGET_ARM) || defined(TARGET_M68K)
     { "semihosting", 0, QEMU_OPTION_semihosting },
 #endif
     { "tdf", 0, QEMU_OPTION_tdf }, /* enable time drift fix */
-#if defined(__linux__)
-    { "no-rtc", 0, QEMU_OPTION_no_rtc },
+    { "name", HAS_ARG, QEMU_OPTION_name },
+#if defined(TARGET_SPARC)
+    { "prom-env", HAS_ARG, QEMU_OPTION_prom_env },
 #endif
     { "cpu-vendor", HAS_ARG, QEMU_OPTION_cpu_vendor },
+#if defined(TARGET_ARM)
+    { "old-param", 0, QEMU_OPTION_old_param },
+#endif
+    { "clock", HAS_ARG, QEMU_OPTION_clock },
     { NULL },
 };
 
@@ -6697,6 +7670,24 @@
 
 /* password input */
 
+int qemu_key_check(BlockDriverState *bs, const char *name)
+{
+    char password[256];
+    int i;
+
+    if (!bdrv_is_encrypted(bs))
+        return 0;
+
+    term_printf("%s is encrypted.\n", name);
+    for(i = 0; i < 3; i++) {
+        monitor_readline("Password: ", 1, password, sizeof(password));
+        if (bdrv_set_key(bs, password) == 0)
+            return 0;
+        term_printf("invalid password\n");
+    }
+    return -EPERM;
+}
+
 static BlockDriverState *get_bdrv(int index)
 {
     BlockDriverState *bs;
@@ -6714,21 +7705,12 @@
 static void read_passwords(void)
 {
     BlockDriverState *bs;
-    int i, j;
-    char password[256];
+    int i;
 
     for(i = 0; i < 6; i++) {
         bs = get_bdrv(i);
-        if (bs && bdrv_is_encrypted(bs)) {
-            term_printf("%s is encrypted.\n", bdrv_get_device_name(bs));
-            for(j = 0; j < 3; j++) {
-                monitor_readline("Password: ", 
-                                 1, password, sizeof(password));
-                if (bdrv_set_key(bs, password) == 0)
-                    break;
-                term_printf("invalid password\n");
-            }
-        }
+        if (bs)
+            qemu_key_check(bs, bdrv_get_device_name(bs));
     }
 }
 
@@ -6742,23 +7724,37 @@
     qemu_register_machine(&heathrow_machine);
     qemu_register_machine(&core99_machine);
     qemu_register_machine(&prep_machine);
+    qemu_register_machine(&ref405ep_machine);
+    qemu_register_machine(&taihu_machine);
 #elif defined(TARGET_MIPS)
     qemu_register_machine(&mips_machine);
     qemu_register_machine(&mips_malta_machine);
+    qemu_register_machine(&mips_pica61_machine);
 #elif defined(TARGET_SPARC)
 #ifdef TARGET_SPARC64
     qemu_register_machine(&sun4u_machine);
 #else
-    qemu_register_machine(&sun4m_machine);
+    qemu_register_machine(&ss5_machine);
+    qemu_register_machine(&ss10_machine);
 #endif
 #elif defined(TARGET_ARM)
-    qemu_register_machine(&integratorcp926_machine);
-    qemu_register_machine(&integratorcp1026_machine);
+    qemu_register_machine(&integratorcp_machine);
     qemu_register_machine(&versatilepb_machine);
     qemu_register_machine(&versatileab_machine);
     qemu_register_machine(&realview_machine);
+    qemu_register_machine(&akitapda_machine);
+    qemu_register_machine(&spitzpda_machine);
+    qemu_register_machine(&borzoipda_machine);
+    qemu_register_machine(&terrierpda_machine);
+    qemu_register_machine(&palmte_machine);
 #elif defined(TARGET_SH4)
     qemu_register_machine(&shix_machine);
+    qemu_register_machine(&r2d_machine);
+#elif defined(TARGET_ALPHA)
+    /* XXX: TODO */
+#elif defined(TARGET_M68K)
+    qemu_register_machine(&mcf5208evb_machine);
+    qemu_register_machine(&an5206_machine);
 #else
 #error unsupported CPU
 #endif
@@ -6766,6 +7762,7 @@
 
 #ifdef HAS_AUDIO
 struct soundhw soundhw[] = {
+#ifdef HAS_AUDIO_CHOICE
 #ifdef TARGET_I386
     {
         "pcspk",
@@ -6814,6 +7811,7 @@
         0,
         { .init_pci = es1370_init }
     },
+#endif
 
     { NULL, NULL, 0, 0, { NULL } }
 };
@@ -6901,12 +7899,16 @@
 int main(int argc, char **argv)
 {
 #ifdef CONFIG_GDBSTUB
-    int use_gdbstub, gdbstub_port;
+    int use_gdbstub;
+    const char *gdbstub_port;
 #endif
-    int i, cdrom_index;
+    int i, cdrom_index, pflash_index;
     int snapshot, linux_boot;
     const char *initrd_filename;
     const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
+    const char *pflash_filename[MAX_PFLASH];
+    const char *sd_filename;
+    const char *mtd_filename;
     const char *kernel_filename, *kernel_cmdline;
     DisplayState *ds = &display_state;
     int cyls, heads, secs, translation;
@@ -6924,9 +7926,12 @@
     int parallel_device_index;
     const char *loadvm = NULL;
     QEMUMachine *machine;
+    const char *cpu_model;
     char usb_devices[MAX_USB_CMDLINE][128];
     int usb_devices_index;
     int fds[2];
+    const char *pid_file = NULL;
+    VLANState *vlan;
 
     saved_argc = argc;
     saved_argv = argv;
@@ -6964,14 +7969,19 @@
 
     register_machines();
     machine = first_machine;
+    cpu_model = NULL;
     initrd_filename = NULL;
     for(i = 0; i < MAX_FD; i++)
         fd_filename[i] = NULL;
     for(i = 0; i < MAX_DISKS; i++)
         hd_filename[i] = NULL;
+    for(i = 0; i < MAX_PFLASH; i++)
+        pflash_filename[i] = NULL;
+    pflash_index = 0;
+    sd_filename = NULL;
+    mtd_filename = NULL;
     ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
     vga_ram_size = VGA_RAM_SIZE;
-    bios_size = BIOS_SIZE;
 #ifdef CONFIG_GDBSTUB
     use_gdbstub = 0;
     gdbstub_port = DEFAULT_GDBSTUB_PORT;
@@ -6997,19 +8007,19 @@
     for(i = 1; i < MAX_SERIAL_PORTS; i++)
         serial_devices[i][0] = '\0';
     serial_device_index = 0;
-    
+
     pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc");
     for(i = 1; i < MAX_PARALLEL_PORTS; i++)
         parallel_devices[i][0] = '\0';
     parallel_device_index = 0;
-    
+
     usb_devices_index = 0;
-    
+
     nb_net_clients = 0;
 
     nb_nics = 0;
     /* default mac address of the first network interface */
-    
+
     optind = 1;
     for(;;) {
         if (optind >= argc)
@@ -7027,7 +8037,7 @@
             popt = qemu_options;
             for(;;) {
                 if (!popt->name) {
-                    fprintf(stderr, "%s: invalid option -- '%s'\n", 
+                    fprintf(stderr, "%s: invalid option -- '%s'\n",
                             argv[0], r);
                     exit(1);
                 }
@@ -7054,10 +8064,27 @@
                     printf("Supported machines are:\n");
                     for(m = first_machine; m != NULL; m = m->next) {
                         printf("%-10s %s%s\n",
-                               m->name, m->desc, 
+                               m->name, m->desc,
                                m == first_machine ? " (default)" : "");
                     }
-                    exit(1);
+                    exit(*optarg != '?');
+                }
+                break;
+            case QEMU_OPTION_cpu:
+                /* hw initialization will check this */
+                if (*optarg == '?') {
+#if defined(TARGET_PPC)
+                    ppc_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_ARM)
+                    arm_cpu_list();
+#elif defined(TARGET_MIPS)
+                    mips_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_SPARC)
+                    sparc_cpu_list(stdout, &fprintf);
+#endif
+                    exit(0);
+                } else {
+                    cpu_model = optarg;
                 }
                 break;
             case QEMU_OPTION_initrd:
@@ -7075,6 +8102,19 @@
                         cdrom_index = -1;
                 }
                 break;
+            case QEMU_OPTION_mtdblock:
+                mtd_filename = optarg;
+                break;
+            case QEMU_OPTION_sd:
+                sd_filename = optarg;
+                break;
+            case QEMU_OPTION_pflash:
+                if (pflash_index >= MAX_PFLASH) {
+                    fprintf(stderr, "qemu: too many parallel flash images\n");
+                    exit(1);
+                }
+                pflash_filename[pflash_index++] = optarg;
+                break;
             case QEMU_OPTION_snapshot:
                 snapshot = 1;
                 break;
@@ -7115,10 +8155,14 @@
                 }
                 break;
             case QEMU_OPTION_nographic:
-                pstrcpy(monitor_device, sizeof(monitor_device), "stdio");
                 pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio");
+                pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "null");
+                pstrcpy(monitor_device, sizeof(monitor_device), "stdio");
                 nographic = 1;
                 break;
+            case QEMU_OPTION_portrait:
+                graphic_rotate = 1;
+                break;
             case QEMU_OPTION_kernel:
                 kernel_filename = optarg;
                 break;
@@ -7132,7 +8176,7 @@
                 break;
             case QEMU_OPTION_boot:
                 boot_device = optarg[0];
-                if (boot_device != 'a' && 
+                if (boot_device != 'a' &&
 #if defined(TARGET_SPARC) || defined(TARGET_I386)
 		    // Network boot
 		    boot_device != 'n' &&
@@ -7170,13 +8214,16 @@
             case QEMU_OPTION_tftp:
 		tftp_prefix = optarg;
                 break;
+            case QEMU_OPTION_bootp:
+                bootp_filename = optarg;
+                break;
 #ifndef _WIN32
             case QEMU_OPTION_smb:
 		net_slirp_smb(optarg);
                 break;
 #endif
             case QEMU_OPTION_redir:
-                net_slirp_redir(optarg);                
+                net_slirp_redir(optarg);
                 break;
 #endif
 #ifdef HAS_AUDIO
@@ -7189,12 +8236,12 @@
                 break;
 #endif
             case QEMU_OPTION_h:
-                help();
+                help(0);
                 break;
             case QEMU_OPTION_m:
                 ram_size = (int64_t)atoi(optarg) * 1024 * 1024;
                 if (ram_size <= 0)
-                    help();
+                    help(1);
                 if (ram_size > PHYS_RAM_MAX_SIZE) {
                     fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n",
                             PHYS_RAM_MAX_SIZE / (1024 * 1024));
@@ -7205,7 +8252,7 @@
                 {
                     int mask;
                     CPULogItem *item;
-                    
+
                     mask = cpu_str_to_log_mask(optarg);
                     if (!mask) {
                         printf("Log items (comma separated):\n");
@@ -7222,7 +8269,7 @@
                 use_gdbstub = 1;
                 break;
             case QEMU_OPTION_p:
-                gdbstub_port = atoi(optarg);
+                gdbstub_port = optarg;
                 break;
 #endif
             case QEMU_OPTION_L:
@@ -7239,9 +8286,15 @@
                 break;
             case QEMU_OPTION_cirrusvga:
                 cirrus_vga_enabled = 1;
+                vmsvga_enabled = 0;
+                break;
+            case QEMU_OPTION_vmsvga:
+                cirrus_vga_enabled = 0;
+                vmsvga_enabled = 1;
                 break;
             case QEMU_OPTION_std_vga:
                 cirrus_vga_enabled = 0;
+                vmsvga_enabled = 0;
                 break;
             case QEMU_OPTION_g:
                 {
@@ -7263,7 +8316,7 @@
                     if (*p == 'x') {
                         p++;
                         depth = strtol(p, (char **)&p, 10);
-                        if (depth != 8 && depth != 15 && depth != 16 && 
+                        if (depth != 8 && depth != 15 && depth != 16 &&
                             depth != 24 && depth != 32)
                             goto graphic_error;
                     } else if (*p == '\0') {
@@ -7271,12 +8324,20 @@
                     } else {
                         goto graphic_error;
                     }
-                    
+
                     graphic_width = w;
                     graphic_height = h;
                     graphic_depth = depth;
                 }
                 break;
+            case QEMU_OPTION_echr:
+                {
+                    char *r;
+                    term_escape_char = strtol(optarg, &r, 0);
+                    if (r == optarg)
+                        printf("Bad argument to echr\n");
+                    break;
+                }
             case QEMU_OPTION_monitor:
                 pstrcpy(monitor_device, sizeof(monitor_device), optarg);
                 break;
@@ -7307,7 +8368,7 @@
                     fprintf(stderr, "qemu: too many serial ports\n");
                     exit(1);
                 }
-                pstrcpy(serial_devices[serial_device_index], 
+                pstrcpy(serial_devices[serial_device_index],
                         sizeof(serial_devices[0]), optarg);
                 serial_device_index++;
                 break;
@@ -7316,7 +8377,7 @@
                     fprintf(stderr, "qemu: too many parallel ports\n");
                     exit(1);
                 }
-                pstrcpy(parallel_devices[parallel_device_index], 
+                pstrcpy(parallel_devices[parallel_device_index],
                         sizeof(parallel_devices[0]), optarg);
                 parallel_device_index++;
                 break;
@@ -7330,12 +8391,18 @@
                 full_screen = 1;
                 break;
 #ifdef CONFIG_SDL
+            case QEMU_OPTION_no_frame:
+                no_frame = 1;
+                break;
+            case QEMU_OPTION_alt_grab:
+                alt_grab = 1;
+                break;
             case QEMU_OPTION_no_quit:
                 no_quit = 1;
                 break;
 #endif
             case QEMU_OPTION_pidfile:
-                create_pidfile(optarg);
+                pid_file = optarg;
                 break;
 #ifdef TARGET_I386
             case QEMU_OPTION_win2k_hack:
@@ -7388,6 +8455,9 @@
             case QEMU_OPTION_no_reboot:
                 no_reboot = 1;
                 break;
+            case QEMU_OPTION_show_cursor:
+                cursor_hide = 0;
+                break;
 	    case QEMU_OPTION_daemonize:
 		daemonize = 1;
 		break;
@@ -7405,14 +8475,29 @@
             case QEMU_OPTION_tdf:
                 time_drift_fix = 1;
 		break;
-#if defined(__linux__)
-	    case QEMU_OPTION_no_rtc:
-		use_rtc = 0;
-		break;
+            case QEMU_OPTION_name:
+                qemu_name = optarg;
+                break;
+#ifdef TARGET_SPARC
+            case QEMU_OPTION_prom_env:
+                if (nb_prom_envs >= MAX_PROM_ENVS) {
+                    fprintf(stderr, "Too many prom variables\n");
+                    exit(1);
+                }
+                prom_envs[nb_prom_envs] = optarg;
+                nb_prom_envs++;
+                break;
 #endif
 	    case QEMU_OPTION_cpu_vendor:
 		cpu_vendor_string = optarg;
 		break;
+#ifdef TARGET_ARM
+            case QEMU_OPTION_old_param:
+                old_param = 1;
+#endif
+            case QEMU_OPTION_clock:
+                configure_alarms(optarg);
+                break;
             }
         }
     }
@@ -7432,16 +8517,19 @@
 	    close(fds[1]);
 
 	again:
-	    len = read(fds[0], &status, 1);
-	    if (len == -1 && (errno == EINTR))
-		goto again;
-	    
-	    if (len != 1 || status != 0)
-		exit(1);
-	    else
-		exit(0);
+            len = read(fds[0], &status, 1);
+            if (len == -1 && (errno == EINTR))
+                goto again;
+
+            if (len != 1)
+                exit(1);
+            else if (status == 1) {
+                fprintf(stderr, "Could not acquire pidfile\n");
+                exit(1);
+            } else
+                exit(0);
 	} else if (pid < 0)
-	    exit(1);
+            exit(1);
 
 	setsid();
 
@@ -7468,6 +8556,15 @@
     }
 #endif
 
+    if (pid_file && qemu_create_pidfile(pid_file) != 0) {
+        if (daemonize) {
+            uint8_t status = 1;
+            write(fds[1], &status, 1);
+        } else
+            fprintf(stderr, "Could not acquire pid file\n");
+        exit(1);
+    }
+
 #ifdef USE_KQEMU
     if (smp_cpus > 1)
         kqemu_allowed = 0;
@@ -7475,10 +8572,11 @@
     linux_boot = (kernel_filename != NULL);
 
     if (!linux_boot &&
-        hd_filename[0] == '\0' && 
+        boot_device != 'n' &&
+        hd_filename[0] == '\0' &&
         (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') &&
         fd_filename[0] == '\0')
-        help();
+        help(1);
 
     /* boot to floppy or the default cd if no hard disk defined yet */
     if (hd_filename[0] == '\0' && boot_device == 'c') {
@@ -7489,7 +8587,7 @@
     }
 
     setvbuf(stdout, NULL, _IOLBF, 0);
-    
+
     init_timers();
     init_timer_alarm();
     qemu_aio_init();
@@ -7512,6 +8610,18 @@
         if (net_client_init(net_clients[i]) < 0)
             exit(1);
     }
+    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
+            continue;
+        if (vlan->nb_guest_devs == 0) {
+            fprintf(stderr, "Invalid vlan (%d) with no nics\n", vlan->id);
+            exit(1);
+        }
+        if (vlan->nb_host_devs == 0)
+            fprintf(stderr,
+                    "Warning: vlan %d is not connected to host network\n",
+                    vlan->id);
+    }
 
 #ifdef TARGET_I386
     if (boot_device == 'n') {
@@ -7535,17 +8645,7 @@
 #endif
 
     /* init the memory */
-    phys_ram_size = ram_size + vga_ram_size + bios_size;
-
-
-    for (i = 0; i < nb_option_roms; i++) {
-	int ret = get_image_size(option_rom[i]);
-	if (ret == -1) {
-	    fprintf(stderr, "Could not load option rom '%s'\n", option_rom[i]);
-	    exit(1);
-	}
-	phys_ram_size += ret;
-    }
+    phys_ram_size = ram_size + vga_ram_size + MAX_BIOS_SIZE;
 
 #if USE_KVM
     /* Initialize kvm */
@@ -7609,7 +8709,7 @@
                 fd_table[i] = bdrv_new(buf);
                 bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY);
             }
-            if (fd_filename[i] != '\0') {
+            if (fd_filename[i][0] != '\0') {
                 if (bdrv_open(fd_table[i], fd_filename[i],
                               snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
                     fprintf(stderr, "qemu: could not open floppy disk image '%s'\n",
@@ -7620,32 +8720,91 @@
         }
     }
 
+    /* Open the virtual parallel flash block devices */
+    for(i = 0; i < MAX_PFLASH; i++) {
+        if (pflash_filename[i]) {
+            if (!pflash_table[i]) {
+                char buf[64];
+                snprintf(buf, sizeof(buf), "fl%c", i + 'a');
+                pflash_table[i] = bdrv_new(buf);
+            }
+            if (bdrv_open(pflash_table[i], pflash_filename[i],
+                          snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
+                fprintf(stderr, "qemu: could not open flash image '%s'\n",
+                        pflash_filename[i]);
+                exit(1);
+            }
+        }
+    }
+
+    sd_bdrv = bdrv_new ("sd");
+    /* FIXME: This isn't really a floppy, but it's a reasonable
+       approximation.  */
+    bdrv_set_type_hint(sd_bdrv, BDRV_TYPE_FLOPPY);
+    if (sd_filename) {
+        if (bdrv_open(sd_bdrv, sd_filename,
+                      snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
+            fprintf(stderr, "qemu: could not open SD card image %s\n",
+                    sd_filename);
+        } else
+            qemu_key_check(sd_bdrv, sd_filename);
+    }
+
+    if (mtd_filename) {
+        mtd_bdrv = bdrv_new ("mtd");
+        if (bdrv_open(mtd_bdrv, mtd_filename,
+                      snapshot ? BDRV_O_SNAPSHOT : 0) < 0 ||
+            qemu_key_check(mtd_bdrv, mtd_filename)) {
+            fprintf(stderr, "qemu: could not open Flash image %s\n",
+                    mtd_filename);
+            bdrv_delete(mtd_bdrv);
+            mtd_bdrv = 0;
+        }
+    }
+
     register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
     register_savevm("ram", 0, 3, ram_save, ram_load, NULL);
 
     init_ioports();
 
     /* terminal init */
+    memset(&display_state, 0, sizeof(display_state));
     if (nographic) {
+        /* nearly nothing to do */
         dumb_display_init(ds);
     } else if (vnc_display != NULL) {
-	vnc_display_init(ds, vnc_display);
+        vnc_display_init(ds);
+        if (vnc_display_open(ds, vnc_display) < 0)
+            exit(1);
     } else {
 #if defined(CONFIG_SDL)
-        sdl_display_init(ds, full_screen);
+        sdl_display_init(ds, full_screen, no_frame);
 #elif defined(CONFIG_COCOA)
         cocoa_display_init(ds, full_screen);
-#else
-        dumb_display_init(ds);
 #endif
     }
 
-    monitor_hd = qemu_chr_open(monitor_device);
-    if (!monitor_hd) {
-        fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
-        exit(1);
+    /* Maintain compatibility with multiple stdio monitors */
+    if (!strcmp(monitor_device,"stdio")) {
+        for (i = 0; i < MAX_SERIAL_PORTS; i++) {
+            if (!strcmp(serial_devices[i],"mon:stdio")) {
+                monitor_device[0] = '\0';
+                break;
+            } else if (!strcmp(serial_devices[i],"stdio")) {
+                monitor_device[0] = '\0';
+                pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "mon:stdio");
+                break;
+            }
+        }
     }
-    monitor_init(monitor_hd, !nographic);
+    if (monitor_device[0] != '\0') {
+        monitor_hd = qemu_chr_open(monitor_device);
+        if (!monitor_hd) {
+            fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
+            exit(1);
+        }
+        monitor_init(monitor_hd, !nographic);
+    }
 
     for(i = 0; i < MAX_VMCHANNEL_DEVICES; i++) {
         const char *devname = vmchannel_devices[i];
@@ -7677,11 +8836,11 @@
         if (devname[0] != '\0' && strcmp(devname, "none")) {
             serial_hds[i] = qemu_chr_open(devname);
             if (!serial_hds[i]) {
-                fprintf(stderr, "qemu: could not open serial device '%s'\n", 
+                fprintf(stderr, "qemu: could not open serial device '%s'\n",
                         devname);
                 exit(1);
             }
-            if (!strcmp(devname, "vc"))
+            if (strstart(devname, "vc", 0))
                 qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i);
         }
     }
@@ -7691,18 +8850,18 @@
         if (devname[0] != '\0' && strcmp(devname, "none")) {
             parallel_hds[i] = qemu_chr_open(devname);
             if (!parallel_hds[i]) {
-                fprintf(stderr, "qemu: could not open parallel device '%s'\n", 
+                fprintf(stderr, "qemu: could not open parallel device '%s'\n",
                         devname);
                 exit(1);
             }
-            if (!strcmp(devname, "vc"))
+            if (strstart(devname, "vc", 0))
                 qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i);
         }
     }
 
     machine->init(ram_size, vga_ram_size, boot_device,
                   ds, fd_filename, snapshot,
-                  kernel_filename, kernel_cmdline, initrd_filename);
+                  kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
 
     /* init USB devices */
     if (usb_enabled) {
@@ -7714,8 +8873,10 @@
         }
     }
 
-    gui_timer = qemu_new_timer(rt_clock, gui_update, NULL);
-    qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock));
+    if (display_state.dpy_refresh) {
+        display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state);
+        qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock));
+    }
 
 #ifdef USE_KVM
     if (kvm_allowed)
@@ -7726,16 +8887,15 @@
     if (use_gdbstub) {
         /* XXX: use standard host:port notation and modify options
            accordingly. */
-        if (gdbserver_start_port(gdbstub_port) < 0) {
-            fprintf(stderr, "qemu: could not open gdbstub device on port '%d'\n",
+        if (gdbserver_start(gdbstub_port) < 0) {
+            fprintf(stderr, "qemu: could not open gdbstub device on port '%s'\n",
                     gdbstub_port);
             exit(1);
         }
-    } else 
-#endif
-    if (loadvm) {
-	do_loadvm(loadvm);
     }
+#endif
+    if (loadvm)
+        do_loadvm(loadvm);
 
     if (incoming) {
         int rc;
@@ -7769,7 +8929,7 @@
 	    exit(1);
 
 	chdir("/");
-	fd = open("/dev/null", O_RDWR);
+	TFR(fd = open("/dev/null", O_RDWR));
 	if (fd == -1)
 	    exit(1);
 
diff --git a/vl.h b/vl.h
index 5a693f5..01aeabc 100644
--- a/vl.h
+++ b/vl.h
@@ -1,8 +1,8 @@
 /*
  * QEMU System Emulator header
- * 
+ *
  * Copyright (c) 2003 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -93,6 +93,15 @@
 #define tostring(s)	#s
 #endif
 
+#ifndef likely
+#if __GNUC__ < 3
+#define __builtin_expect(x, n) (x)
+#endif
+
+#define likely(x)   __builtin_expect(!!(x), 1)
+#define unlikely(x)   __builtin_expect(!!(x), 0)
+#endif
+
 #ifndef MIN
 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
 #endif
@@ -100,6 +109,14 @@
 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
 #endif
 
+#ifndef always_inline
+#if (__GNUC__ < 3) || defined(__APPLE__)
+#define always_inline inline
+#else
+#define always_inline __attribute__ (( always_inline )) inline
+#endif
+#endif
+
 /* cutils.c */
 void pstrcpy(char *buf, int buf_size, const char *str);
 char *pstrcat(char *buf, int buf_size, const char *s);
@@ -118,6 +135,7 @@
 extern const char *bios_dir;
 
 extern int vm_running;
+extern const char *qemu_name;
 
 typedef struct vm_change_state_entry VMChangeStateEntry;
 typedef void VMChangeStateHandler(void *opaque, int running);
@@ -157,6 +175,7 @@
 extern int bios_size;
 extern int rtc_utc;
 extern int cirrus_vga_enabled;
+extern int vmsvga_enabled;
 extern int graphic_width;
 extern int graphic_height;
 extern int graphic_depth;
@@ -165,24 +184,34 @@
 extern int kvm_allowed;
 extern int kvm_irqchip;
 extern int win2k_install_hack;
+extern int alt_grab;
 extern int usb_enabled;
 extern int smp_cpus;
+extern int cursor_hide;
+extern int graphic_rotate;
 extern int no_quit;
 extern int semihosting_enabled;
 extern int autostart;
 extern int time_drift_fix;
+extern int old_param;
+extern const char *bootp_filename;
 
 #define MAX_OPTION_ROMS 16
 extern const char *option_rom[MAX_OPTION_ROMS];
 extern int nb_option_roms;
 
+#ifdef TARGET_SPARC
+#define MAX_PROM_ENVS 128
+extern const char *prom_envs[MAX_PROM_ENVS];
+extern unsigned int nb_prom_envs;
+#endif
+
 /* XXX: make it dynamic */
+#define MAX_BIOS_SIZE (4 * 1024 * 1024)
 #if defined (TARGET_PPC) || defined (TARGET_SPARC64)
 #define BIOS_SIZE ((512 + 32) * 1024)
 #elif defined(TARGET_MIPS)
 #define BIOS_SIZE (4 * 1024 * 1024)
-#else
-#define BIOS_SIZE ((256 + 64) * 1024)
 #endif
 
 #if USE_KVM
@@ -252,13 +281,13 @@
 typedef int IOCanRWHandler(void *opaque);
 typedef void IOHandler(void *opaque);
 
-int qemu_set_fd_handler2(int fd, 
-                         IOCanRWHandler *fd_read_poll, 
-                         IOHandler *fd_read, 
-                         IOHandler *fd_write, 
+int qemu_set_fd_handler2(int fd,
+                         IOCanRWHandler *fd_read_poll,
+                         IOHandler *fd_read,
+                         IOHandler *fd_write,
                          void *opaque);
 int qemu_set_fd_handler(int fd,
-                        IOHandler *fd_read, 
+                        IOHandler *fd_read,
                         IOHandler *fd_write,
                         void *opaque);
 
@@ -302,6 +331,10 @@
 #define CHR_IOCTL_PP_READ_CONTROL     5
 #define CHR_IOCTL_PP_WRITE_CONTROL    6
 #define CHR_IOCTL_PP_READ_STATUS      7
+#define CHR_IOCTL_PP_EPP_READ_ADDR    8
+#define CHR_IOCTL_PP_EPP_READ         9
+#define CHR_IOCTL_PP_EPP_WRITE_ADDR  10
+#define CHR_IOCTL_PP_EPP_WRITE       11
 
 typedef void IOEventHandler(void *opaque, int event);
 
@@ -316,6 +349,7 @@
     void (*chr_send_event)(struct CharDriverState *chr, int event);
     void (*chr_close)(struct CharDriverState *chr);
     void *opaque;
+    int focus;
     QEMUBH *bh;
 } CharDriverState;
 
@@ -323,8 +357,8 @@
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
 int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len);
 void qemu_chr_send_event(CharDriverState *s, int event);
-void qemu_chr_add_handlers(CharDriverState *s, 
-                           IOCanRWHandler *fd_can_read, 
+void qemu_chr_add_handlers(CharDriverState *s,
+                           IOCanRWHandler *fd_can_read,
                            IOReadHandler *fd_read,
                            IOEventHandler *fd_event,
                            void *opaque);
@@ -351,7 +385,7 @@
 void vga_hw_screen_dump(const char *filename);
 
 int is_graphic_console(void);
-CharDriverState *text_console_init(DisplayState *ds);
+CharDriverState *text_console_init(DisplayState *ds, const char *p);
 void console_select(unsigned int index);
 
 /* vmchannel devices */
@@ -370,6 +404,11 @@
 
 extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
 
+struct ParallelIOArg {
+    void *buffer;
+    int count;
+};
+
 /* VLANs support */
 
 typedef struct VLANClientState VLANClientState;
@@ -389,6 +428,7 @@
     int id;
     VLANClientState *first_client;
     struct VLANState *next;
+    unsigned int nb_guest_devs, nb_host_devs;
 } VLANState;
 
 VLANState *qemu_find_vlan(int id);
@@ -444,7 +484,6 @@
 int qemu_timer_pending(QEMUTimer *ts);
 
 extern int64_t ticks_per_sec;
-extern int pit_min_timer_count;
 
 int64_t cpu_get_ticks(void);
 void cpu_enable_ticks(void);
@@ -533,8 +572,8 @@
 typedef void SaveStateHandler(QEMUFile *f, void *opaque);
 typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
 
-int register_savevm(const char *idstr, 
-                    int instance_id, 
+int register_savevm(const char *idstr,
+                    int instance_id,
                     int version_id,
                     SaveStateHandler *save_state,
                     LoadStateHandler *load_state,
@@ -577,12 +616,13 @@
 extern BlockDriver bdrv_vpc;
 extern BlockDriver bdrv_vvfat;
 extern BlockDriver bdrv_qcow2;
+extern BlockDriver bdrv_parallels;
 
 typedef struct BlockDriverInfo {
     /* in bytes, 0 if irrelevant */
-    int cluster_size; 
+    int cluster_size;
     /* offset at which the VM state can be saved (0 if not possible) */
-    int64_t vm_state_offset; 
+    int64_t vm_state_offset;
 } BlockDriverInfo;
 
 typedef struct QEMUSnapshotInfo {
@@ -613,7 +653,7 @@
 
 void bdrv_init(void);
 BlockDriver *bdrv_find_format(const char *format_name);
-int bdrv_create(BlockDriver *drv, 
+int bdrv_create(BlockDriver *drv,
                 const char *filename, int64_t size_in_sectors,
                 const char *backing_file, int flags);
 BlockDriverState *bdrv_new(const char *device_name);
@@ -623,13 +663,13 @@
 int bdrv_open2(BlockDriverState *bs, const char *filename, int flags,
                BlockDriver *drv);
 void bdrv_close(BlockDriverState *bs);
-int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
+int bdrv_read(BlockDriverState *bs, int64_t sector_num,
               uint8_t *buf, int nb_sectors);
-int bdrv_write(BlockDriverState *bs, int64_t sector_num, 
+int bdrv_write(BlockDriverState *bs, int64_t sector_num,
                const uint8_t *buf, int nb_sectors);
-int bdrv_pread(BlockDriverState *bs, int64_t offset, 
+int bdrv_pread(BlockDriverState *bs, int64_t offset,
                void *buf, int count);
-int bdrv_pwrite(BlockDriverState *bs, int64_t offset, 
+int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
                 const void *buf, int count);
 int bdrv_truncate(BlockDriverState *bs, int64_t offset);
 int64_t bdrv_getlength(BlockDriverState *bs);
@@ -656,6 +696,8 @@
 void qemu_aio_wait(void);
 void qemu_aio_wait_end(void);
 
+int qemu_key_check(BlockDriverState *bs, const char *name);
+
 /* Ensure contents are flushed to disk.  */
 void bdrv_flush(BlockDriverState *bs);
 
@@ -668,11 +710,11 @@
 #define BIOS_ATA_TRANSLATION_LARGE  3
 #define BIOS_ATA_TRANSLATION_RECHS  4
 
-void bdrv_set_geometry_hint(BlockDriverState *bs, 
+void bdrv_set_geometry_hint(BlockDriverState *bs,
                             int cyls, int heads, int secs);
 void bdrv_set_type_hint(BlockDriverState *bs, int type);
 void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
-void bdrv_get_geometry_hint(BlockDriverState *bs, 
+void bdrv_get_geometry_hint(BlockDriverState *bs,
                             int *pcyls, int *pheads, int *psecs);
 int bdrv_get_type_hint(BlockDriverState *bs);
 int bdrv_get_translation_hint(BlockDriverState *bs);
@@ -683,7 +725,7 @@
 int bdrv_is_locked(BlockDriverState *bs);
 void bdrv_set_locked(BlockDriverState *bs, int locked);
 void bdrv_eject(BlockDriverState *bs, int eject_flag);
-void bdrv_set_change_cb(BlockDriverState *bs, 
+void bdrv_set_change_cb(BlockDriverState *bs,
                         void (*change_cb)(void *opaque), void *opaque);
 void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
 void bdrv_info(void);
@@ -691,21 +733,21 @@
 void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque);
 int bdrv_is_encrypted(BlockDriverState *bs);
 int bdrv_set_key(BlockDriverState *bs, const char *key);
-void bdrv_iterate_format(void (*it)(void *opaque, const char *name), 
+void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
                          void *opaque);
 const char *bdrv_get_device_name(BlockDriverState *bs);
-int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num, 
+int bdrv_write_compressed(BlockDriverState *bs, int64_t sector_num,
                           const uint8_t *buf, int nb_sectors);
 int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
 
-void bdrv_get_backing_filename(BlockDriverState *bs, 
+void bdrv_get_backing_filename(BlockDriverState *bs,
                                char *filename, int filename_size);
-int bdrv_snapshot_create(BlockDriverState *bs, 
+int bdrv_snapshot_create(BlockDriverState *bs,
                          QEMUSnapshotInfo *sn_info);
-int bdrv_snapshot_goto(BlockDriverState *bs, 
+int bdrv_snapshot_goto(BlockDriverState *bs,
                        const char *snapshot_id);
 int bdrv_snapshot_delete(BlockDriverState *bs, const char *snapshot_id);
-int bdrv_snapshot_list(BlockDriverState *bs, 
+int bdrv_snapshot_list(BlockDriverState *bs,
                        QEMUSnapshotInfo **psn_info);
 char *bdrv_snapshot_dump(char *buf, int buf_size, QEMUSnapshotInfo *sn);
 
@@ -721,7 +763,7 @@
                                  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 *initrd_filename, const char *cpu_model);
 
 typedef struct QEMUMachine {
     const char *name;
@@ -733,7 +775,16 @@
 int qemu_register_machine(QEMUMachine *m);
 
 typedef void SetIRQFunc(void *opaque, int irq_num, int level);
-typedef void IRQRequestFunc(void *opaque, int level);
+
+#if defined(TARGET_PPC)
+void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#endif
+
+#if defined(TARGET_MIPS)
+void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#endif
+
+#include "hw/irq.h"
 
 /* ISA bus */
 
@@ -742,9 +793,9 @@
 typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
 typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
 
-int register_ioport_read(int start, int length, int size, 
+int register_ioport_read(int start, int length, int size,
                          IOPortReadFunc *func, void *opaque);
-int register_ioport_write(int start, int length, int size, 
+int register_ioport_write(int start, int length, int size,
                           IOPortWriteFunc *func, void *opaque);
 void isa_unassign_ioport(int start, int length);
 
@@ -757,11 +808,11 @@
 typedef struct PCIBus PCIBus;
 typedef struct PCIDevice PCIDevice;
 
-typedef void PCIConfigWriteFunc(PCIDevice *pci_dev, 
+typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
                                 uint32_t address, uint32_t data, int len);
-typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev, 
+typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
                                    uint32_t address, int len);
-typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num, 
+typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
                                 uint32_t addr, uint32_t size, int type);
 
 #define PCI_ADDRESS_SPACE_MEM		0x00
@@ -800,39 +851,40 @@
     int devfn;
     char name[64];
     PCIIORegion io_regions[PCI_NUM_REGIONS];
-    
+
     /* do not access the following fields */
     PCIConfigReadFunc *config_read;
     PCIConfigWriteFunc *config_write;
     /* ??? This is a PC-specific hack, and should be removed.  */
     int irq_index;
 
+    /* IRQ objects for the INTA-INTD pins.  */
+    qemu_irq *irq;
+
     /* Current IRQ levels.  Used internally by the generic PCI code.  */
     int irq_state[4];
 };
 
 PCIDevice *pci_register_device(PCIBus *bus, const char *name,
                                int instance_size, int devfn,
-                               PCIConfigReadFunc *config_read, 
+                               PCIConfigReadFunc *config_read,
                                PCIConfigWriteFunc *config_write);
 
-void pci_register_io_region(PCIDevice *pci_dev, int region_num, 
-                            uint32_t size, int type, 
+void pci_register_io_region(PCIDevice *pci_dev, int region_num,
+                            uint32_t size, int type,
                             PCIMapIORegionFunc *map_func);
 
-void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level);
-
-uint32_t pci_default_read_config(PCIDevice *d, 
+uint32_t pci_default_read_config(PCIDevice *d,
                                  uint32_t address, int len);
-void pci_default_write_config(PCIDevice *d, 
+void pci_default_write_config(PCIDevice *d,
                               uint32_t address, uint32_t val, int len);
 void pci_device_save(PCIDevice *s, QEMUFile *f);
 int pci_device_load(PCIDevice *s, QEMUFile *f);
 
-typedef void (*pci_set_irq_fn)(void *pic, int irq_num, int level);
+typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level);
 typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
 PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
-                         void *pic, int devfn_min, int nirq);
+                         qemu_irq *pic, int devfn_min, int nirq);
 
 void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn);
 void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
@@ -845,22 +897,22 @@
                         pci_map_irq_fn map_irq, const char *name);
 
 /* prep_pci.c */
-PCIBus *pci_prep_init(void);
+PCIBus *pci_prep_init(qemu_irq *pic);
 
 /* grackle_pci.c */
-PCIBus *pci_grackle_init(uint32_t base, void *pic);
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic);
 
 /* unin_pci.c */
-PCIBus *pci_pmac_init(void *pic);
+PCIBus *pci_pmac_init(qemu_irq *pic);
 
 /* apb_pci.c */
-PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
-                     void *pic);
+PCIBus *pci_apb_init(target_phys_addr_t special_base, target_phys_addr_t mem_base,
+                     qemu_irq *pic);
 
-PCIBus *pci_vpb_init(void *pic, int irq, int realview);
+PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview);
 
 /* piix_pci.c */
-PCIBus *i440fx_init(PCIDevice **pi440fx_state);
+PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic);
 void i440fx_set_smm(PCIDevice *d, int val);
 int piix3_init(PCIBus *bus, int devfn);
 void i440fx_init_memory_mappings(PCIDevice *d);
@@ -868,18 +920,23 @@
 int piix4_init(PCIBus *bus, int devfn);
 
 /* openpic.c */
-typedef struct openpic_t openpic_t;
-void openpic_set_irq(void *opaque, int n_IRQ, int level);
-openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
-                         CPUState **envp);
+/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
+enum {
+    OPENPIC_OUTPUT_INT = 0, /* IRQ                       */
+    OPENPIC_OUTPUT_CINT,    /* critical IRQ              */
+    OPENPIC_OUTPUT_MCK,     /* Machine check event       */
+    OPENPIC_OUTPUT_DEBUG,   /* Inconditional debug event */
+    OPENPIC_OUTPUT_RESET,   /* Core reset event          */
+    OPENPIC_OUTPUT_NB,
+};
+qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+                        qemu_irq **irqs, qemu_irq irq_out);
 
 /* heathrow_pic.c */
-typedef struct HeathrowPICS HeathrowPICS;
-void heathrow_pic_set_irq(void *opaque, int num, int level);
-HeathrowPICS *heathrow_pic_init(int *pmem_index);
+qemu_irq *heathrow_pic_init(int *pmem_index);
 
 /* gt64xxx.c */
-PCIBus *pci_gt64120_init(void *pic);
+PCIBus *pci_gt64120_init(qemu_irq *pic);
 
 #ifdef HAS_AUDIO
 struct soundhw {
@@ -888,7 +945,7 @@
     int enabled;
     int isa;
     union {
-        int (*init_isa) (AudioState *s);
+        int (*init_isa) (AudioState *s, qemu_irq *pic);
         int (*init_pci) (PCIBus *bus, AudioState *s);
     } init;
 };
@@ -898,7 +955,11 @@
 
 /* vga.c */
 
+#ifndef TARGET_SPARC
 #define VGA_RAM_SIZE (8192 * 1024)
+#else
+#define VGA_RAM_SIZE (9 * 1024 * 1024)
+#endif
 
 struct DisplayState {
     uint8_t *data;
@@ -908,11 +969,18 @@
     int width;
     int height;
     void *opaque;
+    QEMUTimer *gui_timer;
 
     void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
     void (*dpy_resize)(struct DisplayState *s, int w, int h);
     void (*dpy_refresh)(struct DisplayState *s);
-    void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h);
+    void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y,
+                     int dst_x, int dst_y, int w, int h);
+    void (*dpy_fill)(struct DisplayState *s, int x, int y,
+                     int w, int h, uint32_t c);
+    void (*mouse_set)(int x, int y, int on);
+    void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
+                          uint8_t *image, uint8_t *mask);
 };
 
 static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
@@ -925,26 +993,37 @@
     s->dpy_resize(s, w, h);
 }
 
-int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base, 
+int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
                  unsigned long vga_ram_offset, int vga_ram_size);
-int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
+int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
                  unsigned long vga_ram_offset, int vga_ram_size,
                  unsigned long vga_bios_offset, int vga_bios_size);
+int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
+                    unsigned long vga_ram_offset, int vga_ram_size,
+                    target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
+                    int it_shift);
 
 /* cirrus_vga.c */
-void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base, 
+void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
                          unsigned long vga_ram_offset, int vga_ram_size);
-void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base, 
+void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
                          unsigned long vga_ram_offset, int vga_ram_size);
 
+/* vmware_vga.c */
+void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
+                     unsigned long vga_ram_offset, int vga_ram_size);
+
 /* sdl.c */
-void sdl_display_init(DisplayState *ds, int full_screen);
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
 
 /* cocoa.m */
 void cocoa_display_init(DisplayState *ds, int full_screen);
 
 /* vnc.c */
-void vnc_display_init(DisplayState *ds, const char *display);
+void vnc_display_init(DisplayState *ds);
+void vnc_display_close(DisplayState *ds);
+int vnc_display_open(DisplayState *ds, const char *display);
+int vnc_display_password(DisplayState *ds, const char *password);
 void do_info_vnc(void);
 
 /* x_keymap.c */
@@ -954,30 +1033,38 @@
 #define MAX_DISKS 4
 
 extern BlockDriverState *bs_table[MAX_DISKS + 1];
+extern BlockDriverState *sd_bdrv;
+extern BlockDriverState *mtd_bdrv;
 
-void isa_ide_init(int iobase, int iobase2, int irq,
+void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
                   BlockDriverState *hd0, BlockDriverState *hd1);
 void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
                          int secondary_ide_enabled);
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn);
-int pmac_ide_init (BlockDriverState **hd_table,
-                   SetIRQFunc *set_irq, void *irq_opaque, int irq);
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic);
+void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+                        qemu_irq *pic);
+int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq);
 
 /* cdrom.c */
 int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
 int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
 
+/* ds1225y.c */
+typedef struct ds1225y_t ds1225y_t;
+ds1225y_t *ds1225y_init(target_phys_addr_t mem_base, const char *filename);
+
 /* es1370.c */
 int es1370_init (PCIBus *bus, AudioState *s);
 
 /* sb16.c */
-int SB16_init (AudioState *s);
+int SB16_init (AudioState *s, qemu_irq *pic);
 
 /* adlib.c */
-int Adlib_init (AudioState *s);
+int Adlib_init (AudioState *s, qemu_irq *pic);
 
 /* gus.c */
-int GUS_init (AudioState *s);
+int GUS_init (AudioState *s, qemu_irq *pic);
 
 /* dma.c */
 typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size);
@@ -998,14 +1085,20 @@
 
 typedef struct fdctrl_t fdctrl_t;
 
-fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, 
-                       uint32_t io_base,
+fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
+                       target_phys_addr_t io_base,
                        BlockDriverState **fds);
 int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);
 
+/* eepro100.c */
+
+void pci_i82551_init(PCIBus *bus, NICInfo *nd, int devfn);
+void pci_i82557b_init(PCIBus *bus, NICInfo *nd, int devfn);
+void pci_i82559er_init(PCIBus *bus, NICInfo *nd, int devfn);
+
 /* ne2000.c */
 
-void isa_ne2000_init(int base, int irq, NICInfo *nd);
+void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd);
 void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn);
 
 /* rtl8139.c */
@@ -1015,35 +1108,52 @@
 /* pcnet.c */
 
 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);
+void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque,
+                qemu_irq irq, qemu_irq *reset);
 
+/* vmmouse.c */
+void *vmmouse_init(void *m);
+
+/* vmport.c */
+#ifdef TARGET_I386
+void vmport_init(CPUState *env);
+void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque);
+#endif
 
 /* pckbd.c */
 
-void kbd_init(void);
+void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base);
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
+                   target_phys_addr_t base, int it_shift);
 
 /* mc146818rtc.c */
 
 typedef struct RTCState RTCState;
 
-RTCState *rtc_init(int base, int irq);
+RTCState *rtc_init(int base, qemu_irq irq);
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq);
 void rtc_set_memory(RTCState *s, int addr, int val);
 void rtc_set_date(RTCState *s, const struct tm *tm);
 
 /* serial.c */
 
 typedef struct SerialState SerialState;
-SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
-                         int base, int irq, CharDriverState *chr);
-SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
-                             target_ulong base, int it_shift,
-                             int irq, CharDriverState *chr);
+SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr);
+SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
+                             qemu_irq irq, CharDriverState *chr,
+                             int ioregister);
+uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr);
+void serial_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value);
+uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr);
+void serial_mm_writew (void *opaque, target_phys_addr_t addr, uint32_t value);
+uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr);
+void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value);
 
 /* parallel.c */
 
 typedef struct ParallelState ParallelState;
-ParallelState *parallel_init(int base, int irq, CharDriverState *chr);
+ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr);
+ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr);
 
 /* i8259.c */
 
@@ -1051,7 +1161,7 @@
 extern PicState2 *isa_pic;
 void pic_set_irq(int irq, int level);
 void pic_set_irq_new(void *opaque, int irq, int level);
-PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque);
+qemu_irq *i8259_init(qemu_irq parent_irq);
 void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
                           void *alt_irq_opaque);
 int pic_read_irq(PicState2 *s);
@@ -1075,28 +1185,30 @@
 
 typedef struct PITState PITState;
 
-PITState *pit_init(int base, int irq);
+PITState *pit_init(int base, qemu_irq irq);
 void pit_set_gate(PITState *pit, int channel, int val);
 int pit_get_gate(PITState *pit, int channel);
 int pit_get_initial_count(PITState *pit, int channel);
 int pit_get_mode(PITState *pit, int channel);
 int pit_get_out(PITState *pit, int channel, int64_t current_time);
 
+/* jazz_led.c */
+extern void jazz_led_init(DisplayState *ds, target_phys_addr_t base);
+
 /* pcspk.c */
 void pcspk_init(PITState *);
-int pcspk_audio_init(AudioState *);
+int pcspk_audio_init(AudioState *, qemu_irq *pic);
+
+#include "hw/i2c.h"
 
 #include "hw/smbus.h"
 
 /* acpi.c */
 extern int acpi_enabled;
-void piix4_pm_init(PCIBus *bus, int devfn);
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
 void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
 void acpi_bios_init(void);
 
-/* smbus_eeprom.c */
-SMBusDevice *smbus_eeprom_device_init(uint8_t addr, uint8_t *buf);
-
 /* pc.c */
 extern QEMUMachine pc_machine;
 extern QEMUMachine isapc_machine;
@@ -1109,6 +1221,8 @@
 extern QEMUMachine prep_machine;
 extern QEMUMachine core99_machine;
 extern QEMUMachine heathrow_machine;
+extern QEMUMachine ref405ep_machine;
+extern QEMUMachine taihu_machine;
 
 /* mips_r4k.c */
 extern QEMUMachine mips_machine;
@@ -1116,8 +1230,11 @@
 /* mips_malta.c */
 extern QEMUMachine mips_malta_machine;
 
-/* mips_int */
-extern void cpu_mips_irq_request(void *opaque, int irq, int level);
+/* mips_int.c */
+extern void cpu_mips_irq_init_cpu(CPUState *env);
+
+/* mips_pica61.c */
+extern QEMUMachine mips_pica61_machine;
 
 /* mips_timer.c */
 extern void cpu_mips_clock_init(CPUState *);
@@ -1126,8 +1243,36 @@
 /* shix.c */
 extern QEMUMachine shix_machine;
 
+/* r2d.c */
+extern QEMUMachine r2d_machine;
+
 #ifdef TARGET_PPC
-ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq);
+/* PowerPC hardware exceptions management helpers */
+typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
+typedef struct clk_setup_t clk_setup_t;
+struct clk_setup_t {
+    clk_setup_cb cb;
+    void *opaque;
+};
+static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
+{
+    if (clk->cb != NULL)
+        (*clk->cb)(clk->opaque, freq);
+}
+
+clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq);
+/* Embedded PowerPC DCR management */
+typedef target_ulong (*dcr_read_cb)(void *opaque, int dcrn);
+typedef void (*dcr_write_cb)(void *opaque, int dcrn, target_ulong val);
+int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
+                  int (*dcr_write_error)(int dcrn));
+int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
+                      dcr_read_cb drc_read, dcr_write_cb dcr_write);
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq);
+/* Embedded PowerPC reset */
+void ppc40x_core_reset (CPUState *env);
+void ppc40x_chip_reset (CPUState *env);
+void ppc40x_system_reset (CPUState *env);
 #endif
 void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);
 
@@ -1136,11 +1281,10 @@
 void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val);
 
 /* sun4m.c */
-extern QEMUMachine sun4m_machine;
-void pic_set_irq_cpu(int irq, int level, unsigned int cpu);
+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,
@@ -1158,53 +1302,53 @@
 }
 
 /* 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 *slavio_intctl_init();
-void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env);
+void *slavio_intctl_init(target_phys_addr_t addr, target_phys_addr_t addrg,
+                         const uint32_t *intbit_to_level,
+                         qemu_irq **irq, qemu_irq **cpu_irq,
+                         qemu_irq **parent_irq, unsigned int cputimer);
 void slavio_pic_info(void *opaque);
 void slavio_irq_info(void *opaque);
-void slavio_pic_set_irq(void *opaque, int irq, int level);
-void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu);
 
 /* loader.c */
 int get_image_size(const char *filename);
 int load_image(const char *filename, uint8_t *addr);
-int load_elf(const char *filename, int64_t virt_to_phys_addend, uint64_t *pentry);
+int load_elf(const char *filename, int64_t virt_to_phys_addend,
+             uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr);
 int load_aout(const char *filename, uint8_t *addr);
+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 slavio_timer_init(target_phys_addr_t addr, qemu_irq irq, int mode);
 
 /* slavio_serial.c */
-SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2);
-void slavio_serial_ms_kbd_init(int base, int 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, int 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_reset(void *opaque);
+void *esp_init(BlockDriverState **bd, target_phys_addr_t espaddr,
+               void *dma_opaque, qemu_irq irq, qemu_irq *reset);
 
 /* sparc32_dma.c */
-void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu,
-                       void *intctl);
-void ledma_set_irq(void *opaque, int isr);
-void ledma_memory_read(void *opaque, target_phys_addr_t addr, 
+void *sparc32_dma_init(target_phys_addr_t daddr, qemu_irq parent_irq,
+                       void *iommu, qemu_irq **dev_irq, qemu_irq **reset);
+void ledma_memory_read(void *opaque, target_phys_addr_t addr,
                        uint8_t *buf, int len, int do_bswap);
-void ledma_memory_write(void *opaque, target_phys_addr_t addr, 
+void ledma_memory_write(void *opaque, target_phys_addr_t addr,
                         uint8_t *buf, int len, int do_bswap);
-void espdma_raise_irq(void *opaque);
-void espdma_clear_irq(void *opaque);
 void espdma_memory_read(void *opaque, uint8_t *buf, int len);
 void espdma_memory_write(void *opaque, uint8_t *buf, int len);
-void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque,
-                                void *lance_opaque);
 
 /* cs4231.c */
 void cs_init(target_phys_addr_t base, int irq, void *intctl);
@@ -1272,9 +1416,9 @@
                 const uint8_t *buf, int len);
 int adb_poll(ADBBusState *s, uint8_t *buf_out);
 
-ADBDevice *adb_register_device(ADBBusState *s, int devaddr, 
-                               ADBDeviceRequest *devreq, 
-                               ADBDeviceReset *devreset, 
+ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
+                               ADBDeviceRequest *devreq,
+                               ADBDeviceReset *devreset,
                                void *opaque);
 void adb_kbd_init(ADBBusState *bus);
 void adb_mouse_init(ADBBusState *bus);
@@ -1282,7 +1426,7 @@
 /* cuda.c */
 
 extern ADBBusState adb_bus;
-int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq);
+int cuda_init(qemu_irq irq);
 
 #include "hw/usb.h"
 
@@ -1327,8 +1471,7 @@
 void *lsi_scsi_init(PCIBus *bus, int devfn);
 
 /* integratorcp.c */
-extern QEMUMachine integratorcp926_machine;
-extern QEMUMachine integratorcp1026_machine;
+extern QEMUMachine integratorcp_machine;
 
 /* versatilepb.c */
 extern QEMUMachine versatilepb_machine;
@@ -1337,6 +1480,15 @@
 /* realview.c */
 extern QEMUMachine realview_machine;
 
+/* spitz.c */
+extern QEMUMachine akitapda_machine;
+extern QEMUMachine spitzpda_machine;
+extern QEMUMachine borzoipda_machine;
+extern QEMUMachine terrierpda_machine;
+
+/* palm.c */
+extern QEMUMachine palmte_machine;
+
 /* ps2.c */
 void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
 void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
@@ -1345,40 +1497,48 @@
 uint32_t ps2_read_data(void *);
 void ps2_queue(void *, int b);
 void ps2_keyboard_set_translation(void *opaque, int mode);
+void ps2_mouse_fake_event(void *opaque);
 
 /* smc91c111.c */
-void smc91c111_init(NICInfo *, uint32_t, void *, int);
+void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
+
+/* pl031.c */
+void pl031_init(uint32_t base, qemu_irq irq);
 
 /* pl110.c */
-void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int);
+void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int);
 
 /* pl011.c */
-void pl011_init(uint32_t base, void *pic, int irq, CharDriverState *chr);
+void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr);
 
 /* pl050.c */
-void pl050_init(uint32_t base, void *pic, int irq, int is_mouse);
+void pl050_init(uint32_t base, qemu_irq irq, int is_mouse);
 
 /* pl080.c */
-void *pl080_init(uint32_t base, void *pic, int irq, int nchannels);
+void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
+
+/* pl181.c */
+void pl181_init(uint32_t base, BlockDriverState *bd,
+                qemu_irq irq0, qemu_irq irq1);
 
 /* pl190.c */
-void *pl190_init(uint32_t base, void *parent, int irq, int fiq);
+qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq);
 
 /* arm-timer.c */
-void sp804_init(uint32_t base, void *pic, int irq);
-void icp_pit_init(uint32_t base, void *pic, int irq);
+void sp804_init(uint32_t base, qemu_irq irq);
+void icp_pit_init(uint32_t base, qemu_irq *pic, int irq);
 
 /* arm_sysctl.c */
 void arm_sysctl_init(uint32_t base, uint32_t sys_id);
 
 /* arm_gic.c */
-void *arm_gic_init(uint32_t base, void *parent, int parent_irq);
+qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq);
 
 /* arm_boot.c */
 
 void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
                      const char *kernel_cmdline, const char *initrd_filename,
-                     int board_id);
+                     int board_id, target_phys_addr_t loader_start);
 
 /* sh7750.c */
 struct SH7750State;
@@ -1399,18 +1559,170 @@
 
 int sh7750_register_io_device(struct SH7750State *s,
 			      sh7750_io_device * device);
+/* sh_timer.c */
+#define TMU012_FEAT_TOCR   (1 << 0)
+#define TMU012_FEAT_3CHAN  (1 << 1)
+#define TMU012_FEAT_EXTCLK (1 << 2)
+void tmu012_init(uint32_t base, int feat, uint32_t freq);
+
+/* sh_serial.c */
+#define SH_SERIAL_FEAT_SCIF (1 << 0)
+void sh_serial_init (target_phys_addr_t base, int feat,
+		     uint32_t freq, CharDriverState *chr);
+
 /* tc58128.c */
 int tc58128_init(struct SH7750State *s, char *zone1, char *zone2);
 
 /* NOR flash devices */
+#define MAX_PFLASH 4
+extern BlockDriverState *pflash_table[MAX_PFLASH];
 typedef struct pflash_t pflash_t;
 
-pflash_t *pflash_register (target_ulong base, ram_addr_t off,
+pflash_t *pflash_register (target_phys_addr_t base, ram_addr_t off,
                            BlockDriverState *bs,
-                           target_ulong sector_len, int nb_blocs, int width,
-                           uint16_t id0, uint16_t id1, 
+                           uint32_t sector_len, int nb_blocs, int width,
+                           uint16_t id0, uint16_t id1,
                            uint16_t id2, uint16_t id3);
 
+/* nand.c */
+struct nand_flash_s;
+struct nand_flash_s *nand_init(int manf_id, int chip_id);
+void nand_done(struct nand_flash_s *s);
+void nand_setpins(struct nand_flash_s *s,
+                int cle, int ale, int ce, int wp, int gnd);
+void nand_getpins(struct nand_flash_s *s, int *rb);
+void nand_setio(struct nand_flash_s *s, uint8_t value);
+uint8_t nand_getio(struct nand_flash_s *s);
+
+#define NAND_MFR_TOSHIBA	0x98
+#define NAND_MFR_SAMSUNG	0xec
+#define NAND_MFR_FUJITSU	0x04
+#define NAND_MFR_NATIONAL	0x8f
+#define NAND_MFR_RENESAS	0x07
+#define NAND_MFR_STMICRO	0x20
+#define NAND_MFR_HYNIX		0xad
+#define NAND_MFR_MICRON		0x2c
+
+/* ecc.c */
+struct ecc_state_s {
+    uint8_t cp;		/* Column parity */
+    uint16_t lp[2];	/* Line parity */
+    uint16_t count;
+};
+
+uint8_t ecc_digest(struct ecc_state_s *s, uint8_t sample);
+void ecc_reset(struct ecc_state_s *s);
+void ecc_put(QEMUFile *f, struct ecc_state_s *s);
+void ecc_get(QEMUFile *f, struct ecc_state_s *s);
+
+/* GPIO */
+typedef void (*gpio_handler_t)(int line, int level, void *opaque);
+
+/* ads7846.c */
+struct ads7846_state_s;
+uint32_t ads7846_read(void *opaque);
+void ads7846_write(void *opaque, uint32_t value);
+struct ads7846_state_s *ads7846_init(qemu_irq penirq);
+
+/* max111x.c */
+struct max111x_s;
+uint32_t max111x_read(void *opaque);
+void max111x_write(void *opaque, uint32_t value);
+struct max111x_s *max1110_init(qemu_irq cb);
+struct max111x_s *max1111_init(qemu_irq cb);
+void max111x_set_input(struct max111x_s *s, int line, uint8_t value);
+
+/* PCMCIA/Cardbus */
+
+struct pcmcia_socket_s {
+    qemu_irq irq;
+    int attached;
+    const char *slot_string;
+    const char *card_string;
+};
+
+void pcmcia_socket_register(struct pcmcia_socket_s *socket);
+void pcmcia_socket_unregister(struct pcmcia_socket_s *socket);
+void pcmcia_info(void);
+
+struct pcmcia_card_s {
+    void *state;
+    struct pcmcia_socket_s *slot;
+    int (*attach)(void *state);
+    int (*detach)(void *state);
+    const uint8_t *cis;
+    int cis_len;
+
+    /* Only valid if attached */
+    uint8_t (*attr_read)(void *state, uint32_t address);
+    void (*attr_write)(void *state, uint32_t address, uint8_t value);
+    uint16_t (*common_read)(void *state, uint32_t address);
+    void (*common_write)(void *state, uint32_t address, uint16_t value);
+    uint16_t (*io_read)(void *state, uint32_t address);
+    void (*io_write)(void *state, uint32_t address, uint16_t value);
+};
+
+#define CISTPL_DEVICE		0x01	/* 5V Device Information Tuple */
+#define CISTPL_NO_LINK		0x14	/* No Link Tuple */
+#define CISTPL_VERS_1		0x15	/* Level 1 Version Tuple */
+#define CISTPL_JEDEC_C		0x18	/* JEDEC ID Tuple */
+#define CISTPL_JEDEC_A		0x19	/* JEDEC ID Tuple */
+#define CISTPL_CONFIG		0x1a	/* Configuration Tuple */
+#define CISTPL_CFTABLE_ENTRY	0x1b	/* 16-bit PCCard Configuration */
+#define CISTPL_DEVICE_OC	0x1c	/* Additional Device Information */
+#define CISTPL_DEVICE_OA	0x1d	/* Additional Device Information */
+#define CISTPL_DEVICE_GEO	0x1e	/* Additional Device Information */
+#define CISTPL_DEVICE_GEO_A	0x1f	/* Additional Device Information */
+#define CISTPL_MANFID		0x20	/* Manufacture ID Tuple */
+#define CISTPL_FUNCID		0x21	/* Function ID Tuple */
+#define CISTPL_FUNCE		0x22	/* Function Extension Tuple */
+#define CISTPL_END		0xff	/* Tuple End */
+#define CISTPL_ENDMARK		0xff
+
+/* 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, uint64_t limit, int reload);
+uint64_t ptimer_get_count(ptimer_state *s);
+void ptimer_set_count(ptimer_state *s, uint64_t count);
+void ptimer_run(ptimer_state *s, int oneshot);
+void ptimer_stop(ptimer_state *s);
+void qemu_put_ptimer(QEMUFile *f, ptimer_state *s);
+void qemu_get_ptimer(QEMUFile *f, ptimer_state *s);
+
+#include "hw/pxa.h"
+
+#include "hw/omap.h"
+
+/* mcf_uart.c */
+uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr);
+void mcf_uart_write(void *opaque, target_phys_addr_t addr, uint32_t val);
+void *mcf_uart_init(qemu_irq irq, CharDriverState *chr);
+void mcf_uart_mm_init(target_phys_addr_t base, qemu_irq irq,
+                      CharDriverState *chr);
+
+/* mcf_intc.c */
+qemu_irq *mcf_intc_init(target_phys_addr_t base, CPUState *env);
+
+/* mcf_fec.c */
+void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq);
+
+/* mcf5206.c */
+qemu_irq *mcf5206_init(uint32_t base, CPUState *env);
+
+/* an5206.c */
+extern QEMUMachine an5206_machine;
+
+/* mcf5208.c */
+extern QEMUMachine mcf5208evb_machine;
+
 #include "gdbstub.h"
 
 #endif /* defined(QEMU_TOOL) */
diff --git a/vnc.c b/vnc.c
index bf70e50..2b0b3b6 100644
--- a/vnc.c
+++ b/vnc.c
@@ -1,9 +1,9 @@
 /*
  * QEMU VNC display driver
- * 
+ *
  * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
  * Copyright (C) 2006 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -30,6 +30,28 @@
 
 #include "vnc_keysym.h"
 #include "keymaps.c"
+#include "d3des.h"
+
+#if CONFIG_VNC_TLS
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#endif /* CONFIG_VNC_TLS */
+
+// #define _VNC_DEBUG 1
+
+#if _VNC_DEBUG
+#define VNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
+
+#if CONFIG_VNC_TLS && _VNC_DEBUG >= 2
+/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
+static void vnc_debug_gnutls_log(int level, const char* str) {
+    VNC_DEBUG("%d %s", level, str);
+}
+#endif /* CONFIG_VNC_TLS && _VNC_DEBUG */
+#else
+#define VNC_DEBUG(fmt, ...) do { } while (0)
+#endif
+
 
 typedef struct Buffer
 {
@@ -46,7 +68,7 @@
 
 typedef void VncSendHextileTile(VncState *vs,
                                 int x, int y, int w, int h,
-                                uint32_t *last_bg, 
+                                uint32_t *last_bg,
                                 uint32_t *last_fg,
                                 int *has_bg, int *has_fg);
 
@@ -54,6 +76,45 @@
 #define VNC_MAX_HEIGHT 2048
 #define VNC_DIRTY_WORDS (VNC_MAX_WIDTH / (16 * 32))
 
+#define VNC_AUTH_CHALLENGE_SIZE 16
+
+enum {
+    VNC_AUTH_INVALID = 0,
+    VNC_AUTH_NONE = 1,
+    VNC_AUTH_VNC = 2,
+    VNC_AUTH_RA2 = 5,
+    VNC_AUTH_RA2NE = 6,
+    VNC_AUTH_TIGHT = 16,
+    VNC_AUTH_ULTRA = 17,
+    VNC_AUTH_TLS = 18,
+    VNC_AUTH_VENCRYPT = 19
+};
+
+#if CONFIG_VNC_TLS
+enum {
+    VNC_WIREMODE_CLEAR,
+    VNC_WIREMODE_TLS,
+};
+
+enum {
+    VNC_AUTH_VENCRYPT_PLAIN = 256,
+    VNC_AUTH_VENCRYPT_TLSNONE = 257,
+    VNC_AUTH_VENCRYPT_TLSVNC = 258,
+    VNC_AUTH_VENCRYPT_TLSPLAIN = 259,
+    VNC_AUTH_VENCRYPT_X509NONE = 260,
+    VNC_AUTH_VENCRYPT_X509VNC = 261,
+    VNC_AUTH_VENCRYPT_X509PLAIN = 262,
+};
+
+#if CONFIG_VNC_TLS
+#define X509_CA_CERT_FILE "ca-cert.pem"
+#define X509_CA_CRL_FILE "ca-crl.pem"
+#define X509_SERVER_KEY_FILE "server-key.pem"
+#define X509_SERVER_CERT_FILE "server-cert.pem"
+#endif
+
+#endif /* CONFIG_VNC_TLS */
+
 struct VncState
 {
     QEMUTimer *timer;
@@ -73,7 +134,27 @@
     int last_x;
     int last_y;
 
-    const char *display;
+    int major;
+    int minor;
+
+    char *display;
+    char *password;
+    int auth;
+#if CONFIG_VNC_TLS
+    int subauth;
+    int x509verify;
+
+    char *x509cacert;
+    char *x509cacrl;
+    char *x509cert;
+    char *x509key;
+#endif
+    char challenge[VNC_AUTH_CHALLENGE_SIZE];
+
+#if CONFIG_VNC_TLS
+    int wiremode;
+    gnutls_session_t tls_session;
+#endif
 
     Buffer output;
     Buffer input;
@@ -145,7 +226,7 @@
         d[j++] = -1;
         n -= 32;
     }
-    if (n > 0) 
+    if (n > 0)
         d[j++] = (1 << n) - 1;
     while (j < nb_words)
         d[j++] = 0;
@@ -156,7 +237,7 @@
     return (d[k >> 5] >> (k & 0x1f)) & 1;
 }
 
-static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2, 
+static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
                                int nb_words)
 {
     int i;
@@ -233,8 +314,8 @@
     r = (v >> vs->red_shift1) & vs->red_max;
     g = (v >> vs->green_shift1) & vs->green_max;
     b = (v >> vs->blue_shift1) & vs->blue_max;
-    v = (r << vs->red_shift) | 
-        (g << vs->green_shift) | 
+    v = (r << vs->red_shift) |
+        (g << vs->green_shift) |
         (b << vs->blue_shift);
     switch(vs->pix_bpp) {
     case 1:
@@ -328,7 +409,7 @@
     has_fg = has_bg = 0;
     for (j = y; j < (y + h); j += 16) {
 	for (i = x; i < (x + w); i += 16) {
-            vs->send_hextile_tile(vs, i, j, 
+            vs->send_hextile_tile(vs, i, j,
                                   MIN(16, x + w - i), MIN(16, y + h - j),
                                   &last_bg32, &last_fg32, &has_bg, &has_fg);
 	}
@@ -550,12 +631,20 @@
 	if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN))
 	    return 0;
 
+	VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
 	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
 	closesocket(vs->csock);
 	vs->csock = -1;
 	buffer_reset(&vs->input);
 	buffer_reset(&vs->output);
 	vs->need_update = 0;
+#if CONFIG_VNC_TLS
+	if (vs->tls_session) {
+	    gnutls_deinit(vs->tls_session);
+	    vs->tls_session = NULL;
+	}
+	vs->wiremode = VNC_WIREMODE_CLEAR;
+#endif /* CONFIG_VNC_TLS */
 	return 0;
     }
     return ret;
@@ -571,7 +660,19 @@
     long ret;
     VncState *vs = opaque;
 
-    ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
+#if CONFIG_VNC_TLS
+    if (vs->tls_session) {
+	ret = gnutls_write(vs->tls_session, vs->output.buffer, vs->output.offset);
+	if (ret < 0) {
+	    if (ret == GNUTLS_E_AGAIN)
+		errno = EAGAIN;
+	    else
+		errno = EIO;
+	    ret = -1;
+	}
+    } else
+#endif /* CONFIG_VNC_TLS */
+	ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
     ret = vnc_client_io_error(vs, ret, socket_error());
     if (!ret)
 	return;
@@ -597,7 +698,19 @@
 
     buffer_reserve(&vs->input, 4096);
 
-    ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
+#if CONFIG_VNC_TLS
+    if (vs->tls_session) {
+	ret = gnutls_read(vs->tls_session, buffer_end(&vs->input), 4096);
+	if (ret < 0) {
+	    if (ret == GNUTLS_E_AGAIN)
+		errno = EAGAIN;
+	    else
+		errno = EIO;
+	    ret = -1;
+	}
+    } else
+#endif /* CONFIG_VNC_TLS */
+	ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
     ret = vnc_client_io_error(vs, ret, socket_error());
     if (!ret)
 	return;
@@ -692,6 +805,41 @@
 	    (data[offset + 2] << 8) | data[offset + 3]);
 }
 
+#if CONFIG_VNC_TLS
+ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
+		     const void *data,
+		     size_t len) {
+    struct VncState *vs = (struct VncState *)transport;
+    int ret;
+
+ retry:
+    ret = send(vs->csock, data, len, 0);
+    if (ret < 0) {
+	if (errno == EINTR)
+	    goto retry;
+	return -1;
+    }
+    return ret;
+}
+
+
+ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
+		     void *data,
+		     size_t len) {
+    struct VncState *vs = (struct VncState *)transport;
+    int ret;
+
+ retry:
+    ret = recv(vs->csock, data, len, 0);
+    if (ret < 0) {
+	if (errno == EINTR)
+	    goto retry;
+	return -1;
+    }
+    return ret;
+}
+#endif /* CONFIG_VNC_TLS */
+
 static void client_cut_text(VncState *vs, size_t len, char *text)
 {
 }
@@ -764,7 +912,7 @@
     int keycode;
 
     keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
-    
+
     /* QEMU console switch */
     switch(keycode) {
     case 0x2a:                          /* Left Shift */
@@ -778,7 +926,7 @@
         else
             vs->modifiers_state[keycode] = 0;
         break;
-    case 0x02 ... 0x0a: /* '1' to '9' keys */ 
+    case 0x02 ... 0x0a: /* '1' to '9' keys */
         if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) {
             /* Reset the modifiers sent to the current console */
             reset_keys(vs);
@@ -867,7 +1015,7 @@
 	char *old_row = vs->old_data + y_position * vs->ds->linesize;
 
 	for (i = 0; i < h; i++) {
-            vnc_set_bits(vs->dirty_row[y_position + i], 
+            vnc_set_bits(vs->dirty_row[y_position + i],
                          (vs->ds->width / 16), VNC_DIRTY_WORDS);
 	    memset(old_row, 42, vs->ds->width * vs->depth);
 	    old_row += vs->ds->linesize;
@@ -939,29 +1087,29 @@
 	vnc_client_error(vs);
         return;
     }
-    if (bits_per_pixel == 32 && 
+    if (bits_per_pixel == 32 &&
         host_big_endian_flag == big_endian_flag &&
         red_max == 0xff && green_max == 0xff && blue_max == 0xff &&
         red_shift == 16 && green_shift == 8 && blue_shift == 0) {
         vs->depth = 4;
         vs->write_pixels = vnc_write_pixels_copy;
         vs->send_hextile_tile = send_hextile_tile_32;
-    } else 
-    if (bits_per_pixel == 16 && 
+    } else
+    if (bits_per_pixel == 16 &&
         host_big_endian_flag == big_endian_flag &&
         red_max == 31 && green_max == 63 && blue_max == 31 &&
         red_shift == 11 && green_shift == 5 && blue_shift == 0) {
         vs->depth = 2;
         vs->write_pixels = vnc_write_pixels_copy;
         vs->send_hextile_tile = send_hextile_tile_16;
-    } else 
-    if (bits_per_pixel == 8 && 
+    } else
+    if (bits_per_pixel == 8 &&
         red_max == 7 && green_max == 7 && blue_max == 3 &&
         red_shift == 5 && green_shift == 2 && blue_shift == 0) {
         vs->depth = 1;
         vs->write_pixels = vnc_write_pixels_copy;
         vs->send_hextile_tile = send_hextile_tile_8;
-    } else 
+    } else
     {
         /* generic and slower case */
         if (bits_per_pixel != 8 &&
@@ -1047,8 +1195,11 @@
 	if (len == 1)
 	    return 8;
 
-	if (len == 8)
-	    return 8 + read_u32(data, 4);
+	if (len == 8) {
+            uint32_t dlen = read_u32(data, 4);
+            if (dlen > 0)
+                return 8 + dlen;
+        }
 
 	client_cut_text(vs, read_u32(data, 4), data + 8);
 	break;
@@ -1057,7 +1208,7 @@
 	vnc_client_error(vs);
 	break;
     }
-	
+
     vnc_read_when(vs, protocol_client_msg, 1);
     return 0;
 }
@@ -1065,6 +1216,9 @@
 static int protocol_client_init(VncState *vs, char *data, size_t len)
 {
     char pad[3] = { 0, 0, 0 };
+    char buf[1024];
+    int size;
+    unsigned char *prog = "QEMU";
 
     vs->width = vs->ds->width;
     vs->height = vs->ds->height;
@@ -1106,19 +1260,21 @@
         vs->send_hextile_tile = send_hextile_tile_8;
     }
     vs->write_pixels = vnc_write_pixels_copy;
-	
+
     vnc_write(vs, pad, 3);           /* padding */
 
 #if USE_KVM
-    if (kvm_allowed) {
-        vnc_write_u32(vs, 8);
-        vnc_write(vs, "QEMU/KVM", 8);
-    } else
+    if (kvm_allowed)
+	prog = "QEMU/KVM";
 #endif
-    {
-        vnc_write_u32(vs, 4);
-        vnc_write(vs, "QEMU", 4);
-    }
+
+    if (qemu_name)
+        size = snprintf(buf, sizeof(buf), "%s (%s)", prog, qemu_name);
+    else
+        size = snprintf(buf, sizeof(buf), "%s", prog);
+
+    vnc_write_u32(vs, size);
+    vnc_write(vs, buf, size);
     vnc_flush(vs);
 
     vnc_read_when(vs, protocol_client_msg, 1);
@@ -1126,23 +1282,588 @@
     return 0;
 }
 
-static int protocol_version(VncState *vs, char *version, size_t len)
+static void make_challenge(VncState *vs)
 {
-    char local[13];
-    int maj, min;
+    int i;
 
-    memcpy(local, version, 12);
-    local[12] = 0;
+    srand(time(NULL)+getpid()+getpid()*987654+rand());
 
-    if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) {
+    for (i = 0 ; i < sizeof(vs->challenge) ; i++)
+        vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0));
+}
+
+static int protocol_client_auth_vnc(VncState *vs, char *data, size_t len)
+{
+    char response[VNC_AUTH_CHALLENGE_SIZE];
+    int i, j, pwlen;
+    char key[8];
+
+    if (!vs->password || !vs->password[0]) {
+	VNC_DEBUG("No password configured on server");
+	vnc_write_u32(vs, 1); /* Reject auth */
+	if (vs->minor >= 8) {
+	    static const char err[] = "Authentication failed";
+	    vnc_write_u32(vs, sizeof(err));
+	    vnc_write(vs, err, sizeof(err));
+	}
+	vnc_flush(vs);
 	vnc_client_error(vs);
 	return 0;
     }
 
-    vnc_write_u32(vs, 1); /* None */
+    memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
+
+    /* Calculate the expected challenge response */
+    pwlen = strlen(vs->password);
+    for (i=0; i<sizeof(key); i++)
+        key[i] = i<pwlen ? vs->password[i] : 0;
+    deskey(key, EN0);
+    for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
+        des(response+j, response+j);
+
+    /* Compare expected vs actual challenge response */
+    if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) {
+	VNC_DEBUG("Client challenge reponse did not match\n");
+	vnc_write_u32(vs, 1); /* Reject auth */
+	if (vs->minor >= 8) {
+	    static const char err[] = "Authentication failed";
+	    vnc_write_u32(vs, sizeof(err));
+	    vnc_write(vs, err, sizeof(err));
+	}
+	vnc_flush(vs);
+	vnc_client_error(vs);
+    } else {
+	VNC_DEBUG("Accepting VNC challenge response\n");
+	vnc_write_u32(vs, 0); /* Accept auth */
+	vnc_flush(vs);
+
+	vnc_read_when(vs, protocol_client_init, 1);
+    }
+    return 0;
+}
+
+static int start_auth_vnc(VncState *vs)
+{
+    make_challenge(vs);
+    /* Send client a 'random' challenge */
+    vnc_write(vs, vs->challenge, sizeof(vs->challenge));
     vnc_flush(vs);
 
-    vnc_read_when(vs, protocol_client_init, 1);
+    vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge));
+    return 0;
+}
+
+
+#if CONFIG_VNC_TLS
+#define DH_BITS 1024
+static gnutls_dh_params_t dh_params;
+
+static int vnc_tls_initialize(void)
+{
+    static int tlsinitialized = 0;
+
+    if (tlsinitialized)
+	return 1;
+
+    if (gnutls_global_init () < 0)
+	return 0;
+
+    /* XXX ought to re-generate diffie-hellmen params periodically */
+    if (gnutls_dh_params_init (&dh_params) < 0)
+	return 0;
+    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
+	return 0;
+
+#if _VNC_DEBUG == 2
+    gnutls_global_set_log_level(10);
+    gnutls_global_set_log_function(vnc_debug_gnutls_log);
+#endif
+
+    tlsinitialized = 1;
+
+    return 1;
+}
+
+static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
+{
+    gnutls_anon_server_credentials anon_cred;
+    int ret;
+
+    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
+	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
+	return NULL;
+    }
+
+    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
+
+    return anon_cred;
+}
+
+
+static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *vs)
+{
+    gnutls_certificate_credentials_t x509_cred;
+    int ret;
+
+    if (!vs->x509cacert) {
+	VNC_DEBUG("No CA x509 certificate specified\n");
+	return NULL;
+    }
+    if (!vs->x509cert) {
+	VNC_DEBUG("No server x509 certificate specified\n");
+	return NULL;
+    }
+    if (!vs->x509key) {
+	VNC_DEBUG("No server private key specified\n");
+	return NULL;
+    }
+
+    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
+	VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
+	return NULL;
+    }
+    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
+						      vs->x509cacert,
+						      GNUTLS_X509_FMT_PEM)) < 0) {
+	VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
+	gnutls_certificate_free_credentials(x509_cred);
+	return NULL;
+    }
+
+    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
+						     vs->x509cert,
+						     vs->x509key,
+						     GNUTLS_X509_FMT_PEM)) < 0) {
+	VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
+	gnutls_certificate_free_credentials(x509_cred);
+	return NULL;
+    }
+
+    if (vs->x509cacrl) {
+	if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
+							vs->x509cacrl,
+							GNUTLS_X509_FMT_PEM)) < 0) {
+	    VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
+	    gnutls_certificate_free_credentials(x509_cred);
+	    return NULL;
+	}
+    }
+
+    gnutls_certificate_set_dh_params (x509_cred, dh_params);
+
+    return x509_cred;
+}
+
+static int vnc_validate_certificate(struct VncState *vs)
+{
+    int ret;
+    unsigned int status;
+    const gnutls_datum_t *certs;
+    unsigned int nCerts, i;
+    time_t now;
+
+    VNC_DEBUG("Validating client certificate\n");
+    if ((ret = gnutls_certificate_verify_peers2 (vs->tls_session, &status)) < 0) {
+	VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
+	return -1;
+    }
+
+    if ((now = time(NULL)) == ((time_t)-1)) {
+	return -1;
+    }
+
+    if (status != 0) {
+	if (status & GNUTLS_CERT_INVALID)
+	    VNC_DEBUG("The certificate is not trusted.\n");
+
+	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+	    VNC_DEBUG("The certificate hasn't got a known issuer.\n");
+
+	if (status & GNUTLS_CERT_REVOKED)
+	    VNC_DEBUG("The certificate has been revoked.\n");
+
+	if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
+	    VNC_DEBUG("The certificate uses an insecure algorithm\n");
+
+	return -1;
+    } else {
+	VNC_DEBUG("Certificate is valid!\n");
+    }
+
+    /* Only support x509 for now */
+    if (gnutls_certificate_type_get(vs->tls_session) != GNUTLS_CRT_X509)
+	return -1;
+
+    if (!(certs = gnutls_certificate_get_peers(vs->tls_session, &nCerts)))
+	return -1;
+
+    for (i = 0 ; i < nCerts ; i++) {
+	gnutls_x509_crt_t cert;
+	VNC_DEBUG ("Checking certificate chain %d\n", i);
+	if (gnutls_x509_crt_init (&cert) < 0)
+	    return -1;
+
+	if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
+	    gnutls_x509_crt_deinit (cert);
+	    return -1;
+	}
+
+	if (gnutls_x509_crt_get_expiration_time (cert) < now) {
+	    VNC_DEBUG("The certificate has expired\n");
+	    gnutls_x509_crt_deinit (cert);
+	    return -1;
+	}
+
+	if (gnutls_x509_crt_get_activation_time (cert) > now) {
+	    VNC_DEBUG("The certificate is not yet activated\n");
+	    gnutls_x509_crt_deinit (cert);
+	    return -1;
+	}
+
+	if (gnutls_x509_crt_get_activation_time (cert) > now) {
+	    VNC_DEBUG("The certificate is not yet activated\n");
+	    gnutls_x509_crt_deinit (cert);
+	    return -1;
+	}
+
+	gnutls_x509_crt_deinit (cert);
+    }
+
+    return 0;
+}
+
+
+static int start_auth_vencrypt_subauth(VncState *vs)
+{
+    switch (vs->subauth) {
+    case VNC_AUTH_VENCRYPT_TLSNONE:
+    case VNC_AUTH_VENCRYPT_X509NONE:
+       VNC_DEBUG("Accept TLS auth none\n");
+       vnc_write_u32(vs, 0); /* Accept auth completion */
+       vnc_read_when(vs, protocol_client_init, 1);
+       break;
+
+    case VNC_AUTH_VENCRYPT_TLSVNC:
+    case VNC_AUTH_VENCRYPT_X509VNC:
+       VNC_DEBUG("Start TLS auth VNC\n");
+       return start_auth_vnc(vs);
+
+    default: /* Should not be possible, but just in case */
+       VNC_DEBUG("Reject auth %d\n", vs->auth);
+       vnc_write_u8(vs, 1);
+       if (vs->minor >= 8) {
+           static const char err[] = "Unsupported authentication type";
+           vnc_write_u32(vs, sizeof(err));
+           vnc_write(vs, err, sizeof(err));
+       }
+       vnc_client_error(vs);
+    }
+
+    return 0;
+}
+
+static void vnc_handshake_io(void *opaque);
+
+static int vnc_continue_handshake(struct VncState *vs) {
+    int ret;
+
+    if ((ret = gnutls_handshake(vs->tls_session)) < 0) {
+       if (!gnutls_error_is_fatal(ret)) {
+           VNC_DEBUG("Handshake interrupted (blocking)\n");
+           if (!gnutls_record_get_direction(vs->tls_session))
+               qemu_set_fd_handler(vs->csock, vnc_handshake_io, NULL, vs);
+           else
+               qemu_set_fd_handler(vs->csock, NULL, vnc_handshake_io, vs);
+           return 0;
+       }
+       VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
+       vnc_client_error(vs);
+       return -1;
+    }
+
+    if (vs->x509verify) {
+	if (vnc_validate_certificate(vs) < 0) {
+	    VNC_DEBUG("Client verification failed\n");
+	    vnc_client_error(vs);
+	    return -1;
+	} else {
+	    VNC_DEBUG("Client verification passed\n");
+	}
+    }
+
+    VNC_DEBUG("Handshake done, switching to TLS data mode\n");
+    vs->wiremode = VNC_WIREMODE_TLS;
+    qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
+
+    return start_auth_vencrypt_subauth(vs);
+}
+
+static void vnc_handshake_io(void *opaque) {
+    struct VncState *vs = (struct VncState *)opaque;
+
+    VNC_DEBUG("Handshake IO continue\n");
+    vnc_continue_handshake(vs);
+}
+
+#define NEED_X509_AUTH(vs)			      \
+    ((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE ||   \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC ||    \
+     (vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
+
+
+static int vnc_start_tls(struct VncState *vs) {
+    static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+    static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
+    static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
+    static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
+
+    VNC_DEBUG("Do TLS setup\n");
+    if (vnc_tls_initialize() < 0) {
+	VNC_DEBUG("Failed to init TLS\n");
+	vnc_client_error(vs);
+	return -1;
+    }
+    if (vs->tls_session == NULL) {
+	if (gnutls_init(&vs->tls_session, GNUTLS_SERVER) < 0) {
+	    vnc_client_error(vs);
+	    return -1;
+	}
+
+	if (gnutls_set_default_priority(vs->tls_session) < 0) {
+	    gnutls_deinit(vs->tls_session);
+	    vs->tls_session = NULL;
+	    vnc_client_error(vs);
+	    return -1;
+	}
+
+	if (gnutls_kx_set_priority(vs->tls_session, NEED_X509_AUTH(vs) ? kx_x509 : kx_anon) < 0) {
+	    gnutls_deinit(vs->tls_session);
+	    vs->tls_session = NULL;
+	    vnc_client_error(vs);
+	    return -1;
+	}
+
+	if (gnutls_certificate_type_set_priority(vs->tls_session, cert_type_priority) < 0) {
+	    gnutls_deinit(vs->tls_session);
+	    vs->tls_session = NULL;
+	    vnc_client_error(vs);
+	    return -1;
+	}
+
+	if (gnutls_protocol_set_priority(vs->tls_session, protocol_priority) < 0) {
+	    gnutls_deinit(vs->tls_session);
+	    vs->tls_session = NULL;
+	    vnc_client_error(vs);
+	    return -1;
+	}
+
+	if (NEED_X509_AUTH(vs)) {
+	    gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs);
+	    if (!x509_cred) {
+		gnutls_deinit(vs->tls_session);
+		vs->tls_session = NULL;
+		vnc_client_error(vs);
+		return -1;
+	    }
+	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
+		gnutls_deinit(vs->tls_session);
+		vs->tls_session = NULL;
+		gnutls_certificate_free_credentials(x509_cred);
+		vnc_client_error(vs);
+		return -1;
+	    }
+	    if (vs->x509verify) {
+		VNC_DEBUG("Requesting a client certificate\n");
+		gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
+	    }
+
+	} else {
+	    gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
+	    if (!anon_cred) {
+		gnutls_deinit(vs->tls_session);
+		vs->tls_session = NULL;
+		vnc_client_error(vs);
+		return -1;
+	    }
+	    if (gnutls_credentials_set(vs->tls_session, GNUTLS_CRD_ANON, anon_cred) < 0) {
+		gnutls_deinit(vs->tls_session);
+		vs->tls_session = NULL;
+		gnutls_anon_free_server_credentials(anon_cred);
+		vnc_client_error(vs);
+		return -1;
+	    }
+	}
+
+	gnutls_transport_set_ptr(vs->tls_session, (gnutls_transport_ptr_t)vs);
+	gnutls_transport_set_push_function(vs->tls_session, vnc_tls_push);
+	gnutls_transport_set_pull_function(vs->tls_session, vnc_tls_pull);
+    }
+
+    VNC_DEBUG("Start TLS handshake process\n");
+    return vnc_continue_handshake(vs);
+}
+
+static int protocol_client_vencrypt_auth(VncState *vs, char *data, size_t len)
+{
+    int auth = read_u32(data, 0);
+
+    if (auth != vs->subauth) {
+	VNC_DEBUG("Rejecting auth %d\n", auth);
+	vnc_write_u8(vs, 0); /* Reject auth */
+	vnc_flush(vs);
+	vnc_client_error(vs);
+    } else {
+	VNC_DEBUG("Accepting auth %d, starting handshake\n", auth);
+	vnc_write_u8(vs, 1); /* Accept auth */
+	vnc_flush(vs);
+
+	if (vnc_start_tls(vs) < 0) {
+	    VNC_DEBUG("Failed to complete TLS\n");
+	    return 0;
+	}
+
+	if (vs->wiremode == VNC_WIREMODE_TLS) {
+	    VNC_DEBUG("Starting VeNCrypt subauth\n");
+	    return start_auth_vencrypt_subauth(vs);
+	} else {
+	    VNC_DEBUG("TLS handshake blocked\n");
+	    return 0;
+	}
+    }
+    return 0;
+}
+
+static int protocol_client_vencrypt_init(VncState *vs, char *data, size_t len)
+{
+    if (data[0] != 0 ||
+	data[1] != 2) {
+	VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
+	vnc_write_u8(vs, 1); /* Reject version */
+	vnc_flush(vs);
+	vnc_client_error(vs);
+    } else {
+	VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
+	vnc_write_u8(vs, 0); /* Accept version */
+	vnc_write_u8(vs, 1); /* Number of sub-auths */
+	vnc_write_u32(vs, vs->subauth); /* The supported auth */
+	vnc_flush(vs);
+	vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
+    }
+    return 0;
+}
+
+static int start_auth_vencrypt(VncState *vs)
+{
+    /* Send VeNCrypt version 0.2 */
+    vnc_write_u8(vs, 0);
+    vnc_write_u8(vs, 2);
+
+    vnc_read_when(vs, protocol_client_vencrypt_init, 2);
+    return 0;
+}
+#endif /* CONFIG_VNC_TLS */
+
+static int protocol_client_auth(VncState *vs, char *data, size_t len)
+{
+    /* We only advertise 1 auth scheme at a time, so client
+     * must pick the one we sent. Verify this */
+    if (data[0] != vs->auth) { /* Reject auth */
+       VNC_DEBUG("Reject auth %d\n", (int)data[0]);
+       vnc_write_u32(vs, 1);
+       if (vs->minor >= 8) {
+           static const char err[] = "Authentication failed";
+           vnc_write_u32(vs, sizeof(err));
+           vnc_write(vs, err, sizeof(err));
+       }
+       vnc_client_error(vs);
+    } else { /* Accept requested auth */
+       VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
+       switch (vs->auth) {
+       case VNC_AUTH_NONE:
+           VNC_DEBUG("Accept auth none\n");
+           vnc_write_u32(vs, 0); /* Accept auth completion */
+           vnc_read_when(vs, protocol_client_init, 1);
+           break;
+
+       case VNC_AUTH_VNC:
+           VNC_DEBUG("Start VNC auth\n");
+           return start_auth_vnc(vs);
+
+#if CONFIG_VNC_TLS
+       case VNC_AUTH_VENCRYPT:
+           VNC_DEBUG("Accept VeNCrypt auth\n");;
+           return start_auth_vencrypt(vs);
+#endif /* CONFIG_VNC_TLS */
+
+       default: /* Should not be possible, but just in case */
+           VNC_DEBUG("Reject auth %d\n", vs->auth);
+           vnc_write_u8(vs, 1);
+           if (vs->minor >= 8) {
+               static const char err[] = "Authentication failed";
+               vnc_write_u32(vs, sizeof(err));
+               vnc_write(vs, err, sizeof(err));
+           }
+           vnc_client_error(vs);
+       }
+    }
+    return 0;
+}
+
+static int protocol_version(VncState *vs, char *version, size_t len)
+{
+    char local[13];
+
+    memcpy(local, version, 12);
+    local[12] = 0;
+
+    if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) {
+	VNC_DEBUG("Malformed protocol version %s\n", local);
+	vnc_client_error(vs);
+	return 0;
+    }
+    VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor);
+    if (vs->major != 3 ||
+	(vs->minor != 3 &&
+	 vs->minor != 4 &&
+	 vs->minor != 5 &&
+	 vs->minor != 7 &&
+	 vs->minor != 8)) {
+	VNC_DEBUG("Unsupported client version\n");
+	vnc_write_u32(vs, VNC_AUTH_INVALID);
+	vnc_flush(vs);
+	vnc_client_error(vs);
+	return 0;
+    }
+    /* Some broken clients report v3.4 or v3.5, which spec requires to be treated
+     * as equivalent to v3.3 by servers
+     */
+    if (vs->minor == 4 || vs->minor == 5)
+	vs->minor = 3;
+
+    if (vs->minor == 3) {
+	if (vs->auth == VNC_AUTH_NONE) {
+            VNC_DEBUG("Tell client auth none\n");
+            vnc_write_u32(vs, vs->auth);
+            vnc_flush(vs);
+            vnc_read_when(vs, protocol_client_init, 1);
+       } else if (vs->auth == VNC_AUTH_VNC) {
+            VNC_DEBUG("Tell client VNC auth\n");
+            vnc_write_u32(vs, vs->auth);
+            vnc_flush(vs);
+            start_auth_vnc(vs);
+       } else {
+            VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
+            vnc_write_u32(vs, VNC_AUTH_INVALID);
+            vnc_flush(vs);
+            vnc_client_error(vs);
+       }
+    } else {
+	VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
+	vnc_write_u8(vs, 1); /* num auth */
+	vnc_write_u8(vs, vs->auth);
+	vnc_read_when(vs, protocol_client_auth, 1);
+	vnc_flush(vs);
+    }
 
     return 0;
 }
@@ -1155,9 +1876,10 @@
 
     vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
     if (vs->csock != -1) {
+	VNC_DEBUG("New client on socket %d\n", vs->csock);
         socket_set_nonblock(vs->csock);
 	qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque);
-	vnc_write(vs, "RFB 003.003\n", 12);
+	vnc_write(vs, "RFB 003.008\n", 12);
 	vnc_flush(vs);
 	vnc_read_when(vs, protocol_version, 12);
 	memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height);
@@ -1170,16 +1892,8 @@
 
 extern int parse_host_port(struct sockaddr_in *saddr, const char *str);
 
-void vnc_display_init(DisplayState *ds, const char *arg)
+void vnc_display_init(DisplayState *ds)
 {
-    struct sockaddr *addr;
-    struct sockaddr_in iaddr;
-#ifndef _WIN32
-    struct sockaddr_un uaddr;
-#endif
-    int reuse_addr, ret;
-    socklen_t addrlen;
-    const char *p;
     VncState *vs;
 
     vs = qemu_mallocz(sizeof(VncState));
@@ -1188,7 +1902,8 @@
 
     ds->opaque = vs;
     vnc_state = vs;
-    vs->display = arg;
+    vs->display = NULL;
+    vs->password = NULL;
 
     vs->lsock = -1;
     vs->csock = -1;
@@ -1213,16 +1928,232 @@
     memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
 
     vnc_dpy_resize(vs->ds, 640, 400);
+}
 
+#if CONFIG_VNC_TLS
+static int vnc_set_x509_credential(VncState *vs,
+				   const char *certdir,
+				   const char *filename,
+				   char **cred,
+				   int ignoreMissing)
+{
+    struct stat sb;
+
+    if (*cred) {
+	qemu_free(*cred);
+	*cred = NULL;
+    }
+
+    if (!(*cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2)))
+	return -1;
+
+    strcpy(*cred, certdir);
+    strcat(*cred, "/");
+    strcat(*cred, filename);
+
+    VNC_DEBUG("Check %s\n", *cred);
+    if (stat(*cred, &sb) < 0) {
+	qemu_free(*cred);
+	*cred = NULL;
+	if (ignoreMissing && errno == ENOENT)
+	    return 0;
+	return -1;
+    }
+
+    return 0;
+}
+
+static int vnc_set_x509_credential_dir(VncState *vs,
+				       const char *certdir)
+{
+    if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
+	goto cleanup;
+    if (vnc_set_x509_credential(vs, certdir, X509_CA_CRL_FILE, &vs->x509cacrl, 1) < 0)
+	goto cleanup;
+    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_CERT_FILE, &vs->x509cert, 0) < 0)
+	goto cleanup;
+    if (vnc_set_x509_credential(vs, certdir, X509_SERVER_KEY_FILE, &vs->x509key, 0) < 0)
+	goto cleanup;
+
+    return 0;
+
+ cleanup:
+    qemu_free(vs->x509cacert);
+    qemu_free(vs->x509cacrl);
+    qemu_free(vs->x509cert);
+    qemu_free(vs->x509key);
+    vs->x509cacert = vs->x509cacrl = vs->x509cert = vs->x509key = NULL;
+    return -1;
+}
+#endif /* CONFIG_VNC_TLS */
+
+void vnc_display_close(DisplayState *ds)
+{
+    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+
+    if (vs->display) {
+	qemu_free(vs->display);
+	vs->display = NULL;
+    }
+    if (vs->lsock != -1) {
+	qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL);
+	close(vs->lsock);
+	vs->lsock = -1;
+    }
+    if (vs->csock != -1) {
+	qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
+	closesocket(vs->csock);
+	vs->csock = -1;
+	buffer_reset(&vs->input);
+	buffer_reset(&vs->output);
+	vs->need_update = 0;
+#if CONFIG_VNC_TLS
+	if (vs->tls_session) {
+	    gnutls_deinit(vs->tls_session);
+	    vs->tls_session = NULL;
+	}
+	vs->wiremode = VNC_WIREMODE_CLEAR;
+#endif /* CONFIG_VNC_TLS */
+    }
+    vs->auth = VNC_AUTH_INVALID;
+#if CONFIG_VNC_TLS
+    vs->subauth = VNC_AUTH_INVALID;
+    vs->x509verify = 0;
+#endif
+}
+
+int vnc_display_password(DisplayState *ds, const char *password)
+{
+    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+
+    if (vs->password) {
+	qemu_free(vs->password);
+	vs->password = NULL;
+    }
+    if (password && password[0]) {
+	if (!(vs->password = qemu_strdup(password)))
+	    return -1;
+    }
+
+    return 0;
+}
+
+int vnc_display_open(DisplayState *ds, const char *display)
+{
+    struct sockaddr *addr;
+    struct sockaddr_in iaddr;
 #ifndef _WIN32
-    if (strstart(arg, "unix:", &p)) {
+    struct sockaddr_un uaddr;
+#endif
+    int reuse_addr, ret;
+    socklen_t addrlen;
+    const char *p;
+    VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
+    const char *options;
+    int password = 0;
+#if CONFIG_VNC_TLS
+    int tls = 0, x509 = 0;
+#endif
+
+    vnc_display_close(ds);
+    if (strcmp(display, "none") == 0)
+	return 0;
+
+    if (!(vs->display = strdup(display)))
+	return -1;
+
+    options = display;
+    while ((options = strchr(options, ','))) {
+	options++;
+	if (strncmp(options, "password", 8) == 0) {
+	    password = 1; /* Require password auth */
+#if CONFIG_VNC_TLS
+	} else if (strncmp(options, "tls", 3) == 0) {
+	    tls = 1; /* Require TLS */
+	} else if (strncmp(options, "x509", 4) == 0) {
+	    char *start, *end;
+	    x509 = 1; /* Require x509 certificates */
+	    if (strncmp(options, "x509verify", 10) == 0)
+	        vs->x509verify = 1; /* ...and verify client certs */
+
+	    /* Now check for 'x509=/some/path' postfix
+	     * and use that to setup x509 certificate/key paths */
+	    start = strchr(options, '=');
+	    end = strchr(options, ',');
+	    if (start && (!end || (start < end))) {
+		int len = end ? end-(start+1) : strlen(start+1);
+		char *path = qemu_malloc(len+1);
+		strncpy(path, start+1, len);
+		path[len] = '\0';
+		VNC_DEBUG("Trying certificate path '%s'\n", path);
+		if (vnc_set_x509_credential_dir(vs, path) < 0) {
+		    fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path);
+		    qemu_free(path);
+		    qemu_free(vs->display);
+		    vs->display = NULL;
+		    return -1;
+		}
+		qemu_free(path);
+	    } else {
+		fprintf(stderr, "No certificate path provided\n");
+		qemu_free(vs->display);
+		vs->display = NULL;
+		return -1;
+	    }
+#endif
+	}
+    }
+
+    if (password) {
+#if CONFIG_VNC_TLS
+	if (tls) {
+	    vs->auth = VNC_AUTH_VENCRYPT;
+	    if (x509) {
+		VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+		vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
+	    } else {
+		VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+		vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
+	    }
+	} else {
+#endif
+	    VNC_DEBUG("Initializing VNC server with password auth\n");
+	    vs->auth = VNC_AUTH_VNC;
+#if CONFIG_VNC_TLS
+	    vs->subauth = VNC_AUTH_INVALID;
+	}
+#endif
+    } else {
+#if CONFIG_VNC_TLS
+	if (tls) {
+	    vs->auth = VNC_AUTH_VENCRYPT;
+	    if (x509) {
+		VNC_DEBUG("Initializing VNC server with x509 no auth\n");
+		vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
+	    } else {
+		VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+		vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+	    }
+	} else {
+#endif
+	    VNC_DEBUG("Initializing VNC server with no auth\n");
+	    vs->auth = VNC_AUTH_NONE;
+#if CONFIG_VNC_TLS
+	    vs->subauth = VNC_AUTH_INVALID;
+	}
+#endif
+    }
+#ifndef _WIN32
+    if (strstart(display, "unix:", &p)) {
 	addr = (struct sockaddr *)&uaddr;
 	addrlen = sizeof(uaddr);
 
 	vs->lsock = socket(PF_UNIX, SOCK_STREAM, 0);
 	if (vs->lsock == -1) {
 	    fprintf(stderr, "Could not create socket\n");
-	    exit(1);
+	    free(vs->display);
+	    vs->display = NULL;
+	    return -1;
 	}
 
 	uaddr.sun_family = AF_UNIX;
@@ -1236,40 +2167,53 @@
 	addr = (struct sockaddr *)&iaddr;
 	addrlen = sizeof(iaddr);
 
+	if (parse_host_port(&iaddr, display) < 0) {
+	    fprintf(stderr, "Could not parse VNC address\n");
+	    free(vs->display);
+	    vs->display = NULL;
+	    return -1;
+	}
+
+	iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900);
+
 	vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
 	if (vs->lsock == -1) {
 	    fprintf(stderr, "Could not create socket\n");
-	    exit(1);
+	    free(vs->display);
+	    vs->display = NULL;
+	    return -1;
 	}
 
-	if (parse_host_port(&iaddr, arg) < 0) {
-	    fprintf(stderr, "Could not parse VNC address\n");
-	    exit(1);
-	}
-	    
-	iaddr.sin_port = htons(ntohs(iaddr.sin_port) + 5900);
-
 	reuse_addr = 1;
 	ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
 			 (const char *)&reuse_addr, sizeof(reuse_addr));
 	if (ret == -1) {
 	    fprintf(stderr, "setsockopt() failed\n");
-	    exit(1);
+	    close(vs->lsock);
+	    vs->lsock = -1;
+	    free(vs->display);
+	    vs->display = NULL;
+	    return -1;
 	}
     }
 
     if (bind(vs->lsock, addr, addrlen) == -1) {
 	fprintf(stderr, "bind() failed\n");
-	exit(1);
+	close(vs->lsock);
+	vs->lsock = -1;
+	free(vs->display);
+	vs->display = NULL;
+	return -1;
     }
 
     if (listen(vs->lsock, 1) == -1) {
 	fprintf(stderr, "listen() failed\n");
-	exit(1);
+	close(vs->lsock);
+	vs->lsock = -1;
+	free(vs->display);
+	vs->display = NULL;
+	return -1;
     }
 
-    ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
-    if (ret == -1) {
-	exit(1);
-    }
+    return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
 }
diff --git a/vnchextile.h b/vnchextile.h
index aa575b7..35dcc57 100644
--- a/vnchextile.h
+++ b/vnchextile.h
@@ -9,7 +9,7 @@
 
 static void CONCAT(send_hextile_tile_, NAME)(VncState *vs,
                                              int x, int y, int w, int h,
-                                             uint32_t *last_bg32, 
+                                             uint32_t *last_bg32,
                                              uint32_t *last_fg32,
                                              int *has_bg, int *has_fg)
 {
@@ -86,7 +86,7 @@
 	flags |= 0x08;
 
 	irow = (pixel_t *)row;
-	
+
 	for (j = 0; j < h; j++) {
 	    int min_x = -1;
 	    for (i = 0; i < w; i++) {